diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2014-10-23 06:45:14 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2014-10-29 08:32:49 -0400 |
commit | df919b400ad3f9e6aac392ce421d710207abf9be (patch) | |
tree | 0e49286a4bfa90bbe221c787702e4759f3005a90 /tools/perf | |
parent | 0db15b1e84a59e6e1da5fe6e74c35fe52fa29d92 (diff) |
perf scripting python: Extend interface to export data in a database-friendly way
Use the new db_export facility to export data in a database-friendly
way.
A Python script selects the db_export mode by setting a global variable
'perf_db_export_mode' to True. The script then optionally implements
functions to receive table rows. The functions are:
evsel_table
machine_table
thread_table
comm_table
dso_table
symbol_table
sample_table
An example script is provided in a subsequent patch.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1414061124-26830-7-git-send-email-adrian.hunter@intel.com
[ Reserve space for per symbol db_id space when perf_db_export_mode is on ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/util/scripting-engines/trace-event-python.c | 286 |
1 files changed, 284 insertions, 2 deletions
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 25e5a238f1cb..2fd7ee8f18c7 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <stdio.h> | 24 | #include <stdio.h> |
25 | #include <stdlib.h> | 25 | #include <stdlib.h> |
26 | #include <string.h> | 26 | #include <string.h> |
27 | #include <stdbool.h> | ||
27 | #include <errno.h> | 28 | #include <errno.h> |
28 | 29 | ||
29 | #include "../../perf.h" | 30 | #include "../../perf.h" |
@@ -33,6 +34,9 @@ | |||
33 | #include "../util.h" | 34 | #include "../util.h" |
34 | #include "../event.h" | 35 | #include "../event.h" |
35 | #include "../thread.h" | 36 | #include "../thread.h" |
37 | #include "../comm.h" | ||
38 | #include "../machine.h" | ||
39 | #include "../db-export.h" | ||
36 | #include "../trace-event.h" | 40 | #include "../trace-event.h" |
37 | #include "../machine.h" | 41 | #include "../machine.h" |
38 | 42 | ||
@@ -53,6 +57,21 @@ static int zero_flag_atom; | |||
53 | 57 | ||
54 | static PyObject *main_module, *main_dict; | 58 | static PyObject *main_module, *main_dict; |
55 | 59 | ||
60 | struct tables { | ||
61 | struct db_export dbe; | ||
62 | PyObject *evsel_handler; | ||
63 | PyObject *machine_handler; | ||
64 | PyObject *thread_handler; | ||
65 | PyObject *comm_handler; | ||
66 | PyObject *comm_thread_handler; | ||
67 | PyObject *dso_handler; | ||
68 | PyObject *symbol_handler; | ||
69 | PyObject *sample_handler; | ||
70 | bool db_export_mode; | ||
71 | }; | ||
72 | |||
73 | static struct tables tables_global; | ||
74 | |||
56 | static void handler_call_die(const char *handler_name) NORETURN; | 75 | static void handler_call_die(const char *handler_name) NORETURN; |
57 | static void handler_call_die(const char *handler_name) | 76 | static void handler_call_die(const char *handler_name) |
58 | { | 77 | { |
@@ -475,6 +494,211 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
475 | Py_DECREF(t); | 494 | Py_DECREF(t); |
476 | } | 495 | } |
477 | 496 | ||
497 | static PyObject *tuple_new(unsigned int sz) | ||
498 | { | ||
499 | PyObject *t; | ||
500 | |||
501 | t = PyTuple_New(sz); | ||
502 | if (!t) | ||
503 | Py_FatalError("couldn't create Python tuple"); | ||
504 | return t; | ||
505 | } | ||
506 | |||
507 | static int tuple_set_u64(PyObject *t, unsigned int pos, u64 val) | ||
508 | { | ||
509 | #if BITS_PER_LONG == 64 | ||
510 | return PyTuple_SetItem(t, pos, PyInt_FromLong(val)); | ||
511 | #endif | ||
512 | #if BITS_PER_LONG == 32 | ||
513 | return PyTuple_SetItem(t, pos, PyLong_FromLongLong(val)); | ||
514 | #endif | ||
515 | } | ||
516 | |||
517 | static int tuple_set_s32(PyObject *t, unsigned int pos, s32 val) | ||
518 | { | ||
519 | return PyTuple_SetItem(t, pos, PyInt_FromLong(val)); | ||
520 | } | ||
521 | |||
522 | static int tuple_set_string(PyObject *t, unsigned int pos, const char *s) | ||
523 | { | ||
524 | return PyTuple_SetItem(t, pos, PyString_FromString(s)); | ||
525 | } | ||
526 | |||
527 | static int python_export_evsel(struct db_export *dbe, struct perf_evsel *evsel) | ||
528 | { | ||
529 | struct tables *tables = container_of(dbe, struct tables, dbe); | ||
530 | PyObject *t; | ||
531 | |||
532 | t = tuple_new(2); | ||
533 | |||
534 | tuple_set_u64(t, 0, evsel->db_id); | ||
535 | tuple_set_string(t, 1, perf_evsel__name(evsel)); | ||
536 | |||
537 | call_object(tables->evsel_handler, t, "evsel_table"); | ||
538 | |||
539 | Py_DECREF(t); | ||
540 | |||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | static int python_export_machine(struct db_export *dbe, | ||
545 | struct machine *machine) | ||
546 | { | ||
547 | struct tables *tables = container_of(dbe, struct tables, dbe); | ||
548 | PyObject *t; | ||
549 | |||
550 | t = tuple_new(3); | ||
551 | |||
552 | tuple_set_u64(t, 0, machine->db_id); | ||
553 | tuple_set_s32(t, 1, machine->pid); | ||
554 | tuple_set_string(t, 2, machine->root_dir ? machine->root_dir : ""); | ||
555 | |||
556 | call_object(tables->machine_handler, t, "machine_table"); | ||
557 | |||
558 | Py_DECREF(t); | ||
559 | |||
560 | return 0; | ||
561 | } | ||
562 | |||
563 | static int python_export_thread(struct db_export *dbe, struct thread *thread, | ||
564 | u64 main_thread_db_id, struct machine *machine) | ||
565 | { | ||
566 | struct tables *tables = container_of(dbe, struct tables, dbe); | ||
567 | PyObject *t; | ||
568 | |||
569 | t = tuple_new(5); | ||
570 | |||
571 | tuple_set_u64(t, 0, thread->db_id); | ||
572 | tuple_set_u64(t, 1, machine->db_id); | ||
573 | tuple_set_u64(t, 2, main_thread_db_id); | ||
574 | tuple_set_s32(t, 3, thread->pid_); | ||
575 | tuple_set_s32(t, 4, thread->tid); | ||
576 | |||
577 | call_object(tables->thread_handler, t, "thread_table"); | ||
578 | |||
579 | Py_DECREF(t); | ||
580 | |||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | static int python_export_comm(struct db_export *dbe, struct comm *comm) | ||
585 | { | ||
586 | struct tables *tables = container_of(dbe, struct tables, dbe); | ||
587 | PyObject *t; | ||
588 | |||
589 | t = tuple_new(2); | ||
590 | |||
591 | tuple_set_u64(t, 0, comm->db_id); | ||
592 | tuple_set_string(t, 1, comm__str(comm)); | ||
593 | |||
594 | call_object(tables->comm_handler, t, "comm_table"); | ||
595 | |||
596 | Py_DECREF(t); | ||
597 | |||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | static int python_export_comm_thread(struct db_export *dbe, u64 db_id, | ||
602 | struct comm *comm, struct thread *thread) | ||
603 | { | ||
604 | struct tables *tables = container_of(dbe, struct tables, dbe); | ||
605 | PyObject *t; | ||
606 | |||
607 | t = tuple_new(3); | ||
608 | |||
609 | tuple_set_u64(t, 0, db_id); | ||
610 | tuple_set_u64(t, 1, comm->db_id); | ||
611 | tuple_set_u64(t, 2, thread->db_id); | ||
612 | |||
613 | call_object(tables->comm_thread_handler, t, "comm_thread_table"); | ||
614 | |||
615 | Py_DECREF(t); | ||
616 | |||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | static int python_export_dso(struct db_export *dbe, struct dso *dso, | ||
621 | struct machine *machine) | ||
622 | { | ||
623 | struct tables *tables = container_of(dbe, struct tables, dbe); | ||
624 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | ||
625 | PyObject *t; | ||
626 | |||
627 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | ||
628 | |||
629 | t = tuple_new(5); | ||
630 | |||
631 | tuple_set_u64(t, 0, dso->db_id); | ||
632 | tuple_set_u64(t, 1, machine->db_id); | ||
633 | tuple_set_string(t, 2, dso->short_name); | ||
634 | tuple_set_string(t, 3, dso->long_name); | ||
635 | tuple_set_string(t, 4, sbuild_id); | ||
636 | |||
637 | call_object(tables->dso_handler, t, "dso_table"); | ||
638 | |||
639 | Py_DECREF(t); | ||
640 | |||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static int python_export_symbol(struct db_export *dbe, struct symbol *sym, | ||
645 | struct dso *dso) | ||
646 | { | ||
647 | struct tables *tables = container_of(dbe, struct tables, dbe); | ||
648 | u64 *sym_db_id = symbol__priv(sym); | ||
649 | PyObject *t; | ||
650 | |||
651 | t = tuple_new(6); | ||
652 | |||
653 | tuple_set_u64(t, 0, *sym_db_id); | ||
654 | tuple_set_u64(t, 1, dso->db_id); | ||
655 | tuple_set_u64(t, 2, sym->start); | ||
656 | tuple_set_u64(t, 3, sym->end); | ||
657 | tuple_set_s32(t, 4, sym->binding); | ||
658 | tuple_set_string(t, 5, sym->name); | ||
659 | |||
660 | call_object(tables->symbol_handler, t, "symbol_table"); | ||
661 | |||
662 | Py_DECREF(t); | ||
663 | |||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static int python_export_sample(struct db_export *dbe, | ||
668 | struct export_sample *es) | ||
669 | { | ||
670 | struct tables *tables = container_of(dbe, struct tables, dbe); | ||
671 | PyObject *t; | ||
672 | |||
673 | t = tuple_new(19); | ||
674 | |||
675 | tuple_set_u64(t, 0, es->db_id); | ||
676 | tuple_set_u64(t, 1, es->evsel->db_id); | ||
677 | tuple_set_u64(t, 2, es->al->machine->db_id); | ||
678 | tuple_set_u64(t, 3, es->thread->db_id); | ||
679 | tuple_set_u64(t, 4, es->comm_db_id); | ||
680 | tuple_set_u64(t, 5, es->dso_db_id); | ||
681 | tuple_set_u64(t, 6, es->sym_db_id); | ||
682 | tuple_set_u64(t, 7, es->offset); | ||
683 | tuple_set_u64(t, 8, es->sample->ip); | ||
684 | tuple_set_u64(t, 9, es->sample->time); | ||
685 | tuple_set_s32(t, 10, es->sample->cpu); | ||
686 | tuple_set_u64(t, 11, es->addr_dso_db_id); | ||
687 | tuple_set_u64(t, 12, es->addr_sym_db_id); | ||
688 | tuple_set_u64(t, 13, es->addr_offset); | ||
689 | tuple_set_u64(t, 14, es->sample->addr); | ||
690 | tuple_set_u64(t, 15, es->sample->period); | ||
691 | tuple_set_u64(t, 16, es->sample->weight); | ||
692 | tuple_set_u64(t, 17, es->sample->transaction); | ||
693 | tuple_set_u64(t, 18, es->sample->data_src); | ||
694 | |||
695 | call_object(tables->sample_handler, t, "sample_table"); | ||
696 | |||
697 | Py_DECREF(t); | ||
698 | |||
699 | return 0; | ||
700 | } | ||
701 | |||
478 | static void python_process_general_event(struct perf_sample *sample, | 702 | static void python_process_general_event(struct perf_sample *sample, |
479 | struct perf_evsel *evsel, | 703 | struct perf_evsel *evsel, |
480 | struct thread *thread, | 704 | struct thread *thread, |
@@ -551,19 +775,25 @@ exit: | |||
551 | Py_DECREF(t); | 775 | Py_DECREF(t); |
552 | } | 776 | } |
553 | 777 | ||
554 | static void python_process_event(union perf_event *event __maybe_unused, | 778 | static void python_process_event(union perf_event *event, |
555 | struct perf_sample *sample, | 779 | struct perf_sample *sample, |
556 | struct perf_evsel *evsel, | 780 | struct perf_evsel *evsel, |
557 | struct thread *thread, | 781 | struct thread *thread, |
558 | struct addr_location *al) | 782 | struct addr_location *al) |
559 | { | 783 | { |
784 | struct tables *tables = &tables_global; | ||
785 | |||
560 | switch (evsel->attr.type) { | 786 | switch (evsel->attr.type) { |
561 | case PERF_TYPE_TRACEPOINT: | 787 | case PERF_TYPE_TRACEPOINT: |
562 | python_process_tracepoint(sample, evsel, thread, al); | 788 | python_process_tracepoint(sample, evsel, thread, al); |
563 | break; | 789 | break; |
564 | /* Reserve for future process_hw/sw/raw APIs */ | 790 | /* Reserve for future process_hw/sw/raw APIs */ |
565 | default: | 791 | default: |
566 | python_process_general_event(sample, evsel, thread, al); | 792 | if (tables->db_export_mode) |
793 | db_export__sample(&tables->dbe, event, sample, evsel, | ||
794 | thread, al); | ||
795 | else | ||
796 | python_process_general_event(sample, evsel, thread, al); | ||
567 | } | 797 | } |
568 | } | 798 | } |
569 | 799 | ||
@@ -589,11 +819,57 @@ error: | |||
589 | return -1; | 819 | return -1; |
590 | } | 820 | } |
591 | 821 | ||
822 | #define SET_TABLE_HANDLER_(name, handler_name, table_name) do { \ | ||
823 | tables->handler_name = get_handler(#table_name); \ | ||
824 | if (tables->handler_name) \ | ||
825 | tables->dbe.export_ ## name = python_export_ ## name; \ | ||
826 | } while (0) | ||
827 | |||
828 | #define SET_TABLE_HANDLER(name) \ | ||
829 | SET_TABLE_HANDLER_(name, name ## _handler, name ## _table) | ||
830 | |||
831 | static void set_table_handlers(struct tables *tables) | ||
832 | { | ||
833 | const char *perf_db_export_mode = "perf_db_export_mode"; | ||
834 | PyObject *db_export_mode; | ||
835 | int ret; | ||
836 | |||
837 | memset(tables, 0, sizeof(struct tables)); | ||
838 | if (db_export__init(&tables->dbe)) | ||
839 | Py_FatalError("failed to initialize export"); | ||
840 | |||
841 | db_export_mode = PyDict_GetItemString(main_dict, perf_db_export_mode); | ||
842 | if (!db_export_mode) | ||
843 | return; | ||
844 | |||
845 | ret = PyObject_IsTrue(db_export_mode); | ||
846 | if (ret == -1) | ||
847 | handler_call_die(perf_db_export_mode); | ||
848 | if (!ret) | ||
849 | return; | ||
850 | |||
851 | tables->db_export_mode = true; | ||
852 | /* | ||
853 | * Reserve per symbol space for symbol->db_id via symbol__priv() | ||
854 | */ | ||
855 | symbol_conf.priv_size = sizeof(u64); | ||
856 | |||
857 | SET_TABLE_HANDLER(evsel); | ||
858 | SET_TABLE_HANDLER(machine); | ||
859 | SET_TABLE_HANDLER(thread); | ||
860 | SET_TABLE_HANDLER(comm); | ||
861 | SET_TABLE_HANDLER(comm_thread); | ||
862 | SET_TABLE_HANDLER(dso); | ||
863 | SET_TABLE_HANDLER(symbol); | ||
864 | SET_TABLE_HANDLER(sample); | ||
865 | } | ||
866 | |||
592 | /* | 867 | /* |
593 | * Start trace script | 868 | * Start trace script |
594 | */ | 869 | */ |
595 | static int python_start_script(const char *script, int argc, const char **argv) | 870 | static int python_start_script(const char *script, int argc, const char **argv) |
596 | { | 871 | { |
872 | struct tables *tables = &tables_global; | ||
597 | const char **command_line; | 873 | const char **command_line; |
598 | char buf[PATH_MAX]; | 874 | char buf[PATH_MAX]; |
599 | int i, err = 0; | 875 | int i, err = 0; |
@@ -632,6 +908,8 @@ static int python_start_script(const char *script, int argc, const char **argv) | |||
632 | 908 | ||
633 | free(command_line); | 909 | free(command_line); |
634 | 910 | ||
911 | set_table_handlers(tables); | ||
912 | |||
635 | return err; | 913 | return err; |
636 | error: | 914 | error: |
637 | Py_Finalize(); | 915 | Py_Finalize(); |
@@ -650,8 +928,12 @@ static int python_flush_script(void) | |||
650 | */ | 928 | */ |
651 | static int python_stop_script(void) | 929 | static int python_stop_script(void) |
652 | { | 930 | { |
931 | struct tables *tables = &tables_global; | ||
932 | |||
653 | try_call_object("trace_end", NULL); | 933 | try_call_object("trace_end", NULL); |
654 | 934 | ||
935 | db_export__exit(&tables->dbe); | ||
936 | |||
655 | Py_XDECREF(main_dict); | 937 | Py_XDECREF(main_dict); |
656 | Py_XDECREF(main_module); | 938 | Py_XDECREF(main_module); |
657 | Py_Finalize(); | 939 | Py_Finalize(); |