aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2010-07-06 23:24:06 -0400
committerJens Axboe <jaxboe@fusionio.com>2010-08-07 12:24:23 -0400
commit455b2864686d3591b3b2f39eb46290c95f76471f (patch)
treeb88059e3691fc5ad4491518e9eb1f1f2ba21711a
parenta89f5c899db3c6be4bb426e4efb72ecee29a93b5 (diff)
writeback: Initial tracing support
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 traces like: sync-[...]: writeback_queue: bdi 8:0: sb_dev 8:1 nr_pages=7712 sync_mode=0 kupdate=0 range_cyclic=0 background=0 flush-8:0-[...]: writeback_exec: bdi 8:0: sb_dev 8:1 nr_pages=7712 sync_mode=0 kupdate=0 range_cyclic=0 background=0 This also lays the foundation for adding more writeback tracing to provide deeper insight into the whole writeback path. The original tracing code is from Jens Axboe, though this version is a rewrite as a result of the code being traced changing significantly. Signed-off-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
-rw-r--r--fs/fs-writeback.c38
-rw-r--r--include/trace/events/writeback.h91
-rw-r--r--mm/backing-dev.c3
3 files changed, 124 insertions, 8 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index c8471b3ddccf..73acab4dc2b7 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -26,15 +26,9 @@
26#include <linux/blkdev.h> 26#include <linux/blkdev.h>
27#include <linux/backing-dev.h> 27#include <linux/backing-dev.h>
28#include <linux/buffer_head.h> 28#include <linux/buffer_head.h>
29#include <linux/tracepoint.h>
29#include "internal.h" 30#include "internal.h"
30 31
31#define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info)
32
33/*
34 * We don't actually have pdflush, but this one is exported though /proc...
35 */
36int nr_pdflush_threads;
37
38/* 32/*
39 * Passed into wb_writeback(), essentially a subset of writeback_control 33 * Passed into wb_writeback(), essentially a subset of writeback_control
40 */ 34 */
@@ -50,6 +44,21 @@ struct wb_writeback_work {
50 struct completion *done; /* set if the caller waits */ 44 struct completion *done; /* set if the caller waits */
51}; 45};
52 46
47/*
48 * Include the creation of the trace points after defining the
49 * wb_writeback_work structure so that the definition remains local to this
50 * file.
51 */
52#define CREATE_TRACE_POINTS
53#include <trace/events/writeback.h>
54
55#define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info)
56
57/*
58 * We don't actually have pdflush, but this one is exported though /proc...
59 */
60int nr_pdflush_threads;
61
53/** 62/**
54 * writeback_in_progress - determine whether there is writeback in progress 63 * writeback_in_progress - determine whether there is writeback in progress
55 * @bdi: the device's backing_dev_info structure. 64 * @bdi: the device's backing_dev_info structure.
@@ -65,6 +74,8 @@ int writeback_in_progress(struct backing_dev_info *bdi)
65static void bdi_queue_work(struct backing_dev_info *bdi, 74static void bdi_queue_work(struct backing_dev_info *bdi,
66 struct wb_writeback_work *work) 75 struct wb_writeback_work *work)
67{ 76{
77 trace_writeback_queue(bdi, work);
78
68 spin_lock(&bdi->wb_lock); 79 spin_lock(&bdi->wb_lock);
69 list_add_tail(&work->list, &bdi->work_list); 80 list_add_tail(&work->list, &bdi->work_list);
70 spin_unlock(&bdi->wb_lock); 81 spin_unlock(&bdi->wb_lock);
@@ -74,6 +85,7 @@ static void bdi_queue_work(struct backing_dev_info *bdi,
74 * it gets created and wakes up, we'll run this work. 85 * it gets created and wakes up, we'll run this work.
75 */ 86 */
76 if (unlikely(!bdi->wb.task)) { 87 if (unlikely(!bdi->wb.task)) {
88 trace_writeback_nothread(bdi, work);
77 wake_up_process(default_backing_dev_info.wb.task); 89 wake_up_process(default_backing_dev_info.wb.task);
78 } else { 90 } else {
79 struct bdi_writeback *wb = &bdi->wb; 91 struct bdi_writeback *wb = &bdi->wb;
@@ -95,8 +107,10 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
95 */ 107 */
96 work = kzalloc(sizeof(*work), GFP_ATOMIC); 108 work = kzalloc(sizeof(*work), GFP_ATOMIC);
97 if (!work) { 109 if (!work) {
98 if (bdi->wb.task) 110 if (bdi->wb.task) {
111 trace_writeback_nowork(bdi);
99 wake_up_process(bdi->wb.task); 112 wake_up_process(bdi->wb.task);
113 }
100 return; 114 return;
101 } 115 }
102 116
@@ -751,6 +765,8 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait)
751 if (force_wait) 765 if (force_wait)
752 work->sync_mode = WB_SYNC_ALL; 766 work->sync_mode = WB_SYNC_ALL;
753 767
768 trace_writeback_exec(bdi, work);
769
754 wrote += wb_writeback(wb, work); 770 wrote += wb_writeback(wb, work);
755 771
756 /* 772 /*
@@ -805,9 +821,13 @@ int bdi_writeback_thread(void *data)
805 smp_mb__after_clear_bit(); 821 smp_mb__after_clear_bit();
806 wake_up_bit(&bdi->state, BDI_pending); 822 wake_up_bit(&bdi->state, BDI_pending);
807 823
824 trace_writeback_thread_start(bdi);
825
808 while (!kthread_should_stop()) { 826 while (!kthread_should_stop()) {
809 pages_written = wb_do_writeback(wb, 0); 827 pages_written = wb_do_writeback(wb, 0);
810 828
829 trace_writeback_pages_written(pages_written);
830
811 if (pages_written) 831 if (pages_written)
812 last_active = jiffies; 832 last_active = jiffies;
813 else if (wait_jiffies != -1UL) { 833 else if (wait_jiffies != -1UL) {
@@ -845,6 +865,8 @@ int bdi_writeback_thread(void *data)
845 */ 865 */
846 if (!list_empty(&bdi->work_list)) 866 if (!list_empty(&bdi->work_list))
847 wb_do_writeback(wb, 1); 867 wb_do_writeback(wb, 1);
868
869 trace_writeback_thread_stop(bdi);
848 return 0; 870 return 0;
849} 871}
850 872
diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h
new file mode 100644
index 000000000000..562fcae10d9d
--- /dev/null
+++ b/include/trace/events/writeback.h
@@ -0,0 +1,91 @@
1#undef TRACE_SYSTEM
2#define TRACE_SYSTEM writeback
3
4#if !defined(_TRACE_WRITEBACK_H) || defined(TRACE_HEADER_MULTI_READ)
5#define _TRACE_WRITEBACK_H
6
7#include <linux/backing-dev.h>
8#include <linux/writeback.h>
9
10struct wb_writeback_work;
11
12DECLARE_EVENT_CLASS(writeback_work_class,
13 TP_PROTO(struct backing_dev_info *bdi, struct wb_writeback_work *work),
14 TP_ARGS(bdi, work),
15 TP_STRUCT__entry(
16 __array(char, name, 32)
17 __field(long, nr_pages)
18 __field(dev_t, sb_dev)
19 __field(int, sync_mode)
20 __field(int, for_kupdate)
21 __field(int, range_cyclic)
22 __field(int, for_background)
23 ),
24 TP_fast_assign(
25 strncpy(__entry->name, dev_name(bdi->dev), 32);
26 __entry->nr_pages = work->nr_pages;
27 __entry->sb_dev = work->sb ? work->sb->s_dev : 0;
28 __entry->sync_mode = work->sync_mode;
29 __entry->for_kupdate = work->for_kupdate;
30 __entry->range_cyclic = work->range_cyclic;
31 __entry->for_background = work->for_background;
32 ),
33 TP_printk("bdi %s: sb_dev %d:%d nr_pages=%ld sync_mode=%d "
34 "kupdate=%d range_cyclic=%d background=%d",
35 __entry->name,
36 MAJOR(__entry->sb_dev), MINOR(__entry->sb_dev),
37 __entry->nr_pages,
38 __entry->sync_mode,
39 __entry->for_kupdate,
40 __entry->range_cyclic,
41 __entry->for_background
42 )
43);
44#define DEFINE_WRITEBACK_WORK_EVENT(name) \
45DEFINE_EVENT(writeback_work_class, name, \
46 TP_PROTO(struct backing_dev_info *bdi, struct wb_writeback_work *work), \
47 TP_ARGS(bdi, work))
48DEFINE_WRITEBACK_WORK_EVENT(writeback_nothread);
49DEFINE_WRITEBACK_WORK_EVENT(writeback_queue);
50DEFINE_WRITEBACK_WORK_EVENT(writeback_exec);
51
52TRACE_EVENT(writeback_pages_written,
53 TP_PROTO(long pages_written),
54 TP_ARGS(pages_written),
55 TP_STRUCT__entry(
56 __field(long, pages)
57 ),
58 TP_fast_assign(
59 __entry->pages = pages_written;
60 ),
61 TP_printk("%ld", __entry->pages)
62);
63
64DECLARE_EVENT_CLASS(writeback_class,
65 TP_PROTO(struct backing_dev_info *bdi),
66 TP_ARGS(bdi),
67 TP_STRUCT__entry(
68 __array(char, name, 32)
69 ),
70 TP_fast_assign(
71 strncpy(__entry->name, dev_name(bdi->dev), 32);
72 ),
73 TP_printk("bdi %s",
74 __entry->name
75 )
76);
77#define DEFINE_WRITEBACK_EVENT(name) \
78DEFINE_EVENT(writeback_class, name, \
79 TP_PROTO(struct backing_dev_info *bdi), \
80 TP_ARGS(bdi))
81
82DEFINE_WRITEBACK_EVENT(writeback_nowork);
83DEFINE_WRITEBACK_EVENT(writeback_bdi_register);
84DEFINE_WRITEBACK_EVENT(writeback_bdi_unregister);
85DEFINE_WRITEBACK_EVENT(writeback_thread_start);
86DEFINE_WRITEBACK_EVENT(writeback_thread_stop);
87
88#endif /* _TRACE_WRITEBACK_H */
89
90/* This part must be outside protection */
91#include <trace/define_trace.h>
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index bceac647e4d1..ac78a3336181 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -10,6 +10,7 @@
10#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/writeback.h> 11#include <linux/writeback.h>
12#include <linux/device.h> 12#include <linux/device.h>
13#include <trace/events/writeback.h>
13 14
14static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0); 15static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0);
15 16
@@ -518,6 +519,7 @@ int bdi_register(struct backing_dev_info *bdi, struct device *parent,
518 519
519 bdi_debug_register(bdi, dev_name(dev)); 520 bdi_debug_register(bdi, dev_name(dev));
520 set_bit(BDI_registered, &bdi->state); 521 set_bit(BDI_registered, &bdi->state);
522 trace_writeback_bdi_register(bdi);
521exit: 523exit:
522 return ret; 524 return ret;
523} 525}
@@ -578,6 +580,7 @@ static void bdi_prune_sb(struct backing_dev_info *bdi)
578void bdi_unregister(struct backing_dev_info *bdi) 580void bdi_unregister(struct backing_dev_info *bdi)
579{ 581{
580 if (bdi->dev) { 582 if (bdi->dev) {
583 trace_writeback_bdi_unregister(bdi);
581 bdi_prune_sb(bdi); 584 bdi_prune_sb(bdi);
582 585
583 if (!bdi_cap_flush_forker(bdi)) 586 if (!bdi_cap_flush_forker(bdi))