diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-01-12 17:15:46 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-01-14 06:11:43 -0500 |
commit | e1d8aa9f1dd655a3534b22fcfbecb70cdb125766 (patch) | |
tree | eb01b005a1d378515d5839bf1c7ea9836355ec9c /kernel/workqueue.c | |
parent | 002bb86d8d42f18937aef396c3ecd65c7e02e21a (diff) |
tracing: add a new workqueue tracer
Impact: new tracer
The workqueue tracer provides some statistical informations
about each cpu workqueue thread such as the number of the
works inserted and executed since their creation. It can help
to evaluate the amount of work each of them have to perform.
For example it can help a developer to decide whether he should
choose a per cpu workqueue instead of a singlethreaded one.
It only traces statistical informations for now but it will probably later
provide event tracing too.
Such a tracer could help too, and be improved, to help rt priority sorted
workqueue development.
To have a snapshot of the workqueues state at any time, just do
cat /debugfs/tracing/trace_stat/workqueues
Ie:
1 125 125 reiserfs/1
1 0 0 scsi_tgtd/1
1 0 0 aio/1
1 0 0 ata/1
1 114 114 kblockd/1
1 0 0 kintegrityd/1
1 2147 2147 events/1
0 0 0 kpsmoused
0 105 105 reiserfs/0
0 0 0 scsi_tgtd/0
0 0 0 aio/0
0 0 0 ata_aux
0 0 0 ata/0
0 0 0 cqueue
0 0 0 kacpi_notify
0 0 0 kacpid
0 149 149 kblockd/0
0 0 0 kintegrityd/0
0 1000 1000 khelper
0 2270 2270 events/0
Changes in V2:
_ Drop the static array based on NR_CPU and dynamically allocate the stat array
with num_possible_cpus() and other cpu mask facilities....
_ Trace workqueue insertion at a bit lower level (insert_work instead of queue_work) to handle
even the workqueue barriers.
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/workqueue.c')
-rw-r--r-- | kernel/workqueue.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 2f445833ae37..1fc2bc20603f 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/kallsyms.h> | 33 | #include <linux/kallsyms.h> |
34 | #include <linux/debug_locks.h> | 34 | #include <linux/debug_locks.h> |
35 | #include <linux/lockdep.h> | 35 | #include <linux/lockdep.h> |
36 | #include <trace/workqueue.h> | ||
36 | 37 | ||
37 | /* | 38 | /* |
38 | * The per-CPU workqueue (if single thread, we always use the first | 39 | * The per-CPU workqueue (if single thread, we always use the first |
@@ -125,9 +126,13 @@ struct cpu_workqueue_struct *get_wq_data(struct work_struct *work) | |||
125 | return (void *) (atomic_long_read(&work->data) & WORK_STRUCT_WQ_DATA_MASK); | 126 | return (void *) (atomic_long_read(&work->data) & WORK_STRUCT_WQ_DATA_MASK); |
126 | } | 127 | } |
127 | 128 | ||
129 | DEFINE_TRACE(workqueue_insertion); | ||
130 | |||
128 | static void insert_work(struct cpu_workqueue_struct *cwq, | 131 | static void insert_work(struct cpu_workqueue_struct *cwq, |
129 | struct work_struct *work, struct list_head *head) | 132 | struct work_struct *work, struct list_head *head) |
130 | { | 133 | { |
134 | trace_workqueue_insertion(cwq->thread, work); | ||
135 | |||
131 | set_wq_data(work, cwq); | 136 | set_wq_data(work, cwq); |
132 | /* | 137 | /* |
133 | * Ensure that we get the right work->data if we see the | 138 | * Ensure that we get the right work->data if we see the |
@@ -259,6 +264,8 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, | |||
259 | } | 264 | } |
260 | EXPORT_SYMBOL_GPL(queue_delayed_work_on); | 265 | EXPORT_SYMBOL_GPL(queue_delayed_work_on); |
261 | 266 | ||
267 | DEFINE_TRACE(workqueue_execution); | ||
268 | |||
262 | static void run_workqueue(struct cpu_workqueue_struct *cwq) | 269 | static void run_workqueue(struct cpu_workqueue_struct *cwq) |
263 | { | 270 | { |
264 | spin_lock_irq(&cwq->lock); | 271 | spin_lock_irq(&cwq->lock); |
@@ -284,7 +291,7 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq) | |||
284 | */ | 291 | */ |
285 | struct lockdep_map lockdep_map = work->lockdep_map; | 292 | struct lockdep_map lockdep_map = work->lockdep_map; |
286 | #endif | 293 | #endif |
287 | 294 | trace_workqueue_execution(cwq->thread, work); | |
288 | cwq->current_work = work; | 295 | cwq->current_work = work; |
289 | list_del_init(cwq->worklist.next); | 296 | list_del_init(cwq->worklist.next); |
290 | spin_unlock_irq(&cwq->lock); | 297 | spin_unlock_irq(&cwq->lock); |
@@ -765,6 +772,8 @@ init_cpu_workqueue(struct workqueue_struct *wq, int cpu) | |||
765 | return cwq; | 772 | return cwq; |
766 | } | 773 | } |
767 | 774 | ||
775 | DEFINE_TRACE(workqueue_creation); | ||
776 | |||
768 | static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) | 777 | static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) |
769 | { | 778 | { |
770 | struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; | 779 | struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; |
@@ -787,6 +796,8 @@ static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu) | |||
787 | sched_setscheduler_nocheck(p, SCHED_FIFO, ¶m); | 796 | sched_setscheduler_nocheck(p, SCHED_FIFO, ¶m); |
788 | cwq->thread = p; | 797 | cwq->thread = p; |
789 | 798 | ||
799 | trace_workqueue_creation(cwq->thread, cpu); | ||
800 | |||
790 | return 0; | 801 | return 0; |
791 | } | 802 | } |
792 | 803 | ||
@@ -868,6 +879,8 @@ struct workqueue_struct *__create_workqueue_key(const char *name, | |||
868 | } | 879 | } |
869 | EXPORT_SYMBOL_GPL(__create_workqueue_key); | 880 | EXPORT_SYMBOL_GPL(__create_workqueue_key); |
870 | 881 | ||
882 | DEFINE_TRACE(workqueue_destruction); | ||
883 | |||
871 | static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq) | 884 | static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq) |
872 | { | 885 | { |
873 | /* | 886 | /* |
@@ -891,6 +904,7 @@ static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq) | |||
891 | * checks list_empty(), and a "normal" queue_work() can't use | 904 | * checks list_empty(), and a "normal" queue_work() can't use |
892 | * a dead CPU. | 905 | * a dead CPU. |
893 | */ | 906 | */ |
907 | trace_workqueue_destruction(cwq->thread); | ||
894 | kthread_stop(cwq->thread); | 908 | kthread_stop(cwq->thread); |
895 | cwq->thread = NULL; | 909 | cwq->thread = NULL; |
896 | } | 910 | } |