diff options
author | Steven Rostedt <srostedt@redhat.com> | 2011-02-25 21:34:34 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2011-02-25 21:40:03 -0500 |
commit | 9e0fd22b14805a3a3219a99bc5eccebf70f5484a (patch) | |
tree | 08df99aed0c1cd75a5c29f16c77fff6de8f09f3c | |
parent | 8d1e65fdb15da0b0061cdb43c938e0882757648a (diff) |
trace-cmd: Add hack to report out blktrace
The blktrace never exported the ftrace events via the
/debug/tracing/events directory. Not to mention, that the blktrace
is much more complex data to read out.
Add a hack into the trace-input that creates a event format that
parse-events can read for the blktrace file, and also create a
plugin to parse the complex data.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | plugin_blk.c | 377 | ||||
-rw-r--r-- | trace-blk-hack.c | 175 | ||||
-rw-r--r-- | trace-cmd.h | 3 | ||||
-rw-r--r-- | trace-input.c | 2 |
5 files changed, 561 insertions, 2 deletions
@@ -272,10 +272,12 @@ KERNEL_SHARK_OBJS = $(TRACE_VIEW_OBJS) $(TRACE_GRAPH_OBJS) $(TRACE_GUI_OBJS) \ | |||
272 | 272 | ||
273 | PEVENT_LIB_OBJS = parse-events.o trace-seq.o parse-filter.o parse-utils.o | 273 | PEVENT_LIB_OBJS = parse-events.o trace-seq.o parse-filter.o parse-utils.o |
274 | TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \ | 274 | TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \ |
275 | trace-output.o trace-recorder.o trace-restore.o trace-usage.o | 275 | trace-output.o trace-recorder.o trace-restore.o trace-usage.o \ |
276 | trace-blk-hack.o | ||
276 | 277 | ||
277 | PLUGIN_OBJS = plugin_hrtimer.o plugin_kmem.o plugin_sched_switch.o \ | 278 | PLUGIN_OBJS = plugin_hrtimer.o plugin_kmem.o plugin_sched_switch.o \ |
278 | plugin_mac80211.o plugin_jbd2.o plugin_function.o plugin_kvm.o | 279 | plugin_mac80211.o plugin_jbd2.o plugin_function.o plugin_kvm.o \ |
280 | plugin_blk.o | ||
279 | 281 | ||
280 | PLUGINS := $(PLUGIN_OBJS:.o=.so) | 282 | PLUGINS := $(PLUGIN_OBJS:.o=.so) |
281 | 283 | ||
diff --git a/plugin_blk.c b/plugin_blk.c new file mode 100644 index 0000000..9327b17 --- /dev/null +++ b/plugin_blk.c | |||
@@ -0,0 +1,377 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
20 | */ | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | |||
25 | #include <linux/blktrace_api.h> | ||
26 | |||
27 | #include "trace-cmd.h" | ||
28 | |||
29 | #define MINORBITS 20 | ||
30 | #define MINORMASK ((1U << MINORBITS) - 1) | ||
31 | #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) | ||
32 | #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) | ||
33 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
34 | |||
35 | struct blk_data { | ||
36 | unsigned long long sector; | ||
37 | struct event_format *event; | ||
38 | unsigned int action; | ||
39 | unsigned int pid; | ||
40 | unsigned int device; | ||
41 | unsigned int bytes; | ||
42 | unsigned int error; | ||
43 | void *pdu_data; | ||
44 | unsigned short pdu_len; | ||
45 | }; | ||
46 | |||
47 | static void fill_rwbs(char *rwbs, int action, unsigned int bytes) | ||
48 | { | ||
49 | int i = 0; | ||
50 | int tc = action >> BLK_TC_SHIFT; | ||
51 | |||
52 | if (action == BLK_TN_MESSAGE) { | ||
53 | rwbs[i++] = 'N'; | ||
54 | goto out; | ||
55 | } | ||
56 | |||
57 | if (tc & BLK_TC_DISCARD) | ||
58 | rwbs[i++] = 'D'; | ||
59 | else if (tc & BLK_TC_WRITE) | ||
60 | rwbs[i++] = 'W'; | ||
61 | else if (bytes) | ||
62 | rwbs[i++] = 'R'; | ||
63 | else | ||
64 | rwbs[i++] = 'N'; | ||
65 | |||
66 | if (tc & BLK_TC_AHEAD) | ||
67 | rwbs[i++] = 'A'; | ||
68 | if (tc & BLK_TC_BARRIER) | ||
69 | rwbs[i++] = 'B'; | ||
70 | if (tc & BLK_TC_SYNC) | ||
71 | rwbs[i++] = 'S'; | ||
72 | if (tc & BLK_TC_META) | ||
73 | rwbs[i++] = 'M'; | ||
74 | out: | ||
75 | rwbs[i] = '\0'; | ||
76 | } | ||
77 | |||
78 | static int log_action(struct trace_seq *s, struct blk_data *data, | ||
79 | const char *act) | ||
80 | { | ||
81 | char rwbs[6]; | ||
82 | |||
83 | fill_rwbs(rwbs, data->action, data->bytes); | ||
84 | return trace_seq_printf(s, "%3d,%-3d %2s %3s ", | ||
85 | MAJOR(data->device), | ||
86 | MINOR(data->device), act, rwbs); | ||
87 | } | ||
88 | |||
89 | static void blk_log_msg(struct trace_seq *s, void *data, int len) | ||
90 | { | ||
91 | trace_seq_printf(s, "%.*s", len, (char *)data); | ||
92 | } | ||
93 | |||
94 | static int blk_log_dump_pdu(struct trace_seq *s, const unsigned char *pdu_buf, | ||
95 | int pdu_len) | ||
96 | { | ||
97 | int i, end, ret; | ||
98 | |||
99 | if (!pdu_len) | ||
100 | return 1; | ||
101 | |||
102 | /* find the last zero that needs to be printed */ | ||
103 | for (end = pdu_len - 1; end >= 0; end--) | ||
104 | if (pdu_buf[end]) | ||
105 | break; | ||
106 | end++; | ||
107 | |||
108 | if (!trace_seq_putc(s, '(')) | ||
109 | return 0; | ||
110 | |||
111 | for (i = 0; i < pdu_len; i++) { | ||
112 | |||
113 | ret = trace_seq_printf(s, "%s%02x", | ||
114 | i == 0 ? "" : " ", pdu_buf[i]); | ||
115 | if (!ret) | ||
116 | return ret; | ||
117 | |||
118 | /* | ||
119 | * stop when the rest is just zeroes and indicate so | ||
120 | * with a ".." appended | ||
121 | */ | ||
122 | if (i == end && end != pdu_len - 1) | ||
123 | return trace_seq_puts(s, " ..) "); | ||
124 | } | ||
125 | |||
126 | return trace_seq_puts(s, ") "); | ||
127 | } | ||
128 | |||
129 | static unsigned int t_sec(int bytes) | ||
130 | { | ||
131 | return bytes >> 9; | ||
132 | } | ||
133 | |||
134 | static unsigned int be32_to_cpu(unsigned int val) | ||
135 | { | ||
136 | unsigned int swap; | ||
137 | |||
138 | if (tracecmd_host_bigendian()) | ||
139 | return val; | ||
140 | |||
141 | swap = ((val & 0xffULL) << 24) | | ||
142 | ((val & (0xffULL << 8)) << 8) | | ||
143 | ((val & (0xffULL << 16)) >> 8) | | ||
144 | ((val & (0xffULL << 24)) >> 24); | ||
145 | |||
146 | return swap; | ||
147 | } | ||
148 | |||
149 | static unsigned long long be64_to_cpu(unsigned long long val) | ||
150 | { | ||
151 | unsigned long long swap; | ||
152 | |||
153 | if (tracecmd_host_bigendian()) | ||
154 | return val; | ||
155 | |||
156 | swap = ((val & 0xffULL) << 56) | | ||
157 | ((val & (0xffULL << 8)) << 40) | | ||
158 | ((val & (0xffULL << 16)) << 24) | | ||
159 | ((val & (0xffULL << 24)) << 8) | | ||
160 | ((val & (0xffULL << 32)) >> 8) | | ||
161 | ((val & (0xffULL << 40)) >> 24) | | ||
162 | ((val & (0xffULL << 48)) >> 40) | | ||
163 | ((val & (0xffULL << 56)) >> 56); | ||
164 | |||
165 | return swap; | ||
166 | } | ||
167 | |||
168 | static unsigned long long get_pdu_int(void *data) | ||
169 | { | ||
170 | const unsigned long long *val = data; | ||
171 | return be64_to_cpu(*val); | ||
172 | } | ||
173 | |||
174 | static void get_pdu_remap(void *pdu_data, | ||
175 | struct blk_io_trace_remap *r) | ||
176 | { | ||
177 | const struct blk_io_trace_remap *__r = pdu_data; | ||
178 | unsigned long long sector_from = __r->sector_from; | ||
179 | |||
180 | r->device_from = be32_to_cpu(__r->device_from); | ||
181 | r->device_to = be32_to_cpu(__r->device_to); | ||
182 | r->sector_from = be64_to_cpu(sector_from); | ||
183 | } | ||
184 | |||
185 | static int blk_log_remap(struct trace_seq *s, struct blk_data *data) | ||
186 | { | ||
187 | struct blk_io_trace_remap r = { .device_from = 0, }; | ||
188 | |||
189 | get_pdu_remap(data->pdu_data, &r); | ||
190 | return trace_seq_printf(s, "%llu + %u <- (%d,%d) %llu\n", | ||
191 | data->sector, t_sec(data->bytes), | ||
192 | MAJOR(r.device_from), MINOR(r.device_from), | ||
193 | (unsigned long long)r.sector_from); | ||
194 | } | ||
195 | |||
196 | static int blk_log_split(struct trace_seq *s, struct blk_data *data) | ||
197 | { | ||
198 | const char *cmd; | ||
199 | |||
200 | cmd = pevent_data_comm_from_pid(data->event->pevent, data->pid); | ||
201 | |||
202 | return trace_seq_printf(s, "%llu / %llu [%s]\n", data->sector, | ||
203 | get_pdu_int(data->pdu_data), cmd); | ||
204 | } | ||
205 | |||
206 | static int blk_log_plug(struct trace_seq *s, struct blk_data *data) | ||
207 | { | ||
208 | const char *cmd; | ||
209 | |||
210 | cmd = pevent_data_comm_from_pid(data->event->pevent, data->pid); | ||
211 | |||
212 | return trace_seq_printf(s, "[%s]\n", cmd); | ||
213 | } | ||
214 | |||
215 | static int blk_log_unplug(struct trace_seq *s, struct blk_data *data) | ||
216 | { | ||
217 | const char *cmd; | ||
218 | |||
219 | cmd = pevent_data_comm_from_pid(data->event->pevent, data->pid); | ||
220 | |||
221 | return trace_seq_printf(s, "[%s] %llu\n", cmd, get_pdu_int(data->pdu_data)); | ||
222 | } | ||
223 | |||
224 | static int blk_log_with_error(struct trace_seq *s, struct blk_data *data) | ||
225 | { | ||
226 | if (data->action & BLK_TC_ACT(BLK_TC_PC)) { | ||
227 | blk_log_dump_pdu(s, data->pdu_data, data->pdu_len); | ||
228 | trace_seq_printf(s, "[%d]\n", data->error); | ||
229 | return 0; | ||
230 | } else { | ||
231 | if (t_sec(data->bytes)) | ||
232 | return trace_seq_printf(s, "%llu + %u [%d]\n", | ||
233 | data->sector, | ||
234 | t_sec(data->bytes), | ||
235 | data->error); | ||
236 | return trace_seq_printf(s, "%llu [%d]\n", | ||
237 | data->sector, data->error); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | static int blk_log_generic(struct trace_seq *s, struct blk_data *data) | ||
242 | { | ||
243 | const char *cmd; | ||
244 | |||
245 | cmd = pevent_data_comm_from_pid(data->event->pevent, data->pid); | ||
246 | |||
247 | if (data->action & BLK_TC_ACT(BLK_TC_PC)) { | ||
248 | int ret; | ||
249 | |||
250 | ret = trace_seq_printf(s, "%u ", data->bytes); | ||
251 | if (!ret) | ||
252 | return 0; | ||
253 | ret = blk_log_dump_pdu(s, data->pdu_data, data->pdu_len); | ||
254 | if (!ret) | ||
255 | return 0; | ||
256 | return trace_seq_printf(s, "[%s]\n", cmd); | ||
257 | } else { | ||
258 | if (t_sec(data->bytes)) | ||
259 | return trace_seq_printf(s, "%llu + %u [%s]\n", | ||
260 | data->sector, | ||
261 | t_sec(data->bytes), cmd); | ||
262 | return trace_seq_printf(s, "[%s]\n", cmd); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | static const struct { | ||
267 | const char *act[2]; | ||
268 | int (*print)(struct trace_seq *s, struct blk_data *data); | ||
269 | } what2act[] = { | ||
270 | [__BLK_TA_QUEUE] = {{ "Q", "queue" }, blk_log_generic }, | ||
271 | [__BLK_TA_BACKMERGE] = {{ "M", "backmerge" }, blk_log_generic }, | ||
272 | [__BLK_TA_FRONTMERGE] = {{ "F", "frontmerge" }, blk_log_generic }, | ||
273 | [__BLK_TA_GETRQ] = {{ "G", "getrq" }, blk_log_generic }, | ||
274 | [__BLK_TA_SLEEPRQ] = {{ "S", "sleeprq" }, blk_log_generic }, | ||
275 | [__BLK_TA_REQUEUE] = {{ "R", "requeue" }, blk_log_with_error }, | ||
276 | [__BLK_TA_ISSUE] = {{ "D", "issue" }, blk_log_generic }, | ||
277 | [__BLK_TA_COMPLETE] = {{ "C", "complete" }, blk_log_with_error }, | ||
278 | [__BLK_TA_PLUG] = {{ "P", "plug" }, blk_log_plug }, | ||
279 | [__BLK_TA_UNPLUG_IO] = {{ "U", "unplug_io" }, blk_log_unplug }, | ||
280 | [__BLK_TA_UNPLUG_TIMER] = {{ "UT", "unplug_timer" }, blk_log_unplug }, | ||
281 | [__BLK_TA_INSERT] = {{ "I", "insert" }, blk_log_generic }, | ||
282 | [__BLK_TA_SPLIT] = {{ "X", "split" }, blk_log_split }, | ||
283 | [__BLK_TA_BOUNCE] = {{ "B", "bounce" }, blk_log_generic }, | ||
284 | [__BLK_TA_REMAP] = {{ "A", "remap" }, blk_log_remap }, | ||
285 | }; | ||
286 | |||
287 | static int blktrace_handler(struct trace_seq *s, struct record *record, | ||
288 | struct event_format *event, void *context) | ||
289 | { | ||
290 | struct format_field *field; | ||
291 | unsigned long long val; | ||
292 | void *data = record->data; | ||
293 | struct blk_data blk_data; | ||
294 | unsigned short what; | ||
295 | int long_act = 0; | ||
296 | |||
297 | field = pevent_find_field(event, "action"); | ||
298 | if (!field) | ||
299 | return 1; | ||
300 | if (pevent_read_number_field(field, data, &val)) | ||
301 | return 1; | ||
302 | blk_data.action = val; | ||
303 | |||
304 | field = pevent_find_field(event, "bytes"); | ||
305 | if (!field) | ||
306 | return 1; | ||
307 | if (pevent_read_number_field(field, data, &val)) | ||
308 | return 1; | ||
309 | blk_data.bytes = val; | ||
310 | |||
311 | field = pevent_find_field(event, "device"); | ||
312 | if (!field) | ||
313 | return 1; | ||
314 | if (pevent_read_number_field(field, data, &val)) | ||
315 | return 1; | ||
316 | blk_data.device = val; | ||
317 | |||
318 | field = pevent_find_field(event, "pdu_len"); | ||
319 | if (!field) | ||
320 | return 1; | ||
321 | if (pevent_read_number_field(field, data, &val)) | ||
322 | return 1; | ||
323 | blk_data.pdu_len = val; | ||
324 | |||
325 | field = pevent_find_field(event, "data"); | ||
326 | if (!field) | ||
327 | return 1; | ||
328 | blk_data.pdu_data = data + field->offset; | ||
329 | |||
330 | field = pevent_find_field(event, "sector"); | ||
331 | if (!field) | ||
332 | return 1; | ||
333 | if (pevent_read_number_field(field, data, &blk_data.sector)) | ||
334 | return 1; | ||
335 | |||
336 | field = pevent_find_field(event, "pid"); | ||
337 | if (!field) | ||
338 | return 1; | ||
339 | if (pevent_read_number_field(field, data, &val)) | ||
340 | return 1; | ||
341 | blk_data.pid = val; | ||
342 | |||
343 | field = pevent_find_field(event, "error"); | ||
344 | if (!field) | ||
345 | return 1; | ||
346 | if (pevent_read_number_field(field, data, &val)) | ||
347 | return 1; | ||
348 | blk_data.error = val; | ||
349 | |||
350 | blk_data.event = event; | ||
351 | |||
352 | |||
353 | what = blk_data.action & ((1 << BLK_TC_SHIFT) - 1); | ||
354 | |||
355 | if (blk_data.action == BLK_TN_MESSAGE) { | ||
356 | log_action(s, &blk_data, "m"); | ||
357 | blk_log_msg(s, blk_data.pdu_data, blk_data.pdu_len); | ||
358 | goto out; | ||
359 | } | ||
360 | |||
361 | if (what == 0 || what >= ARRAY_SIZE(what2act)) | ||
362 | trace_seq_printf(s, "Unknown action %x\n", what); | ||
363 | else { | ||
364 | log_action(s, &blk_data, what2act[what].act[long_act]); | ||
365 | what2act[what].print(s, &blk_data); | ||
366 | } | ||
367 | |||
368 | out: | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
373 | { | ||
374 | pevent_register_event_handler(pevent, -1, "ftrace", "blktrace", | ||
375 | blktrace_handler, NULL); | ||
376 | return 0; | ||
377 | } | ||
diff --git a/trace-blk-hack.c b/trace-blk-hack.c new file mode 100644 index 0000000..29c3c74 --- /dev/null +++ b/trace-blk-hack.c | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
20 | */ | ||
21 | #include <stdio.h> | ||
22 | #include "trace-cmd.h" | ||
23 | #include "trace-local.h" | ||
24 | |||
25 | static const char blk_event_start[] = | ||
26 | "name: blktrace\n" | ||
27 | "ID: %d\n" | ||
28 | "format:\n" | ||
29 | "\tfield:unsigned short common_type;\toffset:0;\tsize:2;\n" | ||
30 | "\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\n" | ||
31 | "\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\n" | ||
32 | "\tfield:int common_pid;\toffset:4;\tsize:4;\n"; | ||
33 | |||
34 | static const char blk_body[] = "\n" | ||
35 | "\tfield:u64 sector;\toffset:16;\tsize:8;\n" | ||
36 | "\tfield:int bytes;\toffset:24;\tsize:4;\n" | ||
37 | "\tfield:int action;\toffset:28;\tsize:4;\n" | ||
38 | "\tfield:int pid;\toffset:32;\tsize:4;\n" | ||
39 | "\tfield:int device;\toffset:36;\tsize:4;\n" | ||
40 | "\tfield:int cpu;\toffset:40;\tsize:4;\n" | ||
41 | "\tfield:short error;\toffset:44;\tsize:2;\n" | ||
42 | "\tfield:short pdu_len;\toffset:46;\tsize:2;\n" | ||
43 | "\tfield:void data;\toffset:48;\tsize:0;\n" | ||
44 | "\n" | ||
45 | "print fmt: \"%%d\", REC->pid\n"; | ||
46 | |||
47 | int tracecmd_blk_hack(struct tracecmd_input *handle) | ||
48 | { | ||
49 | struct pevent *pevent; | ||
50 | struct event_format *event; | ||
51 | struct format_field *field; | ||
52 | char buf[4096]; /* way more than enough! */ | ||
53 | int id; | ||
54 | int l; | ||
55 | int r; | ||
56 | int i; | ||
57 | |||
58 | pevent = tracecmd_get_pevent(handle); | ||
59 | |||
60 | /* | ||
61 | * Unfortunately, the TRACE_BLK has changed a bit. | ||
62 | * We need to test if various events exist to try | ||
63 | * to guess what event id TRACE_BLK would be. | ||
64 | */ | ||
65 | |||
66 | /* It was originally behind the "power" event */ | ||
67 | event = pevent_find_event_by_name(pevent, "ftrace", "power"); | ||
68 | if (event) { | ||
69 | id = event->id + 1; | ||
70 | goto found; | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * But the power tracer is now in perf. | ||
75 | * Then it was after kmem_free | ||
76 | */ | ||
77 | event = pevent_find_event_by_name(pevent, "ftrace", "kmem_free"); | ||
78 | if (event) { | ||
79 | id = event->id + 1; | ||
80 | goto found; | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * But that then went away. | ||
85 | * Currently it should be behind the user stack. | ||
86 | */ | ||
87 | event = pevent_find_event_by_name(pevent, "ftrace", "user_stack"); | ||
88 | if (event) { | ||
89 | id = event->id + 1; | ||
90 | goto found; | ||
91 | } | ||
92 | /* Give up :( */ | ||
93 | return -1; | ||
94 | |||
95 | found: | ||
96 | /* | ||
97 | * Blk events are not exported in the events directory. | ||
98 | * This is a hack to attempt to create a block event | ||
99 | * that we can read. | ||
100 | * | ||
101 | * We'll make a format file to look like this: | ||
102 | * | ||
103 | * name: blktrace | ||
104 | * ID: 13 | ||
105 | * format: | ||
106 | * field:unsigned short common_type; offset:0; size:2; | ||
107 | * field:unsigned char common_flags; offset:2; size:1; | ||
108 | * field:unsigned char common_preempt_count; offset:3; size:1; | ||
109 | * field:int common_pid; offset:4; size:4; | ||
110 | * field:int common_lock_depth; offset:8; size:4; | ||
111 | * | ||
112 | * field:u64 sector; offset:16; size:8; | ||
113 | * field:int bytes; offset:32; size:4; | ||
114 | * field:int action; offset:36; size:4; | ||
115 | * field:int pid; offset:40; size:4; | ||
116 | * field:int device; offset:44; size:4; | ||
117 | * field:int cpu; offset:48; size:4; | ||
118 | * field:short error; offset:52; size:2; | ||
119 | * field:short pdu_len; offset:54; size:2; | ||
120 | * field:void data; offset:60; size:0; | ||
121 | * | ||
122 | * print fmt: "%d", REC->pid | ||
123 | * | ||
124 | * Note: the struct blk_io_trace is used directly and | ||
125 | * just the first parts of the struct are not used in order | ||
126 | * to not write over the ftrace data. | ||
127 | */ | ||
128 | |||
129 | /* search for a ftrace event */ | ||
130 | for (i = 0; i < 13; i++) { | ||
131 | event = pevent_find_event(pevent, i); | ||
132 | if (event) | ||
133 | break; | ||
134 | } | ||
135 | if (!event) | ||
136 | goto fail; | ||
137 | |||
138 | /* Make sure the common fields exist */ | ||
139 | field = pevent_find_common_field(event, "common_type"); | ||
140 | if (!field || field->offset != 0 || field->size != 2) | ||
141 | goto fail; | ||
142 | field = pevent_find_common_field(event, "common_flags"); | ||
143 | if (!field || field->offset != 2 || field->size != 1) | ||
144 | goto fail; | ||
145 | field = pevent_find_common_field(event, "common_preempt_count"); | ||
146 | if (!field || field->offset != 3 || field->size != 1) | ||
147 | goto fail; | ||
148 | field = pevent_find_common_field(event, "common_pid"); | ||
149 | if (!field || field->offset != 4 || field->size != 4) | ||
150 | goto fail; | ||
151 | r = sprintf(buf, blk_event_start, id); | ||
152 | l = r; | ||
153 | |||
154 | /* lock depth is optional */ | ||
155 | field = pevent_find_common_field(event, "common_lock_depth"); | ||
156 | if (field) { | ||
157 | if (field->offset != 8 || field->size != 4) | ||
158 | return -1; | ||
159 | r = sprintf(buf+l, "\tfield:int common_lock_depth;\toffset:8;\tsize:4;\n"); | ||
160 | l += r; | ||
161 | } | ||
162 | |||
163 | r = sprintf(buf+l, blk_body); | ||
164 | |||
165 | /* Parse this event */ | ||
166 | l += r; | ||
167 | pevent_parse_event(pevent, buf, l, "ftrace"); | ||
168 | |||
169 | return 0; | ||
170 | |||
171 | fail: | ||
172 | exit(0); | ||
173 | printf("failed!\n"); | ||
174 | return -1; | ||
175 | } | ||
diff --git a/trace-cmd.h b/trace-cmd.h index b3cc6b4..9063c8c 100644 --- a/trace-cmd.h +++ b/trace-cmd.h | |||
@@ -214,4 +214,7 @@ void trace_util_load_plugins(struct pevent *pevent, const char *suffix, | |||
214 | void *data), | 214 | void *data), |
215 | void *data); | 215 | void *data); |
216 | 216 | ||
217 | /* --- Hack! --- */ | ||
218 | int tracecmd_blk_hack(struct tracecmd_input *handle); | ||
219 | |||
217 | #endif /* _TRACE_CMD_H */ | 220 | #endif /* _TRACE_CMD_H */ |
diff --git a/trace-input.c b/trace-input.c index b11392e..c3b58b1 100644 --- a/trace-input.c +++ b/trace-input.c | |||
@@ -2089,6 +2089,8 @@ int tracecmd_init_data(struct tracecmd_input *handle) | |||
2089 | return -1; | 2089 | return -1; |
2090 | } | 2090 | } |
2091 | 2091 | ||
2092 | tracecmd_blk_hack(handle); | ||
2093 | |||
2092 | return 0; | 2094 | return 0; |
2093 | } | 2095 | } |
2094 | 2096 | ||