Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Adrian Hunter and committed by
Arnaldo Carvalho de Melo
df919b40 0db15b1e

+284 -2
+284 -2
tools/perf/util/scripting-engines/trace-event-python.c
··· 24 24 #include <stdio.h> 25 25 #include <stdlib.h> 26 26 #include <string.h> 27 + #include <stdbool.h> 27 28 #include <errno.h> 28 29 29 30 #include "../../perf.h" ··· 34 33 #include "../util.h" 35 34 #include "../event.h" 36 35 #include "../thread.h" 36 + #include "../comm.h" 37 + #include "../machine.h" 38 + #include "../db-export.h" 37 39 #include "../trace-event.h" 38 40 #include "../machine.h" 39 41 ··· 56 52 static int zero_flag_atom; 57 53 58 54 static PyObject *main_module, *main_dict; 55 + 56 + struct tables { 57 + struct db_export dbe; 58 + PyObject *evsel_handler; 59 + PyObject *machine_handler; 60 + PyObject *thread_handler; 61 + PyObject *comm_handler; 62 + PyObject *comm_thread_handler; 63 + PyObject *dso_handler; 64 + PyObject *symbol_handler; 65 + PyObject *sample_handler; 66 + bool db_export_mode; 67 + }; 68 + 69 + static struct tables tables_global; 59 70 60 71 static void handler_call_die(const char *handler_name) NORETURN; 61 72 static void handler_call_die(const char *handler_name) ··· 494 475 Py_DECREF(t); 495 476 } 496 477 478 + static PyObject *tuple_new(unsigned int sz) 479 + { 480 + PyObject *t; 481 + 482 + t = PyTuple_New(sz); 483 + if (!t) 484 + Py_FatalError("couldn't create Python tuple"); 485 + return t; 486 + } 487 + 488 + static int tuple_set_u64(PyObject *t, unsigned int pos, u64 val) 489 + { 490 + #if BITS_PER_LONG == 64 491 + return PyTuple_SetItem(t, pos, PyInt_FromLong(val)); 492 + #endif 493 + #if BITS_PER_LONG == 32 494 + return PyTuple_SetItem(t, pos, PyLong_FromLongLong(val)); 495 + #endif 496 + } 497 + 498 + static int tuple_set_s32(PyObject *t, unsigned int pos, s32 val) 499 + { 500 + return PyTuple_SetItem(t, pos, PyInt_FromLong(val)); 501 + } 502 + 503 + static int tuple_set_string(PyObject *t, unsigned int pos, const char *s) 504 + { 505 + return PyTuple_SetItem(t, pos, PyString_FromString(s)); 506 + } 507 + 508 + static int python_export_evsel(struct db_export *dbe, struct perf_evsel *evsel) 509 + { 510 + struct tables *tables = container_of(dbe, struct tables, dbe); 511 + PyObject *t; 512 + 513 + t = tuple_new(2); 514 + 515 + tuple_set_u64(t, 0, evsel->db_id); 516 + tuple_set_string(t, 1, perf_evsel__name(evsel)); 517 + 518 + call_object(tables->evsel_handler, t, "evsel_table"); 519 + 520 + Py_DECREF(t); 521 + 522 + return 0; 523 + } 524 + 525 + static int python_export_machine(struct db_export *dbe, 526 + struct machine *machine) 527 + { 528 + struct tables *tables = container_of(dbe, struct tables, dbe); 529 + PyObject *t; 530 + 531 + t = tuple_new(3); 532 + 533 + tuple_set_u64(t, 0, machine->db_id); 534 + tuple_set_s32(t, 1, machine->pid); 535 + tuple_set_string(t, 2, machine->root_dir ? machine->root_dir : ""); 536 + 537 + call_object(tables->machine_handler, t, "machine_table"); 538 + 539 + Py_DECREF(t); 540 + 541 + return 0; 542 + } 543 + 544 + static int python_export_thread(struct db_export *dbe, struct thread *thread, 545 + u64 main_thread_db_id, struct machine *machine) 546 + { 547 + struct tables *tables = container_of(dbe, struct tables, dbe); 548 + PyObject *t; 549 + 550 + t = tuple_new(5); 551 + 552 + tuple_set_u64(t, 0, thread->db_id); 553 + tuple_set_u64(t, 1, machine->db_id); 554 + tuple_set_u64(t, 2, main_thread_db_id); 555 + tuple_set_s32(t, 3, thread->pid_); 556 + tuple_set_s32(t, 4, thread->tid); 557 + 558 + call_object(tables->thread_handler, t, "thread_table"); 559 + 560 + Py_DECREF(t); 561 + 562 + return 0; 563 + } 564 + 565 + static int python_export_comm(struct db_export *dbe, struct comm *comm) 566 + { 567 + struct tables *tables = container_of(dbe, struct tables, dbe); 568 + PyObject *t; 569 + 570 + t = tuple_new(2); 571 + 572 + tuple_set_u64(t, 0, comm->db_id); 573 + tuple_set_string(t, 1, comm__str(comm)); 574 + 575 + call_object(tables->comm_handler, t, "comm_table"); 576 + 577 + Py_DECREF(t); 578 + 579 + return 0; 580 + } 581 + 582 + static int python_export_comm_thread(struct db_export *dbe, u64 db_id, 583 + struct comm *comm, struct thread *thread) 584 + { 585 + struct tables *tables = container_of(dbe, struct tables, dbe); 586 + PyObject *t; 587 + 588 + t = tuple_new(3); 589 + 590 + tuple_set_u64(t, 0, db_id); 591 + tuple_set_u64(t, 1, comm->db_id); 592 + tuple_set_u64(t, 2, thread->db_id); 593 + 594 + call_object(tables->comm_thread_handler, t, "comm_thread_table"); 595 + 596 + Py_DECREF(t); 597 + 598 + return 0; 599 + } 600 + 601 + static int python_export_dso(struct db_export *dbe, struct dso *dso, 602 + struct machine *machine) 603 + { 604 + struct tables *tables = container_of(dbe, struct tables, dbe); 605 + char sbuild_id[BUILD_ID_SIZE * 2 + 1]; 606 + PyObject *t; 607 + 608 + build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); 609 + 610 + t = tuple_new(5); 611 + 612 + tuple_set_u64(t, 0, dso->db_id); 613 + tuple_set_u64(t, 1, machine->db_id); 614 + tuple_set_string(t, 2, dso->short_name); 615 + tuple_set_string(t, 3, dso->long_name); 616 + tuple_set_string(t, 4, sbuild_id); 617 + 618 + call_object(tables->dso_handler, t, "dso_table"); 619 + 620 + Py_DECREF(t); 621 + 622 + return 0; 623 + } 624 + 625 + static int python_export_symbol(struct db_export *dbe, struct symbol *sym, 626 + struct dso *dso) 627 + { 628 + struct tables *tables = container_of(dbe, struct tables, dbe); 629 + u64 *sym_db_id = symbol__priv(sym); 630 + PyObject *t; 631 + 632 + t = tuple_new(6); 633 + 634 + tuple_set_u64(t, 0, *sym_db_id); 635 + tuple_set_u64(t, 1, dso->db_id); 636 + tuple_set_u64(t, 2, sym->start); 637 + tuple_set_u64(t, 3, sym->end); 638 + tuple_set_s32(t, 4, sym->binding); 639 + tuple_set_string(t, 5, sym->name); 640 + 641 + call_object(tables->symbol_handler, t, "symbol_table"); 642 + 643 + Py_DECREF(t); 644 + 645 + return 0; 646 + } 647 + 648 + static int python_export_sample(struct db_export *dbe, 649 + struct export_sample *es) 650 + { 651 + struct tables *tables = container_of(dbe, struct tables, dbe); 652 + PyObject *t; 653 + 654 + t = tuple_new(19); 655 + 656 + tuple_set_u64(t, 0, es->db_id); 657 + tuple_set_u64(t, 1, es->evsel->db_id); 658 + tuple_set_u64(t, 2, es->al->machine->db_id); 659 + tuple_set_u64(t, 3, es->thread->db_id); 660 + tuple_set_u64(t, 4, es->comm_db_id); 661 + tuple_set_u64(t, 5, es->dso_db_id); 662 + tuple_set_u64(t, 6, es->sym_db_id); 663 + tuple_set_u64(t, 7, es->offset); 664 + tuple_set_u64(t, 8, es->sample->ip); 665 + tuple_set_u64(t, 9, es->sample->time); 666 + tuple_set_s32(t, 10, es->sample->cpu); 667 + tuple_set_u64(t, 11, es->addr_dso_db_id); 668 + tuple_set_u64(t, 12, es->addr_sym_db_id); 669 + tuple_set_u64(t, 13, es->addr_offset); 670 + tuple_set_u64(t, 14, es->sample->addr); 671 + tuple_set_u64(t, 15, es->sample->period); 672 + tuple_set_u64(t, 16, es->sample->weight); 673 + tuple_set_u64(t, 17, es->sample->transaction); 674 + tuple_set_u64(t, 18, es->sample->data_src); 675 + 676 + call_object(tables->sample_handler, t, "sample_table"); 677 + 678 + Py_DECREF(t); 679 + 680 + return 0; 681 + } 682 + 497 683 static void python_process_general_event(struct perf_sample *sample, 498 684 struct perf_evsel *evsel, 499 685 struct thread *thread, ··· 775 551 Py_DECREF(t); 776 552 } 777 553 778 - static void python_process_event(union perf_event *event __maybe_unused, 554 + static void python_process_event(union perf_event *event, 779 555 struct perf_sample *sample, 780 556 struct perf_evsel *evsel, 781 557 struct thread *thread, 782 558 struct addr_location *al) 783 559 { 560 + struct tables *tables = &tables_global; 561 + 784 562 switch (evsel->attr.type) { 785 563 case PERF_TYPE_TRACEPOINT: 786 564 python_process_tracepoint(sample, evsel, thread, al); 787 565 break; 788 566 /* Reserve for future process_hw/sw/raw APIs */ 789 567 default: 790 - python_process_general_event(sample, evsel, thread, al); 568 + if (tables->db_export_mode) 569 + db_export__sample(&tables->dbe, event, sample, evsel, 570 + thread, al); 571 + else 572 + python_process_general_event(sample, evsel, thread, al); 791 573 } 792 574 } 793 575 ··· 819 589 return -1; 820 590 } 821 591 592 + #define SET_TABLE_HANDLER_(name, handler_name, table_name) do { \ 593 + tables->handler_name = get_handler(#table_name); \ 594 + if (tables->handler_name) \ 595 + tables->dbe.export_ ## name = python_export_ ## name; \ 596 + } while (0) 597 + 598 + #define SET_TABLE_HANDLER(name) \ 599 + SET_TABLE_HANDLER_(name, name ## _handler, name ## _table) 600 + 601 + static void set_table_handlers(struct tables *tables) 602 + { 603 + const char *perf_db_export_mode = "perf_db_export_mode"; 604 + PyObject *db_export_mode; 605 + int ret; 606 + 607 + memset(tables, 0, sizeof(struct tables)); 608 + if (db_export__init(&tables->dbe)) 609 + Py_FatalError("failed to initialize export"); 610 + 611 + db_export_mode = PyDict_GetItemString(main_dict, perf_db_export_mode); 612 + if (!db_export_mode) 613 + return; 614 + 615 + ret = PyObject_IsTrue(db_export_mode); 616 + if (ret == -1) 617 + handler_call_die(perf_db_export_mode); 618 + if (!ret) 619 + return; 620 + 621 + tables->db_export_mode = true; 622 + /* 623 + * Reserve per symbol space for symbol->db_id via symbol__priv() 624 + */ 625 + symbol_conf.priv_size = sizeof(u64); 626 + 627 + SET_TABLE_HANDLER(evsel); 628 + SET_TABLE_HANDLER(machine); 629 + SET_TABLE_HANDLER(thread); 630 + SET_TABLE_HANDLER(comm); 631 + SET_TABLE_HANDLER(comm_thread); 632 + SET_TABLE_HANDLER(dso); 633 + SET_TABLE_HANDLER(symbol); 634 + SET_TABLE_HANDLER(sample); 635 + } 636 + 822 637 /* 823 638 * Start trace script 824 639 */ 825 640 static int python_start_script(const char *script, int argc, const char **argv) 826 641 { 642 + struct tables *tables = &tables_global; 827 643 const char **command_line; 828 644 char buf[PATH_MAX]; 829 645 int i, err = 0; ··· 908 632 909 633 free(command_line); 910 634 635 + set_table_handlers(tables); 636 + 911 637 return err; 912 638 error: 913 639 Py_Finalize(); ··· 928 650 */ 929 651 static int python_stop_script(void) 930 652 { 653 + struct tables *tables = &tables_global; 654 + 931 655 try_call_object("trace_end", NULL); 656 + 657 + db_export__exit(&tables->dbe); 932 658 933 659 Py_XDECREF(main_dict); 934 660 Py_XDECREF(main_module);