mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Wilson Felipe Pereira <wfelipe@google.com>
To: Tejun Heo <tj@kernel.org>, Lai Jiangshan <jiangshanlai@gmail.com>
Cc: Jonathan Corbet <corbet@lwn.net>,
	Shuah Khan <skhan@linuxfoundation.org>,
	 Randy Dunlap <rdunlap@infradead.org>,
	linux-doc@vger.kernel.org,  linux-kernel@vger.kernel.org,
	Wilson Felipe Pereira <wfelipe@google.com>,
	 Shuhao Tan <tanshuhao@google.com>
Subject: [PATCH 2/3] workqueue: expose per-workqueue stats in debugfs
Date: Thu, 22 Oct 2026 15:53:35 +0000	[thread overview]
Message-ID: <20261022155352.1293020-3-wfelipe@google.com> (raw)
In-Reply-To: <20261022155352.1293020-1-wfelipe@google.com>

struct pool_workqueue tracks runtime counters in pwq->stats[],
pwq->total_in_flight, and pwq->nr_active, but reading them currently
requires tools/workqueue/wq_monitor.py with drgn and kernel DWARF
debuginfo. This makes it impractical to inspect workqueue stats on
systems without drgn or debug symbols.

Add /sys/kernel/debug/workqueue/stats to expose per-workqueue stats
directly from the kernel. Iterate over the workqueues list under RCU and
sum wq->retired_stats[] with each pwq's stats[], total_in_flight, and
nr_active to report queued, active, and running work items alongside the
cumulative pwq->stats[] counters.

Signed-off-by: Wilson Felipe Pereira <wfelipe@google.com>
---
 kernel/workqueue.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)

diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 88c8cc2b38d8..ed0f0be6494a 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -57,6 +57,8 @@
 #include <linux/delay.h>
 #include <linux/irq_work.h>
 #include <linux/math64.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #include "workqueue_internal.h"
 
@@ -7990,6 +7992,103 @@ static void workqueue_sysfs_unregister(struct workqueue_struct *wq)
 static void workqueue_sysfs_unregister(struct workqueue_struct *wq)	{ }
 #endif	/* CONFIG_SYSFS */
 
+#ifdef CONFIG_DEBUG_FS
+
+static const char *wq_type_str(struct workqueue_struct *wq)
+{
+	if (wq->flags & WQ_BH)
+		return "bh";
+	if (wq->flags & WQ_UNBOUND) {
+		if (wq->flags & __WQ_ORDERED)
+			return "ordered";
+		return "unbound";
+	}
+	return "percpu";
+}
+
+static void *wq_stats_start(struct seq_file *m, loff_t *pos)
+	__acquires(rcu)
+{
+	rcu_read_lock();
+	return seq_list_start_head_rcu(&workqueues, *pos);
+}
+
+static void *wq_stats_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	return seq_list_next_rcu(v, &workqueues, pos);
+}
+
+static void wq_stats_stop(struct seq_file *m, void *v)
+	__releases(rcu)
+{
+	rcu_read_unlock();
+}
+
+static int wq_stats_show(struct seq_file *m, void *v)
+{
+	struct workqueue_struct *wq;
+	struct pool_workqueue *pwq;
+	u64 stats[PWQ_NR_STATS];
+	long in_flight = 0, active = 0;
+	long running, queued;
+	int i;
+
+	if (v == &workqueues) {
+		seq_printf(m, "%-24s %-8s %6s %6s %7s %10s %10s %12s %8s %8s %8s %8s %8s\n",
+			   "workqueue", "type", "queued", "active", "running",
+			   "started", "completed", "cpu_time_us",
+			   "cpu_itsv", "cm_wkup", "repat", "mayday", "rescued");
+		return 0;
+	}
+
+	wq = list_entry(v, struct workqueue_struct, list);
+
+	/* Advisory stats read without wq->mutex or pool->lock. */
+	for (i = 0; i < PWQ_NR_STATS; i++)
+		stats[i] = data_race(wq->retired_stats[i]);
+
+	for_each_pwq(pwq, wq) {
+		for (i = 0; i < PWQ_NR_STATS; i++)
+			stats[i] += data_race(pwq->stats[i]);
+		in_flight += data_race(pwq->total_in_flight);
+		active += data_race(pwq->nr_active);
+	}
+
+	running = max_t(long, stats[PWQ_STAT_STARTED] -
+			      stats[PWQ_STAT_COMPLETED], 0);
+	queued = max_t(long, in_flight - running, 0);
+	active = max_t(long, active, 0);
+
+	seq_printf(m, "%-24s %-8s %6ld %6ld %7ld %10llu %10llu %12llu %8llu %8llu %8llu %8llu %8llu\n",
+		   wq->name, wq_type_str(wq), queued, active, running,
+		   stats[PWQ_STAT_STARTED], stats[PWQ_STAT_COMPLETED],
+		   stats[PWQ_STAT_CPU_TIME], stats[PWQ_STAT_CPU_INTENSIVE],
+		   stats[PWQ_STAT_CM_WAKEUP], stats[PWQ_STAT_REPATRIATED],
+		   stats[PWQ_STAT_MAYDAY], stats[PWQ_STAT_RESCUED]);
+
+	return 0;
+}
+
+static const struct seq_operations wq_stats_sops = {
+	.start	= wq_stats_start,
+	.next	= wq_stats_next,
+	.stop	= wq_stats_stop,
+	.show	= wq_stats_show,
+};
+DEFINE_SEQ_ATTRIBUTE(wq_stats);
+
+static int __init wq_debugfs_init(void)
+{
+	struct dentry *dir;
+
+	dir = debugfs_create_dir("workqueue", NULL);
+	debugfs_create_file("stats", 0444, dir, NULL, &wq_stats_fops);
+	return 0;
+}
+late_initcall(wq_debugfs_init);
+
+#endif	/* CONFIG_DEBUG_FS */
+
 /*
  * Workqueue watchdog.
  *
-- 
2.56.0.218.g1ec904b173-goog


  parent reply	other threads:[~2026-10-22 15:54 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-22 15:53 [PATCH 0/3] " Wilson Felipe Pereira
2026-10-22 15:53 ` [PATCH 1/3] workqueue: preserve pwq->stats[] when unbound pwqs are released Wilson Felipe Pereira
2026-10-22 15:53 ` Wilson Felipe Pereira [this message]
2026-10-22 15:53 ` [PATCH 3/3] tools/workqueue: report queued items and retired stats in wq_monitor.py Wilson Felipe Pereira

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261022155352.1293020-3-wfelipe@google.com \
    --to=wfelipe@google.com \
    --cc=corbet@lwn.net \
    --cc=jiangshanlai@gmail.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rdunlap@infradead.org \
    --cc=skhan@linuxfoundation.org \
    --cc=tanshuhao@google.com \
    --cc=tj@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®