diff options
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(); |
