perf tools: Introduce bpf-output event
authorWang Nan <wangnan0@huawei.com>
Mon, 22 Feb 2016 09:10:37 +0000 (09:10 +0000)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 22 Feb 2016 17:37:21 +0000 (14:37 -0300)
Commit a43eec304259 ("bpf: introduce bpf_perf_event_output() helper")
adds a helper to enable a BPF program to output data to a perf ring
buffer through a new type of perf event, PERF_COUNT_SW_BPF_OUTPUT. This
patch enables perf to create events of that type. Now a perf user can
use the following cmdline to receive output data from BPF programs:

  # perf record -a -e bpf-output/no-inherit,name=evt/ \
                    -e ./test_bpf_output.c/map:channel.event=evt/ ls /
  # perf script
     perf 1560 [004] 347747.086295:  evt: ffffffff811fd201 sys_write ...
     perf 1560 [004] 347747.086300:  evt: ffffffff811fd201 sys_write ...
     perf 1560 [004] 347747.086315:  evt: ffffffff811fd201 sys_write ...
            ...

Test result:

  # cat test_bpf_output.c
  /************************ 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__,
  };

  SEC("func_write=sys_write")
  int func_write(void *ctx)
  {
  struct {
  u64 ktime;
  int cpuid;
  } __attribute__((packed)) output_data;
  char error_data[] = "Error: failed to output: %d\n";

  output_data.cpuid = get_smp_processor_id();
  output_data.ktime = ktime_get_ns();
  int err = perf_event_output(ctx, &channel, get_smp_processor_id(),
      &output_data, sizeof(output_data));
  if (err)
  trace_printk(error_data, sizeof(error_data), err);
  return 0;
  }
  char _license[] SEC("license") = "GPL";
  int _version SEC("version") = LINUX_VERSION_CODE;
  /************************ END ***************************/

  # perf record -a -e bpf-output/no-inherit,name=evt/ \
                    -e ./test_bpf_output.c/map:channel.event=evt/ ls /
  # perf script | grep ls
     ls  2242 [003] 347851.557563:   evt: ffffffff811fd201 sys_write ...
     ls  2242 [003] 347851.557571:   evt: ffffffff811fd201 sys_write ...

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Cody P Schafer <dev@codyps.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jeremie Galarneau <jeremie.galarneau@efficios.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kirill Smelkov <kirr@nexedi.com>
Cc: Li Zefan <lizefan@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1456132275-98875-11-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/bpf-loader.c
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/parse-events.l

index 44824e3eeaed51f19c63ad1779a9e74a59d4f384..0967ce601931685ed294827e8aef7c30c47736c6 100644 (file)
@@ -1331,13 +1331,12 @@ apply_config_evsel_for_key(const char *name, int map_fd, void *pkey,
                return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH;
        }
 
+       if (perf_evsel__is_bpf_output(evsel))
+               check_pass = true;
        if (attr->type == PERF_TYPE_RAW)
                check_pass = true;
        if (attr->type == PERF_TYPE_HARDWARE)
                check_pass = true;
-       if (attr->type == PERF_TYPE_SOFTWARE &&
-                       attr->config == PERF_COUNT_SW_BPF_OUTPUT)
-               check_pass = true;
        if (!check_pass) {
                pr_debug("ERROR: Event type is wrong for map %s\n", name);
                return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE;
index 6ae20d0056de6a6bff31f62290ac81bffa44ef2d..0902fe418754ec0c3149d3daeafc122fee65e243 100644 (file)
@@ -225,6 +225,11 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
        if (evsel != NULL)
                perf_evsel__init(evsel, attr, idx);
 
+       if (perf_evsel__is_bpf_output(evsel)) {
+               evsel->attr.sample_type |= PERF_SAMPLE_RAW;
+               evsel->attr.sample_period = 1;
+       }
+
        return evsel;
 }
 
index 8e75434bd01c671a8ed2e0c0b03a139212d7001c..efad78f811adcc70697b35d20baa08fe4ee247ec 100644 (file)
@@ -364,6 +364,14 @@ static inline bool perf_evsel__is_function_event(struct perf_evsel *evsel)
 #undef FUNCTION_EVENT
 }
 
+static inline bool perf_evsel__is_bpf_output(struct perf_evsel *evsel)
+{
+       struct perf_event_attr *attr = &evsel->attr;
+
+       return (attr->config == PERF_COUNT_SW_BPF_OUTPUT) &&
+               (attr->type == PERF_TYPE_SOFTWARE);
+}
+
 struct perf_attr_details {
        bool freq;
        bool verbose;
index fb85d0311d28f3a714e0b106751e558dae1c04f1..1477fbc78993c7b31d7bb1531f630cca8587d93f 100644 (file)
@@ -248,6 +248,7 @@ cpu-migrations|migrations                   { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COU
 alignment-faults                               { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
 emulation-faults                               { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
 dummy                                          { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
+bpf-output                                     { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_BPF_OUTPUT); }
 
        /*
         * We have to handle the kernel PMU event cycles-ct/cycles-t/mem-loads/mem-stores separately.