Skip to content

Commit

Permalink
workqueue: Add basic tracepoints to track workqueue execution
Browse files Browse the repository at this point in the history
With the introduction of the new unified work queue thread pools,
we lost one feature: It's no longer possible to know which worker
is causing the CPU to wake out of idle. The result is that PowerTOP
now reports a lot of "kworker/a:b" instead of more readable results.

This patch adds a pair of tracepoints to the new workqueue code,
similar in style to the timer/hrtimer tracepoints.

With this pair of tracepoints, the next PowerTOP can correctly
report which work item caused the wakeup (and how long it took):

Interrupt (43)            i915      time   3.51ms    wakeups 141
Work      ieee80211_iface_work      time   0.81ms    wakeups  29
Work              do_dbs_timer      time   0.55ms    wakeups  24
Process                   Xorg      time  21.36ms    wakeups   4
Timer    sched_rt_period_timer      time   0.01ms    wakeups   1

Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Arjan van de Ven authored and Linus Torvalds committed Aug 21, 2010
1 parent 69b26c7 commit e36c886
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 0 deletions.
62 changes: 62 additions & 0 deletions include/trace/events/workqueue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#undef TRACE_SYSTEM
#define TRACE_SYSTEM workqueue

#if !defined(_TRACE_WORKQUEUE_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_WORKQUEUE_H

#include <linux/tracepoint.h>
#include <linux/workqueue.h>

/**
* workqueue_execute_start - called immediately before the workqueue callback
* @work: pointer to struct work_struct
*
* Allows to track workqueue execution.
*/
TRACE_EVENT(workqueue_execute_start,

TP_PROTO(struct work_struct *work),

TP_ARGS(work),

TP_STRUCT__entry(
__field( void *, work )
__field( void *, function)
),

TP_fast_assign(
__entry->work = work;
__entry->function = work->func;
),

TP_printk("work struct %p: function %pf", __entry->work, __entry->function)
);

/**
* workqueue_execute_end - called immediately before the workqueue callback
* @work: pointer to struct work_struct
*
* Allows to track workqueue execution.
*/
TRACE_EVENT(workqueue_execute_end,

TP_PROTO(struct work_struct *work),

TP_ARGS(work),

TP_STRUCT__entry(
__field( void *, work )
),

TP_fast_assign(
__entry->work = work;
),

TP_printk("work struct %p", __entry->work)
);


#endif /* _TRACE_WORKQUEUE_H */

/* This part must be outside protection */
#include <trace/define_trace.h>
9 changes: 9 additions & 0 deletions kernel/workqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
#include <linux/lockdep.h>
#include <linux/idr.h>

#define CREATE_TRACE_POINTS
#include <trace/events/workqueue.h>

#include "workqueue_sched.h"

enum {
Expand Down Expand Up @@ -1790,7 +1793,13 @@ static void process_one_work(struct worker *worker, struct work_struct *work)
work_clear_pending(work);
lock_map_acquire(&cwq->wq->lockdep_map);
lock_map_acquire(&lockdep_map);
trace_workqueue_execute_start(work);
f(work);
/*
* While we must be careful to not use "work" after this, the trace
* point will only record its address.
*/
trace_workqueue_execute_end(work);
lock_map_release(&lockdep_map);
lock_map_release(&cwq->wq->lockdep_map);

Expand Down

0 comments on commit e36c886

Please sign in to comment.