c4054aa761b0e15f606d1f019dbda3b25a9f60e4
[lttv.git] / lttv / modules / text / formattedDump.c
1 /*
2 * This file is part of the Linux Trace Toolkit viewer
3 * Copyright (C) 2003-2004 Michel Dagenais
4 * 2005 Mathieu Desnoyers
5 * 2011 Vincent Attard <vinc.attard@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License Version 2 as
9 * published by the Free Software Foundation;
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 * MA 02111-1307, USA.
20 */
21
22 /*
23 * Formatted dump plugin prints a formatted output of each events in a trace.
24 * The output format is defined as a parameter. It provides a default format
25 * easy to read, a "strace-like" format and the original textDump format for
26 * backward compatibility.
27 */
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
32
33 #include <lttv/lttv.h>
34 #include <lttv/option.h>
35 #include <lttv/module.h>
36 #include <lttv/hook.h>
37 #include <lttv/attribute.h>
38 #include <lttv/iattribute.h>
39 #include <lttv/stats.h>
40 #include <lttv/filter.h>
41 #include <lttv/print.h>
42 #include <ltt/ltt.h>
43 #include <ltt/event.h>
44 #include <ltt/trace.h>
45 #include <stdio.h>
46 #include <inttypes.h>
47 #include <string.h>
48 #include <stdlib.h>
49
50 static gboolean a_no_field_names;
51 static gboolean a_state;
52 static gboolean a_text;
53 static gboolean a_strace;
54 static gboolean a_meta;
55 static char *a_file_name;
56 static char *a_format;
57
58 static LttvHooks *before_traceset;
59 static LttvHooks *event_hook;
60
61 static const char default_format[] =
62 "channel:%c event:%e timestamp:%t elapsed:%l cpu:%u pid:%d "
63 "ppid:%i tgpid:%g process:%p brand:%b state:%a payload:{ %m }";
64 static const char textDump_format[] =
65 "%c.%e: %s.%n (%r/%c_%u), %d, %g, %p, %b, %i, %y, %a { %m }";
66 static const char strace_format[] = "%e(%m) %s.%n";
67 static const char *fmt;
68
69 static FILE *a_file;
70
71 static GString *a_string;
72
73 static int output_format_len;
74
75 static gboolean open_output_file(void *hook_data, void *call_data)
76 {
77 if (a_text) {
78 /* textDump format (used with -T command option) */
79 fmt = textDump_format;
80 } else if (a_strace) {
81 /* strace-like format (used with -S command option) */
82 fmt = strace_format;
83 } else if (!a_format) {
84 /* Default format (used if no option) */
85 fmt = default_format;
86 } else {
87 /*
88 * formattedDump format
89 * (used with -F command option following by the desired format)
90 */
91 fmt = a_format;
92 }
93
94 output_format_len = strlen(fmt);
95
96 g_info("Open the output file");
97 if (a_file_name == NULL) {
98 a_file = stdout;
99 } else {
100 a_file = fopen(a_file_name, "w");
101 }
102 if (a_file == NULL) {
103 g_error("cannot open file %s", a_file_name);
104 }
105 return FALSE;
106 }
107
108 static int write_event_content(void *hook_data, void *call_data)
109 {
110 gboolean result;
111
112 LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes());
113
114 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
115
116 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
117
118 LttEvent *e;
119
120 LttvAttributeValue value_filter;
121
122 LttvFilter *filter;
123
124 guint cpu = tfs->cpu;
125 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
126 LttvProcessState *process = ts->running_process[cpu];
127
128 e = ltt_tracefile_get_event(tfc->tf);
129
130 result = lttv_iattribute_find_by_path(attributes, "filter/lttv_filter",
131 LTTV_POINTER, &value_filter);
132 g_assert(result);
133 filter = (LttvFilter *)*(value_filter.v_pointer);
134
135 /* call to the filter if available */
136 if (filter->head != NULL) {
137 if (!lttv_filter_tree_parse(filter->head, e, tfc->tf,
138 tfc->t_context->t, tfc, NULL, NULL)) {
139 return FALSE;
140 }
141 }
142
143 /*
144 * By default, metadata's channel won't be display: it goes directly
145 * to the next event. You can have metadata's information with -M
146 * switch (a_meta option).
147 */
148 if (!a_meta && ltt_tracefile_name(tfs->parent.tf) ==
149 g_quark_from_string("metadata")) {
150 return FALSE;
151 /*
152 * TODO:
153 * Investigate the use of filter to do it.
154 */
155 }
156
157 lttv_event_to_string(e, a_string, TRUE, !a_no_field_names, tfs);
158
159 if (a_state) {
160 g_string_append_printf(a_string, "%s ",
161 g_quark_to_string(process->state->s));
162 }
163
164 g_string_append_printf(a_string, "\n");
165
166 fputs(a_string->str, a_file);
167 return FALSE;
168 }
169
170 void lttv_event_to_string(LttEvent *e, GString *string_buffer, gboolean mandatory_fields,
171 gboolean field_names, LttvTracefileState *tfs)
172 {
173 struct marker_field *field;
174 struct marker_info *info;
175
176 LttTime time;
177 LttTime elapse;
178 static LttTime time_prev = {0, 0};
179 /*
180 * TODO:
181 * Added this static value into state.c and reset each time you do a
182 * seek for using it in the GUI.
183 */
184
185 int i;
186 guint cpu = tfs->cpu;
187 LttvTraceState *ts = (LttvTraceState *)tfs->parent.t_context;
188 LttvProcessState *process = ts->running_process[cpu];
189
190 info = marker_get_info_from_id(tfs->parent.tf->mdata, e->event_id);
191 if (mandatory_fields) {
192 time = ltt_event_time(e);
193 /* Calculate elapsed time between current and previous event */
194 if (time_prev.tv_sec == 0 && time_prev.tv_nsec == 0) {
195 time_prev = ltt_event_time(e);
196 elapse.tv_sec = 0;
197 elapse.tv_nsec = 0;
198 /*
199 * TODO:
200 * Keep in mind that you should add the ability to
201 * restore the previous event time to state.c if you
202 * want to reuse this code into the GUI.
203 */
204 } else {
205 elapse = ltt_time_sub(time, time_prev);
206 time_prev = time;
207 }
208 }
209 g_string_set_size(string_buffer, 0);
210 /*
211 * Switch case:
212 * all '%-' are replaced by the desired value in 'string_buffer'
213 */
214 for (i = 0; i < output_format_len; i++) {
215 if (fmt[i] == '%') {
216 switch (fmt[++i]) {
217 case 't':
218 g_string_append_printf(string_buffer,
219 "%ld:%02ld:%02ld.%09ld",
220 time.tv_sec/3600,
221 (time.tv_sec%3600)/60,
222 time.tv_sec%60,
223 time.tv_nsec);
224 break;
225 case 'c':
226 g_string_append(string_buffer,
227 g_quark_to_string(ltt_tracefile_name(tfs->parent.tf)));
228 break;
229 case 'e':
230 g_string_append(string_buffer,
231 g_quark_to_string(info->name));
232 break;
233 case 'd':
234 g_string_append_printf(string_buffer, "%u",
235 process->pid);
236 break;
237 case 's':
238 g_string_append_printf(string_buffer, "%ld",
239 time.tv_sec);
240 break;
241 case 'n':
242 g_string_append_printf(string_buffer, "%ld",
243 time.tv_nsec);
244 break;
245 case 'i':
246 g_string_append_printf(string_buffer, "%u",
247 process->ppid);
248 break;
249 case 'g':
250 g_string_append_printf(string_buffer, "%u",
251 process->tgid);
252 break;
253 case 'p':
254 g_string_append(string_buffer,
255 g_quark_to_string(process->name));
256 break;
257 case 'b':
258 g_string_append(string_buffer,
259 g_quark_to_string(process->brand));
260 break;
261 case 'u':
262 g_string_append_printf(string_buffer, "%u", cpu);
263 break;
264 case 'l':
265 g_string_append_printf(string_buffer,
266 "%ld.%09ld",
267 elapse.tv_sec, elapse.tv_nsec);
268 break;
269 case 'a':
270 g_string_append(string_buffer,
271 g_quark_to_string(process->state->t));
272 break;
273 case 'm':
274 {
275 /*
276 * Get and print markers and tracepoints fields
277 * into 'string_buffer'
278 */
279 if (marker_get_num_fields(info) == 0)
280 break;
281 for (field = marker_get_field(info, 0);
282 field != marker_get_field(info, marker_get_num_fields(info));
283 field++) {
284 if (field != marker_get_field(info, 0)) {
285 g_string_append(string_buffer, ", ");
286 }
287
288 lttv_print_field(e, field, string_buffer, field_names, tfs);
289 }
290 }
291 break;
292 case 'r':
293 g_string_append(string_buffer, g_quark_to_string(
294 ltt_trace_name(ltt_tracefile_get_trace(tfs->parent.tf))));
295 break;
296 case '%':
297 g_string_append_c(string_buffer, '%');
298 break;
299 case 'y':
300 g_string_append_printf(string_buffer,
301 "0x%" PRIx64,
302 process->current_function);
303 break;
304 }
305 } else {
306 /* Copy every character if different of '%' */
307 g_string_append_c(string_buffer, fmt[i]);
308 }
309 }
310 }
311
312 static void init()
313 {
314 gboolean result;
315
316 LttvAttributeValue value;
317
318 LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes());
319
320 g_info("Init formattedDump.c");
321
322 a_string = g_string_new("");
323
324 a_file_name = NULL;
325 lttv_option_add("output", 'o',
326 "output file where the text is written",
327 "file name",
328 LTTV_OPT_STRING, &a_file_name, NULL, NULL);
329
330 a_text = FALSE;
331 lttv_option_add("text", 'T',
332 "output the textDump format",
333 "",
334 LTTV_OPT_NONE, &a_text, NULL, NULL);
335
336 a_strace = FALSE;
337 lttv_option_add("strace", 'S',
338 "output a \"strace-like\" format",
339 "",
340 LTTV_OPT_NONE, &a_strace, NULL, NULL);
341
342 a_meta = FALSE;
343 lttv_option_add("metadata", 'M',
344 "add metadata information",
345 "",
346 LTTV_OPT_NONE, &a_meta, NULL, NULL);
347
348 a_format = NULL;
349 lttv_option_add("format", 'F',
350 "output the desired format\n"
351 " FORMAT controls the output. "
352 "Interpreted sequences are:\n"
353 "\n"
354 " %c channel name\n"
355 " %p process name\n"
356 " %e event name\n"
357 " %r path to trace\n"
358 " %t timestamp (e.g., 2:08:54.025684145)\n"
359 " %s seconds\n"
360 " %n nanoseconds\n"
361 " %l elapsed time with the previous event\n"
362 " %d pid\n"
363 " %i ppid\n"
364 " %g tgid\n"
365 " %u cpu\n"
366 " %b brand\n"
367 " %a state\n"
368 " %y memory address\n"
369 " %m markers and tracepoints fields\n",
370 "format string (e.g., \"channel:%c event:%e process:%p\")",
371 LTTV_OPT_STRING, &a_format, NULL, NULL);
372
373 result = lttv_iattribute_find_by_path(attributes, "hooks/event",
374 LTTV_POINTER, &value);
375 g_assert(result);
376 event_hook = *(value.v_pointer);
377 g_assert(event_hook);
378 lttv_hooks_add(event_hook, write_event_content, NULL, LTTV_PRIO_DEFAULT);
379
380 result = lttv_iattribute_find_by_path(attributes, "hooks/traceset/before",
381 LTTV_POINTER, &value);
382 g_assert(result);
383 before_traceset = *(value.v_pointer);
384 g_assert(before_traceset);
385 lttv_hooks_add(before_traceset, open_output_file, NULL,
386 LTTV_PRIO_DEFAULT);
387
388 }
389
390 static void destroy()
391 {
392 g_info("Destroy formattedDump");
393
394 lttv_option_remove("format");
395
396 lttv_option_remove("output");
397
398 lttv_option_remove("text");
399
400 lttv_option_remove("strace");
401
402 lttv_option_remove("metadata");
403
404 g_string_free(a_string, TRUE);
405
406 lttv_hooks_remove_data(event_hook, write_event_content, NULL);
407
408 lttv_hooks_remove_data(before_traceset, open_output_file, NULL);
409
410 }
411
412
413 LTTV_MODULE("formattedDump", "Print events with desired format in a file",
414 "Produce a detailed formatted text printout of a trace",
415 init, destroy, "batchAnalysis", "option")
This page took 0.036045 seconds and 3 git commands to generate.