aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-script.c
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2016-02-24 06:20:45 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-02-24 10:09:24 -0500
commit30372f04c9dc159f99f1f09c61e5e0dbe4c91251 (patch)
treef36de1d6d7d664537fa85cfe47b48fac3e106fa6 /tools/perf/builtin-script.c
parentc339b1a90e6cd638a1d99cbbf49d870ce233198e (diff)
perf script: Print bpf-output events in 'perf script'
This patch allows 'perf script' output messages from BPF program. For example, use test_bpf_output_3.c at the end of this commit message, # ./perf record -e bpf-output/no-inherit,name=evt/ \ -e ./test_bpf_output_3.c/map:channel.event=evt/ \ usleep 100000 # ./perf script usleep 4882 21384.532523: evt: ffffffff810e97d1 sys_nanosleep ([kernel.kallsyms]) BPF output: 0000: 52 61 69 73 65 20 61 20 Raise a 0008: 42 50 46 20 65 76 65 6e BPF even 0010: 74 21 00 00 t!.. BPF string: "Raise a BPF event!" usleep 4882 21384.632606: evt: ffffffff8105c609 kretprobe_trampoline_holder ([kernel.kallsyms BPF output: 0000: 52 61 69 73 65 20 61 20 Raise a 0008: 42 50 46 20 65 76 65 6e BPF even 0010: 74 21 00 00 t!.. BPF string: "Raise a BPF event!" Two samples from BPF output are printed by both binary and string format. If BPF program output something unprintable, string format is suppressed. /************************ BEGIN **************************/ #include <uapi/linux/bpf.h> struct bpf_map_def { unsigned int type; unsigned int key_size; unsigned int value_size; unsigned int max_entries; }; #define SEC(NAME) __attribute__((section(NAME), used)) static u64 (*ktime_get_ns)(void) = (void *)BPF_FUNC_ktime_get_ns; static int (*trace_printk)(const char *fmt, int fmt_size, ...) = (void *)BPF_FUNC_trace_printk; static int (*get_smp_processor_id)(void) = (void *)BPF_FUNC_get_smp_processor_id; static int (*perf_event_output)(void *, struct bpf_map_def *, int, void *, unsigned long) = (void *)BPF_FUNC_perf_event_output; struct bpf_map_def SEC("maps") channel = { .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, .key_size = sizeof(int), .value_size = sizeof(u32), .max_entries = __NR_CPUS__, }; static inline int __attribute__((always_inline)) func(void *ctx, int type) { char output_str[] = "Raise a BPF event!"; perf_event_output(ctx, &channel, get_smp_processor_id(), &output_str, sizeof(output_str)); return 0; } SEC("func_begin=sys_nanosleep") int func_begin(void *ctx) {return func(ctx, 1);} SEC("func_end=sys_nanosleep%return") int func_end(void *ctx) { return func(ctx, 2);} char _license[] SEC("license") = "GPL"; int _version SEC("version") = LINUX_VERSION_CODE; /************************* END ***************************/ Signed-off-by: Wang Nan <wangnan0@huawei.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Brendan Gregg <brendan.d.gregg@gmail.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Li Zefan <lizefan@huawei.com> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1456312845-111583-3-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-script.c')
-rw-r--r--tools/perf/builtin-script.c93
1 files changed, 88 insertions, 5 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 8ff5ff0fe38c..ec4fbd410a4b 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -61,6 +61,7 @@ enum perf_output_field {
61 PERF_OUTPUT_BRSTACKSYM = 1U << 16, 61 PERF_OUTPUT_BRSTACKSYM = 1U << 16,
62 PERF_OUTPUT_DATA_SRC = 1U << 17, 62 PERF_OUTPUT_DATA_SRC = 1U << 17,
63 PERF_OUTPUT_WEIGHT = 1U << 18, 63 PERF_OUTPUT_WEIGHT = 1U << 18,
64 PERF_OUTPUT_BPF_OUTPUT = 1U << 19,
64}; 65};
65 66
66struct output_option { 67struct output_option {
@@ -86,6 +87,7 @@ struct output_option {
86 {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, 87 {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM},
87 {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC}, 88 {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC},
88 {.str = "weight", .field = PERF_OUTPUT_WEIGHT}, 89 {.str = "weight", .field = PERF_OUTPUT_WEIGHT},
90 {.str = "bpf-output", .field = PERF_OUTPUT_BPF_OUTPUT},
89}; 91};
90 92
91/* default set to maintain compatibility with current format */ 93/* default set to maintain compatibility with current format */
@@ -106,7 +108,7 @@ static struct {
106 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 108 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
107 PERF_OUTPUT_PERIOD, 109 PERF_OUTPUT_PERIOD,
108 110
109 .invalid_fields = PERF_OUTPUT_TRACE, 111 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
110 }, 112 },
111 113
112 [PERF_TYPE_SOFTWARE] = { 114 [PERF_TYPE_SOFTWARE] = {
@@ -116,7 +118,7 @@ static struct {
116 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 118 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
117 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | 119 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
118 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 120 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
119 PERF_OUTPUT_PERIOD, 121 PERF_OUTPUT_PERIOD | PERF_OUTPUT_BPF_OUTPUT,
120 122
121 .invalid_fields = PERF_OUTPUT_TRACE, 123 .invalid_fields = PERF_OUTPUT_TRACE,
122 }, 124 },
@@ -126,7 +128,7 @@ static struct {
126 128
127 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | 129 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
128 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 130 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
129 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, 131 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE
130 }, 132 },
131 133
132 [PERF_TYPE_RAW] = { 134 [PERF_TYPE_RAW] = {
@@ -139,7 +141,7 @@ static struct {
139 PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR | 141 PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR |
140 PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT, 142 PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT,
141 143
142 .invalid_fields = PERF_OUTPUT_TRACE, 144 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
143 }, 145 },
144 146
145 [PERF_TYPE_BREAKPOINT] = { 147 [PERF_TYPE_BREAKPOINT] = {
@@ -151,7 +153,7 @@ static struct {
151 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 153 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
152 PERF_OUTPUT_PERIOD, 154 PERF_OUTPUT_PERIOD,
153 155
154 .invalid_fields = PERF_OUTPUT_TRACE, 156 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
155 }, 157 },
156}; 158};
157 159
@@ -624,6 +626,84 @@ static void print_sample_flags(u32 flags)
624 printf(" %-4s ", str); 626 printf(" %-4s ", str);
625} 627}
626 628
629struct printer_data {
630 int line_no;
631 bool hit_nul;
632 bool is_printable;
633};
634
635static void
636print_sample_bpf_output_printer(enum binary_printer_ops op,
637 unsigned int val,
638 void *extra)
639{
640 unsigned char ch = (unsigned char)val;
641 struct printer_data *printer_data = extra;
642
643 switch (op) {
644 case BINARY_PRINT_DATA_BEGIN:
645 printf("\n");
646 break;
647 case BINARY_PRINT_LINE_BEGIN:
648 printf("%17s", !printer_data->line_no ? "BPF output:" :
649 " ");
650 break;
651 case BINARY_PRINT_ADDR:
652 printf(" %04x:", val);
653 break;
654 case BINARY_PRINT_NUM_DATA:
655 printf(" %02x", val);
656 break;
657 case BINARY_PRINT_NUM_PAD:
658 printf(" ");
659 break;
660 case BINARY_PRINT_SEP:
661 printf(" ");
662 break;
663 case BINARY_PRINT_CHAR_DATA:
664 if (printer_data->hit_nul && ch)
665 printer_data->is_printable = false;
666
667 if (!isprint(ch)) {
668 printf("%c", '.');
669
670 if (!printer_data->is_printable)
671 break;
672
673 if (ch == '\0')
674 printer_data->hit_nul = true;
675 else
676 printer_data->is_printable = false;
677 } else {
678 printf("%c", ch);
679 }
680 break;
681 case BINARY_PRINT_CHAR_PAD:
682 printf(" ");
683 break;
684 case BINARY_PRINT_LINE_END:
685 printf("\n");
686 printer_data->line_no++;
687 break;
688 case BINARY_PRINT_DATA_END:
689 default:
690 break;
691 }
692}
693
694static void print_sample_bpf_output(struct perf_sample *sample)
695{
696 unsigned int nr_bytes = sample->raw_size;
697 struct printer_data printer_data = {0, false, true};
698
699 print_binary(sample->raw_data, nr_bytes, 8,
700 print_sample_bpf_output_printer, &printer_data);
701
702 if (printer_data.is_printable && printer_data.hit_nul)
703 printf("%17s \"%s\"\n", "BPF string:",
704 (char *)(sample->raw_data));
705}
706
627struct perf_script { 707struct perf_script {
628 struct perf_tool tool; 708 struct perf_tool tool;
629 struct perf_session *session; 709 struct perf_session *session;
@@ -731,6 +811,9 @@ static void process_event(struct perf_script *script, union perf_event *event,
731 else if (PRINT_FIELD(BRSTACKSYM)) 811 else if (PRINT_FIELD(BRSTACKSYM))
732 print_sample_brstacksym(event, sample, thread, attr); 812 print_sample_brstacksym(event, sample, thread, attr);
733 813
814 if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT))
815 print_sample_bpf_output(sample);
816
734 printf("\n"); 817 printf("\n");
735} 818}
736 819