diff options
author | Steven Rostedt <rostedt@goodmis.org> | 2008-08-29 16:51:43 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-14 04:36:28 -0400 |
commit | 1b6cced6ec9677fa65471e890dfdcb4bf5387643 (patch) | |
tree | 3728f61fff36a4c2f1f41ae15e638be58437c6bc /kernel | |
parent | d53475b5aa946752e3306b2ecb5a8c9c51cf8dd0 (diff) |
ftrace: stack trace add indexes
This patch adds indexes into the stack that the functions in the
stack dump were found at. As an added bonus, I also added a diff
to show which function is the most notorious consumer of the stack.
The output now looks like this:
# cat /debug/tracing/stack_trace
Depth Size Location (48 entries)
----- ---- --------
0) 2476 212 blk_recount_segments+0x39/0x59
1) 2264 12 bio_phys_segments+0x16/0x1d
2) 2252 20 blk_rq_bio_prep+0x23/0xaf
3) 2232 12 init_request_from_bio+0x74/0x77
4) 2220 56 __make_request+0x294/0x331
5) 2164 136 generic_make_request+0x34f/0x37d
6) 2028 56 submit_bio+0xe7/0xef
7) 1972 28 submit_bh+0xd1/0xf0
8) 1944 112 block_read_full_page+0x299/0x2a9
9) 1832 8 blkdev_readpage+0x14/0x16
10) 1824 28 read_cache_page_async+0x7e/0x109
11) 1796 16 read_cache_page+0x11/0x49
12) 1780 32 read_dev_sector+0x3c/0x72
13) 1748 48 read_lba+0x4d/0xaa
14) 1700 168 efi_partition+0x85/0x61b
15) 1532 72 rescan_partitions+0x10e/0x266
16) 1460 40 do_open+0x1c7/0x24e
17) 1420 292 __blkdev_get+0x79/0x84
18) 1128 12 blkdev_get+0x12/0x14
19) 1116 20 register_disk+0xd1/0x11e
20) 1096 28 add_disk+0x34/0x90
21) 1068 52 sd_probe+0x2b1/0x366
22) 1016 20 driver_probe_device+0xa5/0x120
23) 996 8 __device_attach+0xd/0xf
24) 988 32 bus_for_each_drv+0x3e/0x68
25) 956 24 device_attach+0x56/0x6c
26) 932 16 bus_attach_device+0x26/0x4d
27) 916 64 device_add+0x380/0x4b4
28) 852 28 scsi_sysfs_add_sdev+0xa1/0x1c9
29) 824 160 scsi_probe_and_add_lun+0x919/0xa2a
30) 664 36 __scsi_add_device+0x88/0xae
31) 628 44 ata_scsi_scan_host+0x9e/0x21c
32) 584 28 ata_host_register+0x1cb/0x1db
33) 556 24 ata_host_activate+0x98/0xb5
34) 532 192 ahci_init_one+0x9bd/0x9e9
35) 340 20 pci_device_probe+0x3e/0x5e
36) 320 20 driver_probe_device+0xa5/0x120
37) 300 20 __driver_attach+0x3f/0x5e
38) 280 36 bus_for_each_dev+0x40/0x62
39) 244 12 driver_attach+0x19/0x1b
40) 232 28 bus_add_driver+0x9c/0x1af
41) 204 28 driver_register+0x76/0xd2
42) 176 20 __pci_register_driver+0x44/0x71
43) 156 8 ahci_init+0x14/0x16
44) 148 100 _stext+0x42/0x122
45) 48 20 kernel_init+0x175/0x1dc
46) 28 28 kernel_thread_helper+0x7/0x10
The first column is simply an index starting from the inner most function
and counting down to the outer most.
The next column is the location that the function was found on the stack.
The next column is the size of the stack for that function.
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace_stack.c | 90 |
1 files changed, 73 insertions, 17 deletions
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 4d1e522e3fe8..74c5d9a3afae 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c | |||
@@ -16,8 +16,10 @@ | |||
16 | 16 | ||
17 | #define STACK_TRACE_ENTRIES 500 | 17 | #define STACK_TRACE_ENTRIES 500 |
18 | 18 | ||
19 | static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES] = | 19 | static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES+1] = |
20 | { [0 ... (STACK_TRACE_ENTRIES-1)] = ULONG_MAX }; | 20 | { [0 ... (STACK_TRACE_ENTRIES)] = ULONG_MAX }; |
21 | static unsigned stack_dump_index[STACK_TRACE_ENTRIES]; | ||
22 | |||
21 | static struct stack_trace max_stack_trace = { | 23 | static struct stack_trace max_stack_trace = { |
22 | .max_entries = STACK_TRACE_ENTRIES, | 24 | .max_entries = STACK_TRACE_ENTRIES, |
23 | .entries = stack_dump_trace, | 25 | .entries = stack_dump_trace, |
@@ -32,8 +34,9 @@ static DEFINE_PER_CPU(int, trace_active); | |||
32 | 34 | ||
33 | static inline void check_stack(void) | 35 | static inline void check_stack(void) |
34 | { | 36 | { |
35 | unsigned long this_size; | 37 | unsigned long this_size, flags; |
36 | unsigned long flags; | 38 | unsigned long *p, *top, *start; |
39 | int i; | ||
37 | 40 | ||
38 | this_size = ((unsigned long)&this_size) & (THREAD_SIZE-1); | 41 | this_size = ((unsigned long)&this_size) & (THREAD_SIZE-1); |
39 | this_size = THREAD_SIZE - this_size; | 42 | this_size = THREAD_SIZE - this_size; |
@@ -51,10 +54,42 @@ static inline void check_stack(void) | |||
51 | max_stack_size = this_size; | 54 | max_stack_size = this_size; |
52 | 55 | ||
53 | max_stack_trace.nr_entries = 0; | 56 | max_stack_trace.nr_entries = 0; |
54 | max_stack_trace.skip = 1; | 57 | max_stack_trace.skip = 3; |
55 | 58 | ||
56 | save_stack_trace(&max_stack_trace); | 59 | save_stack_trace(&max_stack_trace); |
57 | 60 | ||
61 | /* | ||
62 | * Now find where in the stack these are. | ||
63 | */ | ||
64 | i = 0; | ||
65 | start = &this_size; | ||
66 | top = (unsigned long *) | ||
67 | (((unsigned long)start & ~(THREAD_SIZE-1)) + THREAD_SIZE); | ||
68 | |||
69 | /* | ||
70 | * Loop through all the entries. One of the entries may | ||
71 | * for some reason be missed on the stack, so we may | ||
72 | * have to account for them. If they are all there, this | ||
73 | * loop will only happen once. This code only takes place | ||
74 | * on a new max, so it is far from a fast path. | ||
75 | */ | ||
76 | while (i < max_stack_trace.nr_entries) { | ||
77 | |||
78 | stack_dump_index[i] = this_size; | ||
79 | p = start; | ||
80 | |||
81 | for (; p < top && i < max_stack_trace.nr_entries; p++) { | ||
82 | if (*p == stack_dump_trace[i]) { | ||
83 | this_size = stack_dump_index[i++] = | ||
84 | (top - p) * sizeof(unsigned long); | ||
85 | /* Start the search from here */ | ||
86 | start = p + 1; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | i++; | ||
91 | } | ||
92 | |||
58 | out: | 93 | out: |
59 | __raw_spin_unlock(&max_stack_lock); | 94 | __raw_spin_unlock(&max_stack_lock); |
60 | raw_local_irq_restore(flags); | 95 | raw_local_irq_restore(flags); |
@@ -145,22 +180,24 @@ static struct file_operations stack_max_size_fops = { | |||
145 | static void * | 180 | static void * |
146 | t_next(struct seq_file *m, void *v, loff_t *pos) | 181 | t_next(struct seq_file *m, void *v, loff_t *pos) |
147 | { | 182 | { |
148 | unsigned long *t = m->private; | 183 | long i = (long)m->private; |
149 | 184 | ||
150 | (*pos)++; | 185 | (*pos)++; |
151 | 186 | ||
152 | if (!t || *t == ULONG_MAX) | 187 | i++; |
188 | |||
189 | if (i >= max_stack_trace.nr_entries || | ||
190 | stack_dump_trace[i] == ULONG_MAX) | ||
153 | return NULL; | 191 | return NULL; |
154 | 192 | ||
155 | t++; | 193 | m->private = (void *)i; |
156 | m->private = t; | ||
157 | 194 | ||
158 | return t; | 195 | return &m->private; |
159 | } | 196 | } |
160 | 197 | ||
161 | static void *t_start(struct seq_file *m, loff_t *pos) | 198 | static void *t_start(struct seq_file *m, loff_t *pos) |
162 | { | 199 | { |
163 | unsigned long *t = m->private; | 200 | void *t = &m->private; |
164 | loff_t l = 0; | 201 | loff_t l = 0; |
165 | 202 | ||
166 | local_irq_disable(); | 203 | local_irq_disable(); |
@@ -178,14 +215,15 @@ static void t_stop(struct seq_file *m, void *p) | |||
178 | local_irq_enable(); | 215 | local_irq_enable(); |
179 | } | 216 | } |
180 | 217 | ||
181 | static int trace_lookup_stack(struct seq_file *m, unsigned long addr) | 218 | static int trace_lookup_stack(struct seq_file *m, long i) |
182 | { | 219 | { |
220 | unsigned long addr = stack_dump_trace[i]; | ||
183 | #ifdef CONFIG_KALLSYMS | 221 | #ifdef CONFIG_KALLSYMS |
184 | char str[KSYM_SYMBOL_LEN]; | 222 | char str[KSYM_SYMBOL_LEN]; |
185 | 223 | ||
186 | sprint_symbol(str, addr); | 224 | sprint_symbol(str, addr); |
187 | 225 | ||
188 | return seq_printf(m, "[<%p>] %s\n", (void*)addr, str); | 226 | return seq_printf(m, "%s\n", str); |
189 | #else | 227 | #else |
190 | return seq_printf(m, "%p\n", (void*)addr); | 228 | return seq_printf(m, "%p\n", (void*)addr); |
191 | #endif | 229 | #endif |
@@ -193,12 +231,30 @@ static int trace_lookup_stack(struct seq_file *m, unsigned long addr) | |||
193 | 231 | ||
194 | static int t_show(struct seq_file *m, void *v) | 232 | static int t_show(struct seq_file *m, void *v) |
195 | { | 233 | { |
196 | unsigned long *t = v; | 234 | long i = *(long *)v; |
235 | int size; | ||
236 | |||
237 | if (i < 0) { | ||
238 | seq_printf(m, " Depth Size Location" | ||
239 | " (%d entries)\n" | ||
240 | " ----- ---- --------\n", | ||
241 | max_stack_trace.nr_entries); | ||
242 | return 0; | ||
243 | } | ||
197 | 244 | ||
198 | if (!t || *t == ULONG_MAX) | 245 | if (i >= max_stack_trace.nr_entries || |
246 | stack_dump_trace[i] == ULONG_MAX) | ||
199 | return 0; | 247 | return 0; |
200 | 248 | ||
201 | trace_lookup_stack(m, *t); | 249 | if (i+1 == max_stack_trace.nr_entries || |
250 | stack_dump_trace[i+1] == ULONG_MAX) | ||
251 | size = stack_dump_index[i]; | ||
252 | else | ||
253 | size = stack_dump_index[i] - stack_dump_index[i+1]; | ||
254 | |||
255 | seq_printf(m, "%3ld) %8d %5d ", i, stack_dump_index[i], size); | ||
256 | |||
257 | trace_lookup_stack(m, i); | ||
202 | 258 | ||
203 | return 0; | 259 | return 0; |
204 | } | 260 | } |
@@ -217,7 +273,7 @@ static int stack_trace_open(struct inode *inode, struct file *file) | |||
217 | ret = seq_open(file, &stack_trace_seq_ops); | 273 | ret = seq_open(file, &stack_trace_seq_ops); |
218 | if (!ret) { | 274 | if (!ret) { |
219 | struct seq_file *m = file->private_data; | 275 | struct seq_file *m = file->private_data; |
220 | m->private = stack_dump_trace; | 276 | m->private = (void *)-1; |
221 | } | 277 | } |
222 | 278 | ||
223 | return ret; | 279 | return ret; |