A new syntax is appended into parser so user can pass predefined perf
events into BPF objects.

After this patch, BPF programs for perf are finally able to utilize
bpf_perf_event_read() introduced in commit 35578d7984003097af2b1e3
(bpf: Implement function bpf_perf_event_read() that get the selected
hardware PMU conuter) in following way:

 ===== BPF program bpf_program.c =====

 struct bpf_map_def SEC("maps") pmu_map = {
     .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)
 {
     unsigned long long val;
     char fmt[] = "sys_write:        pmu=%llu\n";
     val = bpf_perf_event_read(&pmu_map, bpf_get_smp_processor_id());
     bpf_trace_printk(fmt, sizeof(fmt), val);
     return 0;
 }

 SEC("func_write_return=sys_write%return")
 int func_write_return(void *ctx)
 {
     unsigned long long val = 0;
     char fmt[] = "sys_write_return: pmu=%llu\n";
     val = bpf_perf_event_read(&pmu_map, bpf_get_smp_processor_id());
     bpf_trace_printk(fmt, sizeof(fmt), val);
     return 0;
 }

 ===== cmdline =====
 # echo "" > /sys/kernel/debug/tracing/trace
 # perf record -e evt=cycles/period=0x7fffffffffffffff/ \
               -e bpf_program.c/maps.pmu_map.event[all]=evt/
               -a ls
 # cat /sys/kernel/debug/tracing/trace | grep ls
              ls-3363  [003] d... 75475.056190: : sys_write:        pmu=3961415
              ls-3363  [003] dN.. 75475.056212: : sys_write_return: pmu=4051390
              ls-3363  [003] d... 75475.056216: : sys_write:        pmu=4065447
              ls-3363  [003] dN.. 75475.056227: : sys_write_return: pmu=4109760
              ls-3363  [003] d... 75475.056230: : sys_write:        pmu=4120776
              ls-3363  [003] dN.. 75475.056245: : sys_write_return: pmu=4178441
              ...
 # perf report --stdio
 Error:
 The perf.data file has no samples!

Where, setting period of cycles Set a very large value to period
of cycles event because we want to use this event as a counter
only, don't need sampling.

Signed-off-by: Wang Nan <wangn...@huawei.com>
Signed-off-by: He Kuang <heku...@huawei.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Alexei Starovoitov <a...@plumgrid.com>
Cc: Brendan Gregg <brendan.d.gr...@gmail.com>
Cc: Daniel Borkmann <dan...@iogearbox.net>
Cc: David Ahern <dsah...@gmail.com>
Cc: He Kuang <heku...@huawei.com>
Cc: Jiri Olsa <jo...@kernel.org>
Cc: Kaixu Xia <xiaka...@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu...@hitachi.com>
Cc: Namhyung Kim <namhy...@kernel.org>
Cc: Paul Mackerras <pau...@samba.org>
Cc: Peter Zijlstra <a.p.zijls...@chello.nl>
Cc: Zefan Li <lize...@huawei.com>
Cc: pi3or...@163.com
Link: http://lkml.kernel.org/n/ebpf-2mjd96mowgzslkj8jrwbn...@git.kernel.org
---
 tools/perf/util/bpf-loader.c   | 106 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/parse-events.c |   2 +-
 2 files changed, 107 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 023fc12..e185fb6 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -643,6 +643,7 @@ enum bpf_map_priv_key_type {
 
 enum bpf_map_priv_value_type {
        BPF_MAP_PRIV_VAL_VALUE,
+       BPF_MAP_PRIV_VAL_EVSEL,
 };
 
 struct bpf_map_priv {
@@ -660,6 +661,7 @@ struct bpf_map_priv {
                enum bpf_map_priv_value_type type;
                union {
                        u64 val;
+                       struct perf_evsel *evsel;
                };
        } value;
 };
@@ -715,6 +717,7 @@ bpf_map_config_foreach_key(struct bpf_map *map,
 
        switch (def.type) {
        case BPF_MAP_TYPE_ARRAY:
+       case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
                switch (priv->key.type) {
                case BPF_MAP_PRIV_KEY_ALL:
                        for (i = 0; i < def.max_entries; i++) {
@@ -838,6 +841,69 @@ bpf__config_obj_map_value(struct bpf_map *map,
        return -EINVAL;
 }
 
+static int
+bpf__config_obj_map_array_event(struct bpf_map *map,
+                               struct parse_events_term *term,
+                               struct perf_evlist *evlist)
+{
+       struct bpf_map_priv *priv;
+       struct perf_evsel *evsel;
+       struct bpf_map_def def;
+       const char *map_name;
+       int err;
+
+       map_name = bpf_map__get_name(map);
+       evsel = perf_evlist__find_evsel_by_alias(evlist, term->val.str);
+       if (!evsel) {
+               pr_debug("Event (for '%s') '%s' doesn't exist\n",
+                        map_name, term->val.str);
+               return -EINVAL;
+       }
+
+       err = bpf_map__get_def(map, &def);
+       if (err) {
+               pr_debug("Unable to get map definition from '%s'\n",
+                        map_name);
+               return -EINVAL;
+       }
+       
+       /*
+        * No need to check key_size and value_size:
+        * kernel has already checked them.
+        */
+       if (def.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) {
+               pr_debug("Map %s type is not BPF_MAP_TYPE_PERF_EVENT_ARRAY\n",
+                        map_name);
+               return -EINVAL;
+       }
+
+       priv = zalloc(sizeof(*priv));
+       if (!priv) {
+               pr_debug("No enough memory for map private\n");
+               return -ENOMEM;
+       }
+
+       err = bpf_map_priv_setkey(priv, term, map_name);
+       if (err)
+               return err;
+
+       priv->value.type = BPF_MAP_PRIV_VAL_EVSEL;
+       priv->value.evsel = evsel;
+       return bpf_map__set_private(map, priv, bpf_map_priv__clear);
+}
+
+static int
+bpf__config_obj_map_event(struct bpf_map *map,
+                         struct parse_events_term *term,
+                         struct perf_evlist *evlist)
+{
+       if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR)
+               return bpf__config_obj_map_array_event(map, term, evlist);
+
+       pr_debug("ERROR: wrong value type\n");
+       return -EINVAL;
+}
+
 struct bpf_config_map_func {
        const char *config_opt;
        int (*config_func)(struct bpf_map *, struct parse_events_term *,
@@ -846,6 +912,7 @@ struct bpf_config_map_func {
 
 struct bpf_config_map_func bpf_config_map_funcs[] = {
        {"value", bpf__config_obj_map_value},
+       {"event", bpf__config_obj_map_event},
 };
 
 static int
@@ -964,6 +1031,40 @@ bpf__apply_config_value_for_key(int map_fd, void *pkey,
 }
 
 static int
+bpf__apply_config_evsel_for_key(const char *name, int map_fd, void *pkey,
+                               struct perf_evsel *evsel)
+{
+       struct xyarray *xy = evsel->fd;
+       unsigned int key, events;
+       int *evt_fd;
+       int err;
+
+       if (!xy) {
+               pr_debug("ERROR: evsel not ready for map %s\n", name);
+               return -EINVAL;
+       }
+
+       if (xy->row_size / xy->entry_size != 1) {
+               pr_debug("ERROR: Dimension of target event is incorrect for map 
%s\n",
+                        name);
+               return -EINVAL;
+       }
+
+       events = xy->entries / (xy->row_size / xy->entry_size);
+       key = *((unsigned int *)pkey);
+       if (key >= events) {
+               pr_debug("ERROR: there is no event %d for map %s\n",
+                        key, name);
+               return -E2BIG;
+       }
+       evt_fd = xyarray__entry(xy, key, 0);
+       err = bpf_map_update_elem(map_fd, pkey, evt_fd, BPF_ANY);
+       if (err && errno)
+               err = -errno;
+       return err;
+}
+
+static int
 bpf__apply_config_map_for_key(const char *name, int map_fd,
                              struct bpf_map_def *pdef __maybe_unused,
                              struct bpf_map_priv *priv,
@@ -977,6 +1078,10 @@ bpf__apply_config_map_for_key(const char *name, int 
map_fd,
                                                      pdef->value_size,
                                                      priv->value.val);
                break;
+       case BPF_MAP_PRIV_VAL_EVSEL:
+               err = bpf__apply_config_evsel_for_key(name, map_fd, pkey,
+                                                     priv->value.evsel);
+               break;
        default:
                pr_debug("ERROR: unknown value type for '%s'\n", name);
                err = -EINVAL;
@@ -1081,6 +1186,7 @@ int bpf__strerror_apply_config(int err, char *buf, size_t 
size)
 {
        bpf__strerror_head(err, buf, size);
        bpf__strerror_entry(EINVAL, "Invalid option for map, add -v to see 
detail");
+       bpf__strerror_entry(E2BIG,  "Array index too big, add -v to see 
detail");
        bpf__strerror_end(buf, size);
        return 0;
 }
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index a2af5a8..ae973cd 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -654,7 +654,7 @@ parse_events_config_bpf(struct parse_events_evlist *data,
                                                 err, errbuf, sizeof(errbuf));
                        data->error->help = strdup(
 "Hint:\tValid config term:\n"
-"     \tmaps.<mapname>.value<indics>\n"
+"     \tmaps.<mapname>.[value|event]<indics>\n"
 "\n"
 "     \twhere <indics> is something like [0,3-4]\n"
 "     \t(add -v to see detail)");
-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to