diff options
author | Tejun Heo <tj@kernel.org> | 2018-05-18 08:47:13 -0700 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2018-05-18 08:47:13 -0700 |
commit | 6b59808bfe482642287ddf3fe9d4cccb10756652 (patch) | |
tree | d97243a24dfec6ade0560190709f94101d06bcd1 | |
parent | 88b72b31e15f9dfed069ede5416bb71040e0d299 (diff) | |
download | linux-6b59808bfe482642287ddf3fe9d4cccb10756652.tar.bz2 |
workqueue: Show the latest workqueue name in /proc/PID/{comm,stat,status}
There can be a lot of workqueue workers and they all show up with the
cryptic kworker/* names making it difficult to understand which is
doing what and how they came to be.
# ps -ef | grep kworker
root 4 2 0 Feb25 ? 00:00:00 [kworker/0:0H]
root 6 2 0 Feb25 ? 00:00:00 [kworker/u112:0]
root 19 2 0 Feb25 ? 00:00:00 [kworker/1:0H]
root 25 2 0 Feb25 ? 00:00:00 [kworker/2:0H]
root 31 2 0 Feb25 ? 00:00:00 [kworker/3:0H]
...
This patch makes workqueue workers report the latest workqueue it was
executing for through /proc/PID/{comm,stat,status}. The extra
information is appended to the kthread name with intervening '+' if
currently executing, otherwise '-'.
# cat /proc/25/comm
kworker/2:0-events_power_efficient
# cat /proc/25/stat
25 (kworker/2:0-events_power_efficient) I 2 0 0 0 -1 69238880 0 0...
# grep Name /proc/25/status
Name: kworker/2:0-events_power_efficient
Unfortunately, ps(1) truncates comm to 15 characters,
# ps 25
PID TTY STAT TIME COMMAND
25 ? I 0:00 [kworker/2:0-eve]
making it a lot less useful; however, this should be an easy fix from
ps(1) side.
Signed-off-by: Tejun Heo <tj@kernel.org>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Craig Small <csmall@enc.com.au>
-rw-r--r-- | fs/proc/array.c | 7 | ||||
-rw-r--r-- | include/linux/workqueue.h | 1 | ||||
-rw-r--r-- | kernel/workqueue.c | 39 |
3 files changed, 45 insertions, 2 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index f29221e95792..bb1d3619ca12 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -99,10 +99,13 @@ void proc_task_name(struct seq_file *m, struct task_struct *p, bool escape) { char *buf; size_t size; - char tcomm[sizeof(p->comm)]; + char tcomm[64]; int ret; - get_task_comm(tcomm, p); + if (p->flags & PF_WQ_WORKER) + wq_worker_comm(tcomm, sizeof(tcomm), p); + else + __get_task_comm(tcomm, sizeof(tcomm), p); size = seq_get_buf(m, &buf); if (escape) { diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 39a0e215022a..60d673e15632 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -494,6 +494,7 @@ extern unsigned int work_busy(struct work_struct *work); extern __printf(1, 2) void set_worker_desc(const char *fmt, ...); extern void print_worker_info(const char *log_lvl, struct task_struct *task); extern void show_workqueue_state(void); +extern void wq_worker_comm(char *buf, size_t size, struct task_struct *task); /** * queue_work - queue work on a workqueue diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 3fbe0076492c..b4a39a15c931 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -4577,6 +4577,45 @@ void show_workqueue_state(void) rcu_read_unlock_sched(); } +/* used to show worker information through /proc/PID/{comm,stat,status} */ +void wq_worker_comm(char *buf, size_t size, struct task_struct *task) +{ + struct worker *worker; + struct worker_pool *pool; + int off; + + /* always show the actual comm */ + off = strscpy(buf, task->comm, size); + if (off < 0) + return; + + /* stabilize worker pool association */ + mutex_lock(&wq_pool_attach_mutex); + + worker = kthread_data(task); + pool = worker->pool; + + if (pool) { + spin_lock_irq(&pool->lock); + /* + * ->desc tracks information (wq name or set_worker_desc()) + * for the latest execution. If current, prepend '+', + * otherwise '-'. + */ + if (worker->desc[0] != '\0') { + if (worker->current_work) + scnprintf(buf + off, size - off, "+%s", + worker->desc); + else + scnprintf(buf + off, size - off, "-%s", + worker->desc); + } + spin_unlock_irq(&pool->lock); + } + + mutex_unlock(&wq_pool_attach_mutex); +} + /* * CPU hotplug. * |