writeback: tracing support
Subsystems (5)
cover writeback: tracing support
Hi Jens,
These are the writeback tracing patches that have not made it to mainline yet. Can you pull these into your writeback tree for 2.6.36?
Cheers,
Dave.
PATCH 1/3 writeback: initial tracing support
From: From: Jens Axboe <[email protected]>
Trace queue/sched/exec parts of the writeback loop. This provides insight into when and why flusher threads are scheduled to run. e.g a sync invocation leaves a trace like:
sync-2798 [006] 611323.335713: writeback_queue: 253:16: pages=87879, sb=0, kupdate=0, range_cyclic=0 for_background=0 sync-2798 [006] 611323.335718: writeback_sched: work=37c0, task=task sync-2798 [006] 611323.335817: writeback_queue: 8:0: pages=92680, sb=1, kupdate=0, range_cyclic=-1 for_background=0 sync-2798 [006] 611323.335819: writeback_sched: work=35c0, task=task sync-2798 [006] 611323.335855: writeback_queue: 253:16: pages=92680, sb=1, kupdate=0, range_cyclic=-1 for_background=0 sync-2798 [006] 611323.335857: writeback_sched: work=36c0, task=task sync-2798 [006] 611323.335890: writeback_queue: 8:0: pages=9223372036854775807, sb=1, kupdate=0, range_cyclic=0 for_background=0 sync-2798 [006] 611323.335891: writeback_sched: work=fe58, task=task sync-2798 [006] 611323.377341: writeback_queue: 253:16: pages=9223372036854775807, sb=1, kupdate=0, range_cyclic=0 for_background=0 sync-2798 [006] 611323.377346: writeback_sched: work=fe58, task=task
This also lays the foundation for adding more writeback tracing to provide deeper insight into the whole writeback path.
--- fs/fs-writeback.c | 45 ++++++++-- include/trace/events/writeback.h | 171 ++++++++++++++++++++++++++++++++++++++ mm/backing-dev.c | 3 + 3 files changed, 209 insertions(+), 10 deletions(-) create mode 100644 include/trace/events/writeback.h
fs/fs-writeback.c +35 -10
@@ -26,15 +26,9 @@#include <linux/blkdev.h> #include <linux/backing-dev.h> #include <linux/buffer_head.h> +#include <linux/ftrace.h> #include "internal.h" -#define inode_to_bdi (inode) ((inode)->i_mapping->backing_dev_info) - -/* -* We don't actually have pdflush, but this one is exported though /proc... -*/ -int nr_pdflush_threads; -/* * Passed into wb_writeback(), essentially a subset of writeback_control */
@@ -62,6 +56,21 @@ struct bdi_work {unsigned long state;/* flag bits, see WS_* */ }; +/* +* Include the creation of the trace points after defining the bdi_work and +* wb_writeback_args structures so that the definitions remain local to this +* file. +*/ +#define CREATE_TRACE_POINTS +#include <trace/events/writeback.h> + +#define inode_to_bdi (inode) ((inode)->i_mapping->backing_dev_info) + +/* +* We don't actually have pdflush, but this one is exported though /proc... +*/ +int nr_pdflush_threads; +enum {WS_USED_B =0 ,WS_ONSTACK_B ,
@@ -136,6 +145,8 @@ static void wb_work_complete(struct bdi_work *work)static void wb_clear_pending (struct bdi_writeback *wb,struct bdi_work *work) { +trace_writeback_clear (work); +/* * The caller has retrieved the work arguments from this work, * drop our reference. If this is the last ref, delete and free it
@@ -171,12 +182,16 @@ static void bdi_queue_work(struct backing_dev_info *bdi, struct bdi_work *work)* If the default thread isn't there, make sure we add it. When * it gets created and wakes up, we'll run this work. */ -if (unlikely (list_empty_careful (&bdi->wb_list))) +if (unlikely (list_empty_careful (&bdi->wb_list))) { +trace_writeback_sched (bdi, work,"default" );wake_up_process (default_backing_dev_info.wb.task); -else { + }else {struct bdi_writeback *wb = &bdi->wb; +struct task_struct *task = wb->task; -if (wb->task) +trace_writeback_sched (bdi, work, task ?"task" :"notask" ); + +if (task)wake_up_process (wb->task); } }
@@ -203,6 +218,7 @@ static void bdi_alloc_queue_work(struct backing_dev_info *bdi, work =kmalloc (sizeof (*work),GFP_ATOMIC );if (work) {bdi_work_init (work, args); +trace_writeback_queue (bdi, args);bdi_queue_work (bdi, work); }else {struct bdi_writeback *wb = &bdi->wb;
@@ -236,6 +252,7 @@ static void bdi_sync_writeback(struct backing_dev_info *bdi,bdi_work_init (&work, &args); work.state |=WS_ONSTACK ; +trace_writeback_queue (bdi, &args);bdi_queue_work (bdi, &work);bdi_wait_on_work_clear (&work); }
@@ -907,6 +924,8 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait)if (force_wait) work->args.sync_mode = args.sync_mode =WB_SYNC_ALL ; +trace_writeback_exec (work); +/* * If this isn't a data integrity operation, just notify * that we have seen this work and we are now starting it.
@@ -942,9 +961,13 @@ int bdi_writeback_task(struct bdi_writeback *wb)unsigned long wait_jiffies =-1UL ;long pages_written; +trace_writeback_thread_start (1 ); +while (!kthread_should_stop ()) { pages_written =wb_do_writeback (wb,0 ); +trace_writeback_pages_written (pages_written); +if (pages_written) last_active = jiffies;else if (wait_jiffies !=-1UL ) {
@@ -974,6 +997,8 @@ int bdi_writeback_task(struct bdi_writeback *wb)try_to_freeze (); } +trace_writeback_thread_start (0 ); +return 0 ; }
include/trace/events/writeback.h new file +171 -0
171 lines not on this page · raw message
mm/backing-dev.c +3 -0
@@ -10,6 +10,7 @@#include <linux/module.h> #include <linux/writeback.h> #include <linux/device.h> +#include <trace/events/writeback.h> static atomic_long_t bdi_seq =ATOMIC_LONG_INIT (0 );
@@ -585,6 +586,7 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent,bdi_debug_register (bdi,dev_name (dev));set_bit (BDI_registered, &bdi->state); +trace_writeback_bdi_register (dev_name (dev),1 ); exit:return ret; }
@@ -647,6 +649,7 @@ static void bdi_prune_sb(struct backing_dev_info *bdi)void bdi_unregister (struct backing_dev_info *bdi) {if (bdi->dev) { +trace_writeback_bdi_register (dev_name (bdi->dev),0 );bdi_prune_sb (bdi);if (!bdi_cap_flush_forker (bdi))
Signature · 1 line
1.7.1
Re: [PATCH 1/3] writeback: initial tracing support
Quoted 1 line · Dave Chinner
+#include <
linux/ftrace.h>
I think this should be <linux/tracepoint.h>.
I fear this might need some more rediffing after my latests writeback patches.
Review
Quoted 2 lines
(quoted diff) +2
-0+ TP_fast_assign( + strlcpy(__entry->name, dev_name(bdi->dev), 16);
For most other fs/block dev tracepoints we print the dev_t as major:minor. It would be good to have some consitency to match on for the trace points.
include/trace/events/writeback.h line 29
Quoted 2 lines
include/trace/events/writeback.h new file +2
-0+ __entry->nr_pages = args->nr_pages; + __entry->sb = !!args->sb;
It might be worth to store the dev_t of the superblock here?
Quoted 7 lines
include/trace/events/writeback.h new file +6
-0+TP_printk ("%s: pages=%ld, sb=%d, kupdate=%d, range_cyclic=%d " +"for_background=%d" , __entry->name, __entry->nr_pages, + __entry->sb, __entry->for_kupdate, + __entry->range_cyclic, __entry->for_background) +TRACE_EVENT(writeback_sched, +
include/trace/events/writeback.h line 52
Quoted 10 lines
include/trace/events/writeback.h new file +10
-0+ TP_PROTO(struct backing_dev_info *bdi, struct bdi_work *work, + const char *msg), + + TP_ARGS(bdi, work, msg), + + TP_STRUCT__entry( + __array(char, name, 16) + __field(unsigned int, work) + __array(char, task, 8) + ),
Instead of the task field I'd make this a calss with three instances for the different types of wakeups.
include/trace/events/writeback.h line 56
Quoted 4 lines
include/trace/events/writeback.h new file +4
-0+ +TP_fast_assign ( + strlcpy(__entry->name, dev_name(bdi->dev), 16); + __entry->work = (unsigned long ) work &0xffff ;
The unsigned long allows to store the whole pointer. Or we could just store it as a void pointer and print it using %p to make the types simpler.
Quoted 6 lines
include/trace/events/writeback.h new file +6
-0+ TP_PROTO(const char *name, int start), + + TP_ARGS(name, start), + + TP_STRUCT__entry( + __array(char, name, 16)
include/trace/events/writeback.h line 166
Quoted 10 lines
include/trace/events/writeback.h new file +10
-0+__field (int, start) + ), + +TP_fast_assign ( + strlcpy(__entry->name, name, 16); + __entry->start = start; + ), + +TP_printk ("%s: %s" , __entry->name, + __entry->start ?"registered" :"unregistered" )
Again, the clean way would be to have class with two instances instead of using one tracepoint for two different events and differenciate them by a string.
PATCH 2/3 writeback: Add tracing to balance_dirty_pages
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
Tracing high level background writeback events is good, but it doesn't give the entire picture. Add IO dispatched by foreground throttling to the writeback events.
--- fs/fs-writeback.c | 5 ++ include/trace/events/writeback.h | 80 ++++++++++++++++++++++++++++++++++++++ mm/page-writeback.c | 4 ++ 3 files changed, 89 insertions(+), 0 deletions(-)
fs/fs-writeback.c +5 -0
@@ -807,7 +807,11 @@ static long wb_writeback(struct bdi_writeback *wb, wbc.more_io =0 ; wbc.nr_to_write =MAX_WRITEBACK_PAGES ; wbc.pages_skipped =0 ; + +trace_wbc_writeback_start (&wbc);writeback_inodes_wb (wb, &wbc); +trace_wbc_writeback_written (&wbc); + args->nr_pages -=MAX_WRITEBACK_PAGES - wbc.nr_to_write; wrote +=MAX_WRITEBACK_PAGES - wbc.nr_to_write;
@@ -835,6 +839,7 @@ static long wb_writeback(struct bdi_writeback *wb,if (!list_empty (&wb->b_more_io)) { inode =list_entry (wb->b_more_io.prev, struct inode, i_list); +trace_wbc_writeback_wait (&wbc);inode_wait_for_writeback (inode); }spin_unlock (&inode_lock);
include/trace/events/writeback.h +80 -0
92 lines not on this page · raw message
mm/page-writeback.c +4 -0
@@ -34,6 +34,7 @@#include <linux/syscalls.h> #include <linux/buffer_head.h> #include <linux/pagevec.h> +#include <trace/events/writeback.h> /* * After a CPU has dirtied this many pages, balance_dirty_pages_ratelimited
@@ -536,11 +537,13 @@ static void balance_dirty_pages(struct address_space *mapping,* threshold otherwise wait until the disk writes catch * up. */ +trace_wbc_balance_dirty_start (&wbc);if (bdi_nr_reclaimable > bdi_thresh) {writeback_inodes_wbc (&wbc); pages_written += write_chunk - wbc.nr_to_write;get_dirty_limits (&background_thresh, &dirty_thresh, &bdi_thresh, bdi); +trace_wbc_balance_dirty_written (&wbc); }/*
@@ -566,6 +569,7 @@ static void balance_dirty_pages(struct address_space *mapping,if (pages_written >= write_chunk)break ;/* We've done our duty */ +trace_wbc_balance_dirty_wait (&wbc);__set_current_state (TASK_INTERRUPTIBLE );io_schedule_timeout (pause);
Signature · 1 line
1.7.1
Re: [PATCH 2/3] writeback: Add tracing to balance_dirty_pages
Quoted 1 line
+/* pass flags explicitly */
which flags?
include/trace/events/writeback.h TRACE_EVENT(writeback_bdi_register, · line 198
Quoted 4 lines
include/trace/events/writeback.h +4
-0+TP_fast_assign ( + char *__name = "(none)"; + + __entry->wbc = (unsigned long )wbc &0xffff ;
The wbc generally is allocated on stack, does it reall make sense to keep this?
include/trace/events/writeback.h TRACE_EVENT(writeback_bdi_register,
Quoted 6 lines
include/trace/events/writeback.h +5
-0+if (wbc->bdi) +strncpy (__entry->name,dev_name (wbc->bdi->dev),16 ); +else +strncpy (__entry->name, __name,16 ); + __entry->sb = !!wbc->sb;
The bdi and sb fields are now gone from the writeback_control. But I think passing the bdi explicitly for the device name makes sense here.
PATCH 3/3 writeback: Add tracing to write_cache_pages
In reply to Dave ChinnerFrom: Dave Chinner <[email protected]>
Add a trace event to the ->writepage loop in write_cache_pages to give visibility into how the ->writepage call is changing variables within the writeback control structure. Of most interest is how wbc->nr_to_write changes from call to call, especially with filesystems that write multiple pages in ->writepage.
--- include/trace/events/writeback.h | 1 + mm/page-writeback.c | 1 + 2 files changed, 2 insertions(+), 0 deletions(-)
include/trace/events/writeback.h +1 -0
@@ -244,6 +244,7 @@ DEFINE_WBC_EVENT(wbc_writeback_wait);DEFINE_WBC_EVENT (wbc_balance_dirty_start);DEFINE_WBC_EVENT (wbc_balance_dirty_written);DEFINE_WBC_EVENT (wbc_balance_dirty_wait); +DEFINE_WBC_EVENT (wbc_writepage);#endif /* _TRACE_WRITEBACK_H */
mm/page-writeback.c +1 -0
@@ -935,6 +935,7 @@ continue_unlock:if (!clear_page_dirty_for_io (page)) goto continue_unlock; +trace_wbc_writepage (wbc); ret = (*writepage)(page, wbc, data);if (unlikely (ret)) {if (ret ==AOP_WRITEPAGE_ACTIVATE ) {
Signature · 1 line
1.7.1
Quoted 5 lines · Dave Chinner
Hi Jens,
These are the writeback tracing patches that have not made it to mainline yet. Can you pull these into your writeback tree for 2.6.36?
Will you send an updated and rediffed version against the current patches? Just generate against for-2.6.36 of the block git tree [1].
[1] git://git.kernel.dk/linux-2.6-block.git
Signature · 1 line
Jens Axboe
Quoted 7 lines · Jens Axboe
Quoted 5 lines · Dave Chinner
Hi Jens,
These are the writeback tracing patches that have not made it to mainline yet. Can you pull these into your writeback tree for 2.6.36?
Quoted 5 lines
Will you send an updated and rediffed version against the current patches? Just generate against for-2.6.36 of the block git tree [1].
[1]
git://git.kernel.dk/linux-2.6-block.git
Yes, will do.
Cheers,
Dave.
Signature · 2 lines
Dave Chinner [email protected]