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 | 246 |
1 files changed, 184 insertions, 62 deletions
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 57b7a00e6f16..c7187f067d31 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -116,6 +116,34 @@ static PyObject *get_handler(const char *handler_name) | |||
116 | return handler; | 116 | return handler; |
117 | } | 117 | } |
118 | 118 | ||
119 | static int get_argument_count(PyObject *handler) | ||
120 | { | ||
121 | int arg_count = 0; | ||
122 | |||
123 | /* | ||
124 | * The attribute for the code object is func_code in Python 2, | ||
125 | * whereas it is __code__ in Python 3.0+. | ||
126 | */ | ||
127 | PyObject *code_obj = PyObject_GetAttrString(handler, | ||
128 | "func_code"); | ||
129 | if (PyErr_Occurred()) { | ||
130 | PyErr_Clear(); | ||
131 | code_obj = PyObject_GetAttrString(handler, | ||
132 | "__code__"); | ||
133 | } | ||
134 | PyErr_Clear(); | ||
135 | if (code_obj) { | ||
136 | PyObject *arg_count_obj = PyObject_GetAttrString(code_obj, | ||
137 | "co_argcount"); | ||
138 | if (arg_count_obj) { | ||
139 | arg_count = (int) PyInt_AsLong(arg_count_obj); | ||
140 | Py_DECREF(arg_count_obj); | ||
141 | } | ||
142 | Py_DECREF(code_obj); | ||
143 | } | ||
144 | return arg_count; | ||
145 | } | ||
146 | |||
119 | static void call_object(PyObject *handler, PyObject *args, const char *die_msg) | 147 | static void call_object(PyObject *handler, PyObject *args, const char *die_msg) |
120 | { | 148 | { |
121 | PyObject *retval; | 149 | PyObject *retval; |
@@ -391,13 +419,115 @@ exit: | |||
391 | return pylist; | 419 | return pylist; |
392 | } | 420 | } |
393 | 421 | ||
422 | static PyObject *get_sample_value_as_tuple(struct sample_read_value *value) | ||
423 | { | ||
424 | PyObject *t; | ||
425 | |||
426 | t = PyTuple_New(2); | ||
427 | if (!t) | ||
428 | Py_FatalError("couldn't create Python tuple"); | ||
429 | PyTuple_SetItem(t, 0, PyLong_FromUnsignedLongLong(value->id)); | ||
430 | PyTuple_SetItem(t, 1, PyLong_FromUnsignedLongLong(value->value)); | ||
431 | return t; | ||
432 | } | ||
433 | |||
434 | static void set_sample_read_in_dict(PyObject *dict_sample, | ||
435 | struct perf_sample *sample, | ||
436 | struct perf_evsel *evsel) | ||
437 | { | ||
438 | u64 read_format = evsel->attr.read_format; | ||
439 | PyObject *values; | ||
440 | unsigned int i; | ||
441 | |||
442 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { | ||
443 | pydict_set_item_string_decref(dict_sample, "time_enabled", | ||
444 | PyLong_FromUnsignedLongLong(sample->read.time_enabled)); | ||
445 | } | ||
446 | |||
447 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { | ||
448 | pydict_set_item_string_decref(dict_sample, "time_running", | ||
449 | PyLong_FromUnsignedLongLong(sample->read.time_running)); | ||
450 | } | ||
451 | |||
452 | if (read_format & PERF_FORMAT_GROUP) | ||
453 | values = PyList_New(sample->read.group.nr); | ||
454 | else | ||
455 | values = PyList_New(1); | ||
456 | |||
457 | if (!values) | ||
458 | Py_FatalError("couldn't create Python list"); | ||
459 | |||
460 | if (read_format & PERF_FORMAT_GROUP) { | ||
461 | for (i = 0; i < sample->read.group.nr; i++) { | ||
462 | PyObject *t = get_sample_value_as_tuple(&sample->read.group.values[i]); | ||
463 | PyList_SET_ITEM(values, i, t); | ||
464 | } | ||
465 | } else { | ||
466 | PyObject *t = get_sample_value_as_tuple(&sample->read.one); | ||
467 | PyList_SET_ITEM(values, 0, t); | ||
468 | } | ||
469 | pydict_set_item_string_decref(dict_sample, "values", values); | ||
470 | } | ||
471 | |||
472 | static PyObject *get_perf_sample_dict(struct perf_sample *sample, | ||
473 | struct perf_evsel *evsel, | ||
474 | struct addr_location *al, | ||
475 | PyObject *callchain) | ||
476 | { | ||
477 | PyObject *dict, *dict_sample; | ||
478 | |||
479 | dict = PyDict_New(); | ||
480 | if (!dict) | ||
481 | Py_FatalError("couldn't create Python dictionary"); | ||
482 | |||
483 | dict_sample = PyDict_New(); | ||
484 | if (!dict_sample) | ||
485 | Py_FatalError("couldn't create Python dictionary"); | ||
486 | |||
487 | pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); | ||
488 | pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize( | ||
489 | (const char *)&evsel->attr, sizeof(evsel->attr))); | ||
490 | |||
491 | pydict_set_item_string_decref(dict_sample, "pid", | ||
492 | PyInt_FromLong(sample->pid)); | ||
493 | pydict_set_item_string_decref(dict_sample, "tid", | ||
494 | PyInt_FromLong(sample->tid)); | ||
495 | pydict_set_item_string_decref(dict_sample, "cpu", | ||
496 | PyInt_FromLong(sample->cpu)); | ||
497 | pydict_set_item_string_decref(dict_sample, "ip", | ||
498 | PyLong_FromUnsignedLongLong(sample->ip)); | ||
499 | pydict_set_item_string_decref(dict_sample, "time", | ||
500 | PyLong_FromUnsignedLongLong(sample->time)); | ||
501 | pydict_set_item_string_decref(dict_sample, "period", | ||
502 | PyLong_FromUnsignedLongLong(sample->period)); | ||
503 | set_sample_read_in_dict(dict_sample, sample, evsel); | ||
504 | pydict_set_item_string_decref(dict, "sample", dict_sample); | ||
505 | |||
506 | pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( | ||
507 | (const char *)sample->raw_data, sample->raw_size)); | ||
508 | pydict_set_item_string_decref(dict, "comm", | ||
509 | PyString_FromString(thread__comm_str(al->thread))); | ||
510 | if (al->map) { | ||
511 | pydict_set_item_string_decref(dict, "dso", | ||
512 | PyString_FromString(al->map->dso->name)); | ||
513 | } | ||
514 | if (al->sym) { | ||
515 | pydict_set_item_string_decref(dict, "symbol", | ||
516 | PyString_FromString(al->sym->name)); | ||
517 | } | ||
518 | |||
519 | pydict_set_item_string_decref(dict, "callchain", callchain); | ||
520 | |||
521 | return dict; | ||
522 | } | ||
523 | |||
394 | static void python_process_tracepoint(struct perf_sample *sample, | 524 | static void python_process_tracepoint(struct perf_sample *sample, |
395 | struct perf_evsel *evsel, | 525 | struct perf_evsel *evsel, |
396 | struct addr_location *al) | 526 | struct addr_location *al) |
397 | { | 527 | { |
398 | struct event_format *event = evsel->tp_format; | 528 | struct event_format *event = evsel->tp_format; |
399 | PyObject *handler, *context, *t, *obj = NULL, *callchain; | 529 | PyObject *handler, *context, *t, *obj = NULL, *callchain; |
400 | PyObject *dict = NULL; | 530 | PyObject *dict = NULL, *all_entries_dict = NULL; |
401 | static char handler_name[256]; | 531 | static char handler_name[256]; |
402 | struct format_field *field; | 532 | struct format_field *field; |
403 | unsigned long s, ns; | 533 | unsigned long s, ns; |
@@ -407,10 +537,7 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
407 | void *data = sample->raw_data; | 537 | void *data = sample->raw_data; |
408 | unsigned long long nsecs = sample->time; | 538 | unsigned long long nsecs = sample->time; |
409 | const char *comm = thread__comm_str(al->thread); | 539 | const char *comm = thread__comm_str(al->thread); |
410 | 540 | const char *default_handler_name = "trace_unhandled"; | |
411 | t = PyTuple_New(MAX_FIELDS); | ||
412 | if (!t) | ||
413 | Py_FatalError("couldn't create Python tuple"); | ||
414 | 541 | ||
415 | if (!event) { | 542 | if (!event) { |
416 | snprintf(handler_name, sizeof(handler_name), | 543 | snprintf(handler_name, sizeof(handler_name), |
@@ -427,10 +554,19 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
427 | 554 | ||
428 | handler = get_handler(handler_name); | 555 | handler = get_handler(handler_name); |
429 | if (!handler) { | 556 | if (!handler) { |
557 | handler = get_handler(default_handler_name); | ||
558 | if (!handler) | ||
559 | return; | ||
430 | dict = PyDict_New(); | 560 | dict = PyDict_New(); |
431 | if (!dict) | 561 | if (!dict) |
432 | Py_FatalError("couldn't create Python dict"); | 562 | Py_FatalError("couldn't create Python dict"); |
433 | } | 563 | } |
564 | |||
565 | t = PyTuple_New(MAX_FIELDS); | ||
566 | if (!t) | ||
567 | Py_FatalError("couldn't create Python tuple"); | ||
568 | |||
569 | |||
434 | s = nsecs / NSEC_PER_SEC; | 570 | s = nsecs / NSEC_PER_SEC; |
435 | ns = nsecs - s * NSEC_PER_SEC; | 571 | ns = nsecs - s * NSEC_PER_SEC; |
436 | 572 | ||
@@ -444,8 +580,10 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
444 | 580 | ||
445 | /* ip unwinding */ | 581 | /* ip unwinding */ |
446 | callchain = python_process_callchain(sample, evsel, al); | 582 | callchain = python_process_callchain(sample, evsel, al); |
583 | /* Need an additional reference for the perf_sample dict */ | ||
584 | Py_INCREF(callchain); | ||
447 | 585 | ||
448 | if (handler) { | 586 | if (!dict) { |
449 | PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); | 587 | PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); |
450 | PyTuple_SetItem(t, n++, PyInt_FromLong(s)); | 588 | PyTuple_SetItem(t, n++, PyInt_FromLong(s)); |
451 | PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); | 589 | PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); |
@@ -484,26 +622,35 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
484 | } else { /* FIELD_IS_NUMERIC */ | 622 | } else { /* FIELD_IS_NUMERIC */ |
485 | obj = get_field_numeric_entry(event, field, data); | 623 | obj = get_field_numeric_entry(event, field, data); |
486 | } | 624 | } |
487 | if (handler) | 625 | if (!dict) |
488 | PyTuple_SetItem(t, n++, obj); | 626 | PyTuple_SetItem(t, n++, obj); |
489 | else | 627 | else |
490 | pydict_set_item_string_decref(dict, field->name, obj); | 628 | pydict_set_item_string_decref(dict, field->name, obj); |
491 | 629 | ||
492 | } | 630 | } |
493 | 631 | ||
494 | if (!handler) | 632 | if (dict) |
495 | PyTuple_SetItem(t, n++, dict); | 633 | PyTuple_SetItem(t, n++, dict); |
496 | 634 | ||
635 | if (get_argument_count(handler) == (int) n + 1) { | ||
636 | all_entries_dict = get_perf_sample_dict(sample, evsel, al, | ||
637 | callchain); | ||
638 | PyTuple_SetItem(t, n++, all_entries_dict); | ||
639 | } else { | ||
640 | Py_DECREF(callchain); | ||
641 | } | ||
642 | |||
497 | if (_PyTuple_Resize(&t, n) == -1) | 643 | if (_PyTuple_Resize(&t, n) == -1) |
498 | Py_FatalError("error resizing Python tuple"); | 644 | Py_FatalError("error resizing Python tuple"); |
499 | 645 | ||
500 | if (handler) { | 646 | if (!dict) { |
501 | call_object(handler, t, handler_name); | 647 | call_object(handler, t, handler_name); |
502 | } else { | 648 | } else { |
503 | try_call_object("trace_unhandled", t); | 649 | call_object(handler, t, default_handler_name); |
504 | Py_DECREF(dict); | 650 | Py_DECREF(dict); |
505 | } | 651 | } |
506 | 652 | ||
653 | Py_XDECREF(all_entries_dict); | ||
507 | Py_DECREF(t); | 654 | Py_DECREF(t); |
508 | } | 655 | } |
509 | 656 | ||
@@ -795,10 +942,16 @@ static void python_process_general_event(struct perf_sample *sample, | |||
795 | struct perf_evsel *evsel, | 942 | struct perf_evsel *evsel, |
796 | struct addr_location *al) | 943 | struct addr_location *al) |
797 | { | 944 | { |
798 | PyObject *handler, *t, *dict, *callchain, *dict_sample; | 945 | PyObject *handler, *t, *dict, *callchain; |
799 | static char handler_name[64]; | 946 | static char handler_name[64]; |
800 | unsigned n = 0; | 947 | unsigned n = 0; |
801 | 948 | ||
949 | snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); | ||
950 | |||
951 | handler = get_handler(handler_name); | ||
952 | if (!handler) | ||
953 | return; | ||
954 | |||
802 | /* | 955 | /* |
803 | * Use the MAX_FIELDS to make the function expandable, though | 956 | * Use the MAX_FIELDS to make the function expandable, though |
804 | * currently there is only one item for the tuple. | 957 | * currently there is only one item for the tuple. |
@@ -807,61 +960,16 @@ static void python_process_general_event(struct perf_sample *sample, | |||
807 | if (!t) | 960 | if (!t) |
808 | Py_FatalError("couldn't create Python tuple"); | 961 | Py_FatalError("couldn't create Python tuple"); |
809 | 962 | ||
810 | dict = PyDict_New(); | ||
811 | if (!dict) | ||
812 | Py_FatalError("couldn't create Python dictionary"); | ||
813 | |||
814 | dict_sample = PyDict_New(); | ||
815 | if (!dict_sample) | ||
816 | Py_FatalError("couldn't create Python dictionary"); | ||
817 | |||
818 | snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); | ||
819 | |||
820 | handler = get_handler(handler_name); | ||
821 | if (!handler) | ||
822 | goto exit; | ||
823 | |||
824 | pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); | ||
825 | pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize( | ||
826 | (const char *)&evsel->attr, sizeof(evsel->attr))); | ||
827 | |||
828 | pydict_set_item_string_decref(dict_sample, "pid", | ||
829 | PyInt_FromLong(sample->pid)); | ||
830 | pydict_set_item_string_decref(dict_sample, "tid", | ||
831 | PyInt_FromLong(sample->tid)); | ||
832 | pydict_set_item_string_decref(dict_sample, "cpu", | ||
833 | PyInt_FromLong(sample->cpu)); | ||
834 | pydict_set_item_string_decref(dict_sample, "ip", | ||
835 | PyLong_FromUnsignedLongLong(sample->ip)); | ||
836 | pydict_set_item_string_decref(dict_sample, "time", | ||
837 | PyLong_FromUnsignedLongLong(sample->time)); | ||
838 | pydict_set_item_string_decref(dict_sample, "period", | ||
839 | PyLong_FromUnsignedLongLong(sample->period)); | ||
840 | pydict_set_item_string_decref(dict, "sample", dict_sample); | ||
841 | |||
842 | pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( | ||
843 | (const char *)sample->raw_data, sample->raw_size)); | ||
844 | pydict_set_item_string_decref(dict, "comm", | ||
845 | PyString_FromString(thread__comm_str(al->thread))); | ||
846 | if (al->map) { | ||
847 | pydict_set_item_string_decref(dict, "dso", | ||
848 | PyString_FromString(al->map->dso->name)); | ||
849 | } | ||
850 | if (al->sym) { | ||
851 | pydict_set_item_string_decref(dict, "symbol", | ||
852 | PyString_FromString(al->sym->name)); | ||
853 | } | ||
854 | |||
855 | /* ip unwinding */ | 963 | /* ip unwinding */ |
856 | callchain = python_process_callchain(sample, evsel, al); | 964 | callchain = python_process_callchain(sample, evsel, al); |
857 | pydict_set_item_string_decref(dict, "callchain", callchain); | 965 | dict = get_perf_sample_dict(sample, evsel, al, callchain); |
858 | 966 | ||
859 | PyTuple_SetItem(t, n++, dict); | 967 | PyTuple_SetItem(t, n++, dict); |
860 | if (_PyTuple_Resize(&t, n) == -1) | 968 | if (_PyTuple_Resize(&t, n) == -1) |
861 | Py_FatalError("error resizing Python tuple"); | 969 | Py_FatalError("error resizing Python tuple"); |
862 | 970 | ||
863 | call_object(handler, t, handler_name); | 971 | call_object(handler, t, handler_name); |
864 | exit: | 972 | |
865 | Py_DECREF(dict); | 973 | Py_DECREF(dict); |
866 | Py_DECREF(t); | 974 | Py_DECREF(t); |
867 | } | 975 | } |
@@ -1259,6 +1367,12 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) | |||
1259 | 1367 | ||
1260 | fprintf(ofp, "%s", f->name); | 1368 | fprintf(ofp, "%s", f->name); |
1261 | } | 1369 | } |
1370 | if (not_first++) | ||
1371 | fprintf(ofp, ", "); | ||
1372 | if (++count % 5 == 0) | ||
1373 | fprintf(ofp, "\n\t\t"); | ||
1374 | fprintf(ofp, "perf_sample_dict"); | ||
1375 | |||
1262 | fprintf(ofp, "):\n"); | 1376 | fprintf(ofp, "):\n"); |
1263 | 1377 | ||
1264 | fprintf(ofp, "\t\tprint_header(event_name, common_cpu, " | 1378 | fprintf(ofp, "\t\tprint_header(event_name, common_cpu, " |
@@ -1328,6 +1442,9 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) | |||
1328 | 1442 | ||
1329 | fprintf(ofp, ")\n\n"); | 1443 | fprintf(ofp, ")\n\n"); |
1330 | 1444 | ||
1445 | fprintf(ofp, "\t\tprint 'Sample: {'+" | ||
1446 | "get_dict_as_string(perf_sample_dict['sample'], ', ')+'}'\n\n"); | ||
1447 | |||
1331 | fprintf(ofp, "\t\tfor node in common_callchain:"); | 1448 | fprintf(ofp, "\t\tfor node in common_callchain:"); |
1332 | fprintf(ofp, "\n\t\t\tif 'sym' in node:"); | 1449 | fprintf(ofp, "\n\t\t\tif 'sym' in node:"); |
1333 | fprintf(ofp, "\n\t\t\t\tprint \"\\t[%%x] %%s\" %% (node['ip'], node['sym']['name'])"); | 1450 | fprintf(ofp, "\n\t\t\t\tprint \"\\t[%%x] %%s\" %% (node['ip'], node['sym']['name'])"); |
@@ -1338,15 +1455,20 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) | |||
1338 | } | 1455 | } |
1339 | 1456 | ||
1340 | fprintf(ofp, "def trace_unhandled(event_name, context, " | 1457 | fprintf(ofp, "def trace_unhandled(event_name, context, " |
1341 | "event_fields_dict):\n"); | 1458 | "event_fields_dict, perf_sample_dict):\n"); |
1342 | 1459 | ||
1343 | fprintf(ofp, "\t\tprint ' '.join(['%%s=%%s'%%(k,str(v))" | 1460 | fprintf(ofp, "\t\tprint get_dict_as_string(event_fields_dict)\n"); |
1344 | "for k,v in sorted(event_fields_dict.items())])\n\n"); | 1461 | fprintf(ofp, "\t\tprint 'Sample: {'+" |
1462 | "get_dict_as_string(perf_sample_dict['sample'], ', ')+'}'\n\n"); | ||
1345 | 1463 | ||
1346 | fprintf(ofp, "def print_header(" | 1464 | fprintf(ofp, "def print_header(" |
1347 | "event_name, cpu, secs, nsecs, pid, comm):\n" | 1465 | "event_name, cpu, secs, nsecs, pid, comm):\n" |
1348 | "\tprint \"%%-20s %%5u %%05u.%%09u %%8u %%-20s \" %% \\\n\t" | 1466 | "\tprint \"%%-20s %%5u %%05u.%%09u %%8u %%-20s \" %% \\\n\t" |
1349 | "(event_name, cpu, secs, nsecs, pid, comm),\n"); | 1467 | "(event_name, cpu, secs, nsecs, pid, comm),\n\n"); |
1468 | |||
1469 | fprintf(ofp, "def get_dict_as_string(a_dict, delimiter=' '):\n" | ||
1470 | "\treturn delimiter.join" | ||
1471 | "(['%%s=%%s'%%(k,str(v))for k,v in sorted(a_dict.items())])\n"); | ||
1350 | 1472 | ||
1351 | fclose(ofp); | 1473 | fclose(ofp); |
1352 | 1474 | ||