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 | ||