diff options
Diffstat (limited to 'tools/perf/util/scripting-engines/trace-event-python.c')
-rw-r--r-- | tools/perf/util/scripting-engines/trace-event-python.c | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c new file mode 100644 index 000000000000..33a414bbba3e --- /dev/null +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -0,0 +1,573 @@ | |||
1 | /* | ||
2 | * trace-event-python. Feed trace events to an embedded Python interpreter. | ||
3 | * | ||
4 | * Copyright (C) 2010 Tom Zanussi <tzanussi@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
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, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <Python.h> | ||
23 | |||
24 | #include <stdio.h> | ||
25 | #include <stdlib.h> | ||
26 | #include <string.h> | ||
27 | #include <ctype.h> | ||
28 | #include <errno.h> | ||
29 | |||
30 | #include "../../perf.h" | ||
31 | #include "../util.h" | ||
32 | #include "../trace-event.h" | ||
33 | |||
34 | PyMODINIT_FUNC initperf_trace_context(void); | ||
35 | |||
36 | #define FTRACE_MAX_EVENT \ | ||
37 | ((1 << (sizeof(unsigned short) * 8)) - 1) | ||
38 | |||
39 | struct event *events[FTRACE_MAX_EVENT]; | ||
40 | |||
41 | #define MAX_FIELDS 64 | ||
42 | #define N_COMMON_FIELDS 7 | ||
43 | |||
44 | extern struct scripting_context *scripting_context; | ||
45 | |||
46 | static char *cur_field_name; | ||
47 | static int zero_flag_atom; | ||
48 | |||
49 | static PyObject *main_module, *main_dict; | ||
50 | |||
51 | static void handler_call_die(const char *handler_name) | ||
52 | { | ||
53 | PyErr_Print(); | ||
54 | Py_FatalError("problem in Python trace event handler"); | ||
55 | } | ||
56 | |||
57 | static void define_value(enum print_arg_type field_type, | ||
58 | const char *ev_name, | ||
59 | const char *field_name, | ||
60 | const char *field_value, | ||
61 | const char *field_str) | ||
62 | { | ||
63 | const char *handler_name = "define_flag_value"; | ||
64 | PyObject *handler, *t, *retval; | ||
65 | unsigned long long value; | ||
66 | unsigned n = 0; | ||
67 | |||
68 | if (field_type == PRINT_SYMBOL) | ||
69 | handler_name = "define_symbolic_value"; | ||
70 | |||
71 | t = PyTuple_New(4); | ||
72 | if (!t) | ||
73 | Py_FatalError("couldn't create Python tuple"); | ||
74 | |||
75 | value = eval_flag(field_value); | ||
76 | |||
77 | PyTuple_SetItem(t, n++, PyString_FromString(ev_name)); | ||
78 | PyTuple_SetItem(t, n++, PyString_FromString(field_name)); | ||
79 | PyTuple_SetItem(t, n++, PyInt_FromLong(value)); | ||
80 | PyTuple_SetItem(t, n++, PyString_FromString(field_str)); | ||
81 | |||
82 | handler = PyDict_GetItemString(main_dict, handler_name); | ||
83 | if (handler && PyCallable_Check(handler)) { | ||
84 | retval = PyObject_CallObject(handler, t); | ||
85 | if (retval == NULL) | ||
86 | handler_call_die(handler_name); | ||
87 | } | ||
88 | |||
89 | Py_DECREF(t); | ||
90 | } | ||
91 | |||
92 | static void define_values(enum print_arg_type field_type, | ||
93 | struct print_flag_sym *field, | ||
94 | const char *ev_name, | ||
95 | const char *field_name) | ||
96 | { | ||
97 | define_value(field_type, ev_name, field_name, field->value, | ||
98 | field->str); | ||
99 | |||
100 | if (field->next) | ||
101 | define_values(field_type, field->next, ev_name, field_name); | ||
102 | } | ||
103 | |||
104 | static void define_field(enum print_arg_type field_type, | ||
105 | const char *ev_name, | ||
106 | const char *field_name, | ||
107 | const char *delim) | ||
108 | { | ||
109 | const char *handler_name = "define_flag_field"; | ||
110 | PyObject *handler, *t, *retval; | ||
111 | unsigned n = 0; | ||
112 | |||
113 | if (field_type == PRINT_SYMBOL) | ||
114 | handler_name = "define_symbolic_field"; | ||
115 | |||
116 | if (field_type == PRINT_FLAGS) | ||
117 | t = PyTuple_New(3); | ||
118 | else | ||
119 | t = PyTuple_New(2); | ||
120 | if (!t) | ||
121 | Py_FatalError("couldn't create Python tuple"); | ||
122 | |||
123 | PyTuple_SetItem(t, n++, PyString_FromString(ev_name)); | ||
124 | PyTuple_SetItem(t, n++, PyString_FromString(field_name)); | ||
125 | if (field_type == PRINT_FLAGS) | ||
126 | PyTuple_SetItem(t, n++, PyString_FromString(delim)); | ||
127 | |||
128 | handler = PyDict_GetItemString(main_dict, handler_name); | ||
129 | if (handler && PyCallable_Check(handler)) { | ||
130 | retval = PyObject_CallObject(handler, t); | ||
131 | if (retval == NULL) | ||
132 | handler_call_die(handler_name); | ||
133 | } | ||
134 | |||
135 | Py_DECREF(t); | ||
136 | } | ||
137 | |||
138 | static void define_event_symbols(struct event *event, | ||
139 | const char *ev_name, | ||
140 | struct print_arg *args) | ||
141 | { | ||
142 | switch (args->type) { | ||
143 | case PRINT_NULL: | ||
144 | break; | ||
145 | case PRINT_ATOM: | ||
146 | define_value(PRINT_FLAGS, ev_name, cur_field_name, "0", | ||
147 | args->atom.atom); | ||
148 | zero_flag_atom = 0; | ||
149 | break; | ||
150 | case PRINT_FIELD: | ||
151 | if (cur_field_name) | ||
152 | free(cur_field_name); | ||
153 | cur_field_name = strdup(args->field.name); | ||
154 | break; | ||
155 | case PRINT_FLAGS: | ||
156 | define_event_symbols(event, ev_name, args->flags.field); | ||
157 | define_field(PRINT_FLAGS, ev_name, cur_field_name, | ||
158 | args->flags.delim); | ||
159 | define_values(PRINT_FLAGS, args->flags.flags, ev_name, | ||
160 | cur_field_name); | ||
161 | break; | ||
162 | case PRINT_SYMBOL: | ||
163 | define_event_symbols(event, ev_name, args->symbol.field); | ||
164 | define_field(PRINT_SYMBOL, ev_name, cur_field_name, NULL); | ||
165 | define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name, | ||
166 | cur_field_name); | ||
167 | break; | ||
168 | case PRINT_STRING: | ||
169 | break; | ||
170 | case PRINT_TYPE: | ||
171 | define_event_symbols(event, ev_name, args->typecast.item); | ||
172 | break; | ||
173 | case PRINT_OP: | ||
174 | if (strcmp(args->op.op, ":") == 0) | ||
175 | zero_flag_atom = 1; | ||
176 | define_event_symbols(event, ev_name, args->op.left); | ||
177 | define_event_symbols(event, ev_name, args->op.right); | ||
178 | break; | ||
179 | default: | ||
180 | /* we should warn... */ | ||
181 | return; | ||
182 | } | ||
183 | |||
184 | if (args->next) | ||
185 | define_event_symbols(event, ev_name, args->next); | ||
186 | } | ||
187 | |||
188 | static inline struct event *find_cache_event(int type) | ||
189 | { | ||
190 | static char ev_name[256]; | ||
191 | struct event *event; | ||
192 | |||
193 | if (events[type]) | ||
194 | return events[type]; | ||
195 | |||
196 | events[type] = event = trace_find_event(type); | ||
197 | if (!event) | ||
198 | return NULL; | ||
199 | |||
200 | sprintf(ev_name, "%s__%s", event->system, event->name); | ||
201 | |||
202 | define_event_symbols(event, ev_name, event->print_fmt.args); | ||
203 | |||
204 | return event; | ||
205 | } | ||
206 | |||
207 | static void python_process_event(int cpu, void *data, | ||
208 | int size __unused, | ||
209 | unsigned long long nsecs, char *comm) | ||
210 | { | ||
211 | PyObject *handler, *retval, *context, *t; | ||
212 | static char handler_name[256]; | ||
213 | struct format_field *field; | ||
214 | unsigned long long val; | ||
215 | unsigned long s, ns; | ||
216 | struct event *event; | ||
217 | unsigned n = 0; | ||
218 | int type; | ||
219 | int pid; | ||
220 | |||
221 | t = PyTuple_New(MAX_FIELDS); | ||
222 | if (!t) | ||
223 | Py_FatalError("couldn't create Python tuple"); | ||
224 | |||
225 | type = trace_parse_common_type(data); | ||
226 | |||
227 | event = find_cache_event(type); | ||
228 | if (!event) | ||
229 | die("ug! no event found for type %d", type); | ||
230 | |||
231 | pid = trace_parse_common_pid(data); | ||
232 | |||
233 | sprintf(handler_name, "%s__%s", event->system, event->name); | ||
234 | |||
235 | s = nsecs / NSECS_PER_SEC; | ||
236 | ns = nsecs - s * NSECS_PER_SEC; | ||
237 | |||
238 | scripting_context->event_data = data; | ||
239 | |||
240 | context = PyCObject_FromVoidPtr(scripting_context, NULL); | ||
241 | |||
242 | PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); | ||
243 | PyTuple_SetItem(t, n++, | ||
244 | PyCObject_FromVoidPtr(scripting_context, NULL)); | ||
245 | PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); | ||
246 | PyTuple_SetItem(t, n++, PyInt_FromLong(s)); | ||
247 | PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); | ||
248 | PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); | ||
249 | PyTuple_SetItem(t, n++, PyString_FromString(comm)); | ||
250 | |||
251 | for (field = event->format.fields; field; field = field->next) { | ||
252 | if (field->flags & FIELD_IS_STRING) { | ||
253 | int offset; | ||
254 | if (field->flags & FIELD_IS_DYNAMIC) { | ||
255 | offset = *(int *)(data + field->offset); | ||
256 | offset &= 0xffff; | ||
257 | } else | ||
258 | offset = field->offset; | ||
259 | PyTuple_SetItem(t, n++, | ||
260 | PyString_FromString((char *)data + offset)); | ||
261 | } else { /* FIELD_IS_NUMERIC */ | ||
262 | val = read_size(data + field->offset, field->size); | ||
263 | if (field->flags & FIELD_IS_SIGNED) { | ||
264 | PyTuple_SetItem(t, n++, PyInt_FromLong(val)); | ||
265 | } else { | ||
266 | PyTuple_SetItem(t, n++, PyInt_FromLong(val)); | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | |||
271 | if (_PyTuple_Resize(&t, n) == -1) | ||
272 | Py_FatalError("error resizing Python tuple"); | ||
273 | |||
274 | handler = PyDict_GetItemString(main_dict, handler_name); | ||
275 | if (handler && PyCallable_Check(handler)) { | ||
276 | retval = PyObject_CallObject(handler, t); | ||
277 | if (retval == NULL) | ||
278 | handler_call_die(handler_name); | ||
279 | } else { | ||
280 | handler = PyDict_GetItemString(main_dict, "trace_unhandled"); | ||
281 | if (handler && PyCallable_Check(handler)) { | ||
282 | if (_PyTuple_Resize(&t, N_COMMON_FIELDS) == -1) | ||
283 | Py_FatalError("error resizing Python tuple"); | ||
284 | |||
285 | retval = PyObject_CallObject(handler, t); | ||
286 | if (retval == NULL) | ||
287 | handler_call_die("trace_unhandled"); | ||
288 | } | ||
289 | } | ||
290 | |||
291 | Py_DECREF(t); | ||
292 | } | ||
293 | |||
294 | static int run_start_sub(void) | ||
295 | { | ||
296 | PyObject *handler, *retval; | ||
297 | int err = 0; | ||
298 | |||
299 | main_module = PyImport_AddModule("__main__"); | ||
300 | if (main_module == NULL) | ||
301 | return -1; | ||
302 | Py_INCREF(main_module); | ||
303 | |||
304 | main_dict = PyModule_GetDict(main_module); | ||
305 | if (main_dict == NULL) { | ||
306 | err = -1; | ||
307 | goto error; | ||
308 | } | ||
309 | Py_INCREF(main_dict); | ||
310 | |||
311 | handler = PyDict_GetItemString(main_dict, "trace_begin"); | ||
312 | if (handler == NULL || !PyCallable_Check(handler)) | ||
313 | goto out; | ||
314 | |||
315 | retval = PyObject_CallObject(handler, NULL); | ||
316 | if (retval == NULL) | ||
317 | handler_call_die("trace_begin"); | ||
318 | |||
319 | Py_DECREF(retval); | ||
320 | return err; | ||
321 | error: | ||
322 | Py_XDECREF(main_dict); | ||
323 | Py_XDECREF(main_module); | ||
324 | out: | ||
325 | return err; | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * Start trace script | ||
330 | */ | ||
331 | static int python_start_script(const char *script, int argc, const char **argv) | ||
332 | { | ||
333 | const char **command_line; | ||
334 | char buf[PATH_MAX]; | ||
335 | int i, err = 0; | ||
336 | FILE *fp; | ||
337 | |||
338 | command_line = malloc((argc + 1) * sizeof(const char *)); | ||
339 | command_line[0] = script; | ||
340 | for (i = 1; i < argc + 1; i++) | ||
341 | command_line[i] = argv[i - 1]; | ||
342 | |||
343 | Py_Initialize(); | ||
344 | |||
345 | initperf_trace_context(); | ||
346 | |||
347 | PySys_SetArgv(argc + 1, (char **)command_line); | ||
348 | |||
349 | fp = fopen(script, "r"); | ||
350 | if (!fp) { | ||
351 | sprintf(buf, "Can't open python script \"%s\"", script); | ||
352 | perror(buf); | ||
353 | err = -1; | ||
354 | goto error; | ||
355 | } | ||
356 | |||
357 | err = PyRun_SimpleFile(fp, script); | ||
358 | if (err) { | ||
359 | fprintf(stderr, "Error running python script %s\n", script); | ||
360 | goto error; | ||
361 | } | ||
362 | |||
363 | err = run_start_sub(); | ||
364 | if (err) { | ||
365 | fprintf(stderr, "Error starting python script %s\n", script); | ||
366 | goto error; | ||
367 | } | ||
368 | |||
369 | free(command_line); | ||
370 | fprintf(stderr, "perf trace started with Python script %s\n\n", | ||
371 | script); | ||
372 | |||
373 | return err; | ||
374 | error: | ||
375 | Py_Finalize(); | ||
376 | free(command_line); | ||
377 | |||
378 | return err; | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * Stop trace script | ||
383 | */ | ||
384 | static int python_stop_script(void) | ||
385 | { | ||
386 | PyObject *handler, *retval; | ||
387 | int err = 0; | ||
388 | |||
389 | handler = PyDict_GetItemString(main_dict, "trace_end"); | ||
390 | if (handler == NULL || !PyCallable_Check(handler)) | ||
391 | goto out; | ||
392 | |||
393 | retval = PyObject_CallObject(handler, NULL); | ||
394 | if (retval == NULL) | ||
395 | handler_call_die("trace_end"); | ||
396 | else | ||
397 | Py_DECREF(retval); | ||
398 | out: | ||
399 | Py_XDECREF(main_dict); | ||
400 | Py_XDECREF(main_module); | ||
401 | Py_Finalize(); | ||
402 | |||
403 | fprintf(stderr, "\nperf trace Python script stopped\n"); | ||
404 | |||
405 | return err; | ||
406 | } | ||
407 | |||
408 | static int python_generate_script(const char *outfile) | ||
409 | { | ||
410 | struct event *event = NULL; | ||
411 | struct format_field *f; | ||
412 | char fname[PATH_MAX]; | ||
413 | int not_first, count; | ||
414 | FILE *ofp; | ||
415 | |||
416 | sprintf(fname, "%s.py", outfile); | ||
417 | ofp = fopen(fname, "w"); | ||
418 | if (ofp == NULL) { | ||
419 | fprintf(stderr, "couldn't open %s\n", fname); | ||
420 | return -1; | ||
421 | } | ||
422 | fprintf(ofp, "# perf trace event handlers, " | ||
423 | "generated by perf trace -g python\n"); | ||
424 | |||
425 | fprintf(ofp, "# Licensed under the terms of the GNU GPL" | ||
426 | " License version 2\n\n"); | ||
427 | |||
428 | fprintf(ofp, "# The common_* event handler fields are the most useful " | ||
429 | "fields common to\n"); | ||
430 | |||
431 | fprintf(ofp, "# all events. They don't necessarily correspond to " | ||
432 | "the 'common_*' fields\n"); | ||
433 | |||
434 | fprintf(ofp, "# in the format files. Those fields not available as " | ||
435 | "handler params can\n"); | ||
436 | |||
437 | fprintf(ofp, "# be retrieved using Python functions of the form " | ||
438 | "common_*(context).\n"); | ||
439 | |||
440 | fprintf(ofp, "# See the perf-trace-python Documentation for the list " | ||
441 | "of available functions.\n\n"); | ||
442 | |||
443 | fprintf(ofp, "import os\n"); | ||
444 | fprintf(ofp, "import sys\n\n"); | ||
} /* identify and execute a 6pack priority command byte */ static void decode_prio_command(struct sixpack *sp, unsigned char cmd) { unsigned char channel; int actual; channel = cmd & SIXP_CHN_MASK; if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */ /* RX and DCD flags can only be set in the same prio command, if the DCD flag has been set without the RX flag in the previous prio command. If DCD has not been set before, something in the transmission has gone wrong. In this case, RX and DCD are cleared in order to prevent the decode_data routine from reading further data that might be corrupt. */ if (((sp->status & SIXP_DCD_MASK) == 0) && ((cmd & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)) { if (sp->status != 1) printk(KERN_DEBUG "6pack: protocol violation\n"); else sp->status = 0; cmd &= !SIXP_RX_DCD_MASK; } sp->status = cmd & SIXP_PRIO_DATA_MASK; } else { /* output watchdog char if idle */ if ((sp->status2 != 0) && (sp->duplex == 1)) { sp->led_state = 0x70; sp->tty->driver->write(sp->tty, &sp->led_state, 1); sp->tx_enable = 1; actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2); sp->xleft -= actual; sp->xhead += actual; sp->led_state = 0x60; sp->status2 = 0; } } /* needed to trigger the TNC watchdog */ sp->tty->driver->write(sp->tty, &sp->led_state, 1); /* if the state byte has been received, the TNC is present, so the resync timer can be reset. */ if (sp->tnc_state == TNC_IN_SYNC) { del_timer(&sp->resync_t); sp->resync_t.data = (unsigned long) sp; sp->resync_t.function = resync_tnc; sp->resync_t.expires = jiffies + SIXP_INIT_RESYNC_TIMEOUT; add_timer(&sp->resync_t); } sp->status1 = cmd & SIXP_PRIO_DATA_MASK; } /* identify and execute a standard 6pack command byte */ static void decode_std_command(struct sixpack *sp, unsigned char cmd) { unsigned char checksum = 0, rest = 0, channel; short i; channel = cmd & SIXP_CHN_MASK; switch (cmd & SIXP_CMD_MASK) { /* normal command */ case SIXP_SEOF: if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) { if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) { sp->led_state = 0x68; sp->tty->driver->write(sp->tty, &sp->led_state, 1); } } else { sp->led_state = 0x60; /* fill trailing bytes with zeroes */ sp->tty->driver->write(sp->tty, &sp->led_state, 1); rest = sp->rx_count; if (rest != 0) for (i = rest; i <= 3; i++) decode_data(sp, 0); if (rest == 2) sp->rx_count_cooked -= 2; else if (rest == 3) sp->rx_count_cooked -= 1; for (i = 0; i < sp->rx_count_cooked; i++) checksum += sp->cooked_buf[i]; if (checksum != SIXP_CHKSUM) { printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum); } else { sp->rcount = sp->rx_count_cooked-2; sp_bump(sp, 0); } sp->rx_count_cooked = 0; } break; case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n"); break; case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n"); break; case SIXP_RX_BUF_OVL: printk(KERN_DEBUG "6pack: RX buffer overflow\n"); } } /* decode a 6pack packet */ static void sixpack_decode(struct sixpack *sp, unsigned char *pre_rbuff, int count) { unsigned char inbyte; int count1; for (count1 = 0; count1 < count; count1++) { inbyte = pre_rbuff[count1]; if (inbyte == SIXP_FOUND_TNC) { tnc_set_sync_state(sp, TNC_IN_SYNC); del_timer(&sp->resync_t); } if ((inbyte & SIXP_PRIO_CMD_MASK) != 0) decode_prio_command(sp, inbyte); else if ((inbyte & SIXP_STD_CMD_MASK) != 0) decode_std_command(sp, inbyte); else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) decode_data(sp, inbyte); } } MODULE_AUTHOR("Ralf Baechle DO1GRB <ralf@linux-mips.org>"); MODULE_DESCRIPTION("6pack driver for AX.25"); MODULE_LICENSE("GPL"); MODULE_ALIAS_LDISC(N_6PACK); module_init(sixpack_init_driver); module_exit(sixpack_exit_driver); |