diff options
| author | Jin Yao <yao.jin@linux.intel.com> | 2018-06-01 05:01:02 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2018-06-06 14:38:26 -0400 |
| commit | 48a1f565261d2ab1e17f9a3ad532cf6d9e07748d (patch) | |
| tree | 2ee2b3fb44754c02b7b803b9637743ea5da3ee64 /tools/perf/util/scripting-engines/trace-event-python.c | |
| parent | 5f9e0f3158a5cd0ef7bb205b9f1826b2ec1893a9 (diff) | |
perf script python: Add more PMU fields to event handler dict
When doing pmu sampling and then running a script with perf script -s
script.py, the process_event function gets dictionary with some fields
from the perf ring buffer (like ip, sym, callchain etc).
But we miss quite a few fields we report now, for example, LBRs, data
source, weight, transaction, iregs, uregs, etc.
This patch reports these fields for perf script python processing.
New keys/items:
---------------
key : brstack
items: from, to, from_dsoname, to_dsoname, mispred,
predicted, in_tx, abort, cycles.
key : brstacksym
items: from, to, pred, in_tx, abort (converted string)
key : datasrc
key : datasrc_decode (decoded string)
key : iregs
key : uregs
key : weight
key : transaction
v2:
---
Add new fields for dso.
Use PyBool_FromLong() for mispred/predicted/in_tx/abort
Committer notes:
!sym->name isn't valid, as its not a pointer, its a [0] array, use
!sym->name[0] instead, guaranteed to be the case by symbol__new.
This was caught by just one of the containers:
52 54.22 ubuntu:17.04 : FAIL gcc (Ubuntu 6.3.0-12ubuntu2) 6.3.0 20170406
CC /tmp/build/perf/util/scripting-engines/trace-event-python.o
util/scripting-engines/trace-event-python.c:534:20: error: address of array 'sym->name' will always evaluate to 'true' [-Werror,-Wpointer-bool-conversion]
if (!sym || !sym->name)
~~~~~~^~~~
1 error generated.
mv: cannot stat '/tmp/build/perf/util/scripting-engines/.trace-event-python.o.tmp': No such file or directory
/git/linux/tools/build/Makefile.build:96: recipe for target '/tmp/build/perf/util/scripting-engines/trace-event-python.o' failed
make[5]: *** [/tmp/build/perf/util/scripting-engines/trace-event-python.o] Error 1
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jin Yao <yao.jin@intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1527843663-32288-3-git-send-email-yao.jin@linux.intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/scripting-engines/trace-event-python.c')
| -rw-r--r-- | tools/perf/util/scripting-engines/trace-event-python.c | 227 |
1 files changed, 226 insertions, 1 deletions
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index f863e96fb7bc..46e9e19ab1ac 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
| @@ -48,6 +48,7 @@ | |||
| 48 | #include "cpumap.h" | 48 | #include "cpumap.h" |
| 49 | #include "print_binary.h" | 49 | #include "print_binary.h" |
| 50 | #include "stat.h" | 50 | #include "stat.h" |
| 51 | #include "mem-events.h" | ||
| 51 | 52 | ||
| 52 | #if PY_MAJOR_VERSION < 3 | 53 | #if PY_MAJOR_VERSION < 3 |
| 53 | #define _PyUnicode_FromString(arg) \ | 54 | #define _PyUnicode_FromString(arg) \ |
| @@ -455,6 +456,166 @@ exit: | |||
| 455 | return pylist; | 456 | return pylist; |
| 456 | } | 457 | } |
| 457 | 458 | ||
| 459 | static PyObject *python_process_brstack(struct perf_sample *sample, | ||
| 460 | struct thread *thread) | ||
| 461 | { | ||
| 462 | struct branch_stack *br = sample->branch_stack; | ||
| 463 | PyObject *pylist; | ||
| 464 | u64 i; | ||
| 465 | |||
| 466 | pylist = PyList_New(0); | ||
| 467 | if (!pylist) | ||
| 468 | Py_FatalError("couldn't create Python list"); | ||
| 469 | |||
| 470 | if (!(br && br->nr)) | ||
| 471 | goto exit; | ||
| 472 | |||
| 473 | for (i = 0; i < br->nr; i++) { | ||
| 474 | PyObject *pyelem; | ||
| 475 | struct addr_location al; | ||
| 476 | const char *dsoname; | ||
| 477 | |||
| 478 | pyelem = PyDict_New(); | ||
| 479 | if (!pyelem) | ||
| 480 | Py_FatalError("couldn't create Python dictionary"); | ||
| 481 | |||
| 482 | pydict_set_item_string_decref(pyelem, "from", | ||
| 483 | PyLong_FromUnsignedLongLong(br->entries[i].from)); | ||
| 484 | pydict_set_item_string_decref(pyelem, "to", | ||
| 485 | PyLong_FromUnsignedLongLong(br->entries[i].to)); | ||
| 486 | pydict_set_item_string_decref(pyelem, "mispred", | ||
| 487 | PyBool_FromLong(br->entries[i].flags.mispred)); | ||
| 488 | pydict_set_item_string_decref(pyelem, "predicted", | ||
| 489 | PyBool_FromLong(br->entries[i].flags.predicted)); | ||
| 490 | pydict_set_item_string_decref(pyelem, "in_tx", | ||
| 491 | PyBool_FromLong(br->entries[i].flags.in_tx)); | ||
| 492 | pydict_set_item_string_decref(pyelem, "abort", | ||
| 493 | PyBool_FromLong(br->entries[i].flags.abort)); | ||
| 494 | pydict_set_item_string_decref(pyelem, "cycles", | ||
| 495 | PyLong_FromUnsignedLongLong(br->entries[i].flags.cycles)); | ||
| 496 | |||
| 497 | thread__find_map(thread, sample->cpumode, | ||
| 498 | br->entries[i].from, &al); | ||
| 499 | dsoname = get_dsoname(al.map); | ||
| 500 | pydict_set_item_string_decref(pyelem, "from_dsoname", | ||
| 501 | _PyUnicode_FromString(dsoname)); | ||
| 502 | |||
| 503 | thread__find_map(thread, sample->cpumode, | ||
| 504 | br->entries[i].to, &al); | ||
| 505 | dsoname = get_dsoname(al.map); | ||
| 506 | pydict_set_item_string_decref(pyelem, "to_dsoname", | ||
| 507 | _PyUnicode_FromString(dsoname)); | ||
| 508 | |||
| 509 | PyList_Append(pylist, pyelem); | ||
| 510 | Py_DECREF(pyelem); | ||
| 511 | } | ||
| 512 | |||
| 513 | exit: | ||
| 514 | return pylist; | ||
| 515 | } | ||
| 516 | |||
| 517 | static unsigned long get_offset(struct symbol *sym, struct addr_location *al) | ||
| 518 | { | ||
| 519 | unsigned long offset; | ||
| 520 | |||
| 521 | if (al->addr < sym->end) | ||
| 522 | offset = al->addr - sym->start; | ||
| 523 | else | ||
| 524 | offset = al->addr - al->map->start - sym->start; | ||
| 525 | |||
| 526 | return offset; | ||
| 527 | } | ||
| 528 | |||
| 529 | static int get_symoff(struct symbol *sym, struct addr_location *al, | ||
| 530 | bool print_off, char *bf, int size) | ||
| 531 | { | ||
| 532 | unsigned long offset; | ||
| 533 | |||
| 534 | if (!sym || !sym->name[0]) | ||
| 535 | return scnprintf(bf, size, "%s", "[unknown]"); | ||
| 536 | |||
| 537 | if (!print_off) | ||
| 538 | return scnprintf(bf, size, "%s", sym->name); | ||
| 539 | |||
| 540 | offset = get_offset(sym, al); | ||
| 541 | |||
| 542 | return scnprintf(bf, size, "%s+0x%x", sym->name, offset); | ||
| 543 | } | ||
| 544 | |||
| 545 | static int get_br_mspred(struct branch_flags *flags, char *bf, int size) | ||
| 546 | { | ||
| 547 | if (!flags->mispred && !flags->predicted) | ||
| 548 | return scnprintf(bf, size, "%s", "-"); | ||
| 549 | |||
| 550 | if (flags->mispred) | ||
| 551 | return scnprintf(bf, size, "%s", "M"); | ||
| 552 | |||
| 553 | return scnprintf(bf, size, "%s", "P"); | ||
| 554 | } | ||
| 555 | |||
| 556 | static PyObject *python_process_brstacksym(struct perf_sample *sample, | ||
| 557 | struct thread *thread) | ||
| 558 | { | ||
| 559 | struct branch_stack *br = sample->branch_stack; | ||
| 560 | PyObject *pylist; | ||
| 561 | u64 i; | ||
| 562 | char bf[512]; | ||
| 563 | struct addr_location al; | ||
| 564 | |||
| 565 | pylist = PyList_New(0); | ||
| 566 | if (!pylist) | ||
| 567 | Py_FatalError("couldn't create Python list"); | ||
| 568 | |||
| 569 | if (!(br && br->nr)) | ||
| 570 | goto exit; | ||
| 571 | |||
| 572 | for (i = 0; i < br->nr; i++) { | ||
| 573 | PyObject *pyelem; | ||
| 574 | |||
| 575 | pyelem = PyDict_New(); | ||
| 576 | if (!pyelem) | ||
| 577 | Py_FatalError("couldn't create Python dictionary"); | ||
| 578 | |||
| 579 | thread__find_symbol(thread, sample->cpumode, | ||
| 580 | br->entries[i].from, &al); | ||
| 581 | get_symoff(al.sym, &al, true, bf, sizeof(bf)); | ||
| 582 | pydict_set_item_string_decref(pyelem, "from", | ||
| 583 | _PyUnicode_FromString(bf)); | ||
| 584 | |||
| 585 | thread__find_symbol(thread, sample->cpumode, | ||
| 586 | br->entries[i].to, &al); | ||
| 587 | get_symoff(al.sym, &al, true, bf, sizeof(bf)); | ||
| 588 | pydict_set_item_string_decref(pyelem, "to", | ||
| 589 | _PyUnicode_FromString(bf)); | ||
| 590 | |||
| 591 | get_br_mspred(&br->entries[i].flags, bf, sizeof(bf)); | ||
| 592 | pydict_set_item_string_decref(pyelem, "pred", | ||
| 593 | _PyUnicode_FromString(bf)); | ||
| 594 | |||
| 595 | if (br->entries[i].flags.in_tx) { | ||
| 596 | pydict_set_item_string_decref(pyelem, "in_tx", | ||
| 597 | _PyUnicode_FromString("X")); | ||
| 598 | } else { | ||
| 599 | pydict_set_item_string_decref(pyelem, "in_tx", | ||
| 600 | _PyUnicode_FromString("-")); | ||
| 601 | } | ||
| 602 | |||
| 603 | if (br->entries[i].flags.abort) { | ||
| 604 | pydict_set_item_string_decref(pyelem, "abort", | ||
| 605 | _PyUnicode_FromString("A")); | ||
| 606 | } else { | ||
| 607 | pydict_set_item_string_decref(pyelem, "abort", | ||
| 608 | _PyUnicode_FromString("-")); | ||
| 609 | } | ||
| 610 | |||
| 611 | PyList_Append(pylist, pyelem); | ||
| 612 | Py_DECREF(pyelem); | ||
| 613 | } | ||
| 614 | |||
| 615 | exit: | ||
| 616 | return pylist; | ||
| 617 | } | ||
| 618 | |||
| 458 | static PyObject *get_sample_value_as_tuple(struct sample_read_value *value) | 619 | static PyObject *get_sample_value_as_tuple(struct sample_read_value *value) |
| 459 | { | 620 | { |
| 460 | PyObject *t; | 621 | PyObject *t; |
| @@ -505,12 +666,63 @@ static void set_sample_read_in_dict(PyObject *dict_sample, | |||
| 505 | pydict_set_item_string_decref(dict_sample, "values", values); | 666 | pydict_set_item_string_decref(dict_sample, "values", values); |
| 506 | } | 667 | } |
| 507 | 668 | ||
| 669 | static void set_sample_datasrc_in_dict(PyObject *dict, | ||
| 670 | struct perf_sample *sample) | ||
| 671 | { | ||
| 672 | struct mem_info mi = { .data_src.val = sample->data_src }; | ||
| 673 | char decode[100]; | ||
| 674 | |||
| 675 | pydict_set_item_string_decref(dict, "datasrc", | ||
| 676 | PyLong_FromUnsignedLongLong(sample->data_src)); | ||
| 677 | |||
| 678 | perf_script__meminfo_scnprintf(decode, 100, &mi); | ||
| 679 | |||
| 680 | pydict_set_item_string_decref(dict, "datasrc_decode", | ||
| 681 | _PyUnicode_FromString(decode)); | ||
| 682 | } | ||
| 683 | |||
| 684 | static int regs_map(struct regs_dump *regs, uint64_t mask, char *bf, int size) | ||
| 685 | { | ||
| 686 | unsigned int i = 0, r; | ||
| 687 | int printed = 0; | ||
| 688 | |||
| 689 | bf[0] = 0; | ||
| 690 | |||
| 691 | for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { | ||
| 692 | u64 val = regs->regs[i++]; | ||
| 693 | |||
| 694 | printed += scnprintf(bf + printed, size - printed, | ||
| 695 | "%5s:0x%" PRIx64 " ", | ||
| 696 | perf_reg_name(r), val); | ||
| 697 | } | ||
| 698 | |||
| 699 | return printed; | ||
| 700 | } | ||
| 701 | |||
| 702 | static void set_regs_in_dict(PyObject *dict, | ||
| 703 | struct perf_sample *sample, | ||
| 704 | struct perf_evsel *evsel) | ||
| 705 | { | ||
| 706 | struct perf_event_attr *attr = &evsel->attr; | ||
| 707 | char bf[512]; | ||
| 708 | |||
| 709 | regs_map(&sample->intr_regs, attr->sample_regs_intr, bf, sizeof(bf)); | ||
| 710 | |||
| 711 | pydict_set_item_string_decref(dict, "iregs", | ||
| 712 | _PyUnicode_FromString(bf)); | ||
| 713 | |||
| 714 | regs_map(&sample->user_regs, attr->sample_regs_user, bf, sizeof(bf)); | ||
| 715 | |||
| 716 | pydict_set_item_string_decref(dict, "uregs", | ||
| 717 | _PyUnicode_FromString(bf)); | ||
| 718 | } | ||
| 719 | |||
| 508 | static PyObject *get_perf_sample_dict(struct perf_sample *sample, | 720 | static PyObject *get_perf_sample_dict(struct perf_sample *sample, |
| 509 | struct perf_evsel *evsel, | 721 | struct perf_evsel *evsel, |
| 510 | struct addr_location *al, | 722 | struct addr_location *al, |
| 511 | PyObject *callchain) | 723 | PyObject *callchain) |
| 512 | { | 724 | { |
| 513 | PyObject *dict, *dict_sample; | 725 | PyObject *dict, *dict_sample, *brstack, *brstacksym; |
| 514 | 726 | ||
| 515 | dict = PyDict_New(); | 727 | dict = PyDict_New(); |
| 516 | if (!dict) | 728 | if (!dict) |
| @@ -541,6 +753,11 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, | |||
| 541 | pydict_set_item_string_decref(dict_sample, "addr", | 753 | pydict_set_item_string_decref(dict_sample, "addr", |
| 542 | PyLong_FromUnsignedLongLong(sample->addr)); | 754 | PyLong_FromUnsignedLongLong(sample->addr)); |
| 543 | set_sample_read_in_dict(dict_sample, sample, evsel); | 755 | set_sample_read_in_dict(dict_sample, sample, evsel); |
| 756 | pydict_set_item_string_decref(dict_sample, "weight", | ||
| 757 | PyLong_FromUnsignedLongLong(sample->weight)); | ||
| 758 | pydict_set_item_string_decref(dict_sample, "transaction", | ||
| 759 | PyLong_FromUnsignedLongLong(sample->transaction)); | ||
| 760 | set_sample_datasrc_in_dict(dict_sample, sample); | ||
| 544 | pydict_set_item_string_decref(dict, "sample", dict_sample); | 761 | pydict_set_item_string_decref(dict, "sample", dict_sample); |
| 545 | 762 | ||
| 546 | pydict_set_item_string_decref(dict, "raw_buf", _PyBytes_FromStringAndSize( | 763 | pydict_set_item_string_decref(dict, "raw_buf", _PyBytes_FromStringAndSize( |
| @@ -558,6 +775,14 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, | |||
| 558 | 775 | ||
| 559 | pydict_set_item_string_decref(dict, "callchain", callchain); | 776 | pydict_set_item_string_decref(dict, "callchain", callchain); |
| 560 | 777 | ||
| 778 | brstack = python_process_brstack(sample, al->thread); | ||
| 779 | pydict_set_item_string_decref(dict, "brstack", brstack); | ||
| 780 | |||
| 781 | brstacksym = python_process_brstacksym(sample, al->thread); | ||
| 782 | pydict_set_item_string_decref(dict, "brstacksym", brstacksym); | ||
| 783 | |||
| 784 | set_regs_in_dict(dict, sample, evsel); | ||
| 785 | |||
| 561 | return dict; | 786 | return dict; |
| 562 | } | 787 | } |
| 563 | 788 | ||
