Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753412AbbH0KoX (ORCPT ); Thu, 27 Aug 2015 06:44:23 -0400 Received: from szxga01-in.huawei.com ([58.251.152.64]:35821 "EHLO szxga01-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751769AbbH0Kmq (ORCPT ); Thu, 27 Aug 2015 06:42:46 -0400 From: Kaixu Xia To: , , , , , , , CC: , , , Subject: [RFC PATCH 2/4] bpf tools: Collect BPF_MAP_TYPE_PERF_EVENT_ARRAY map definitions from 'maps' section Date: Thu, 27 Aug 2015 10:42:20 +0000 Message-ID: <1440672142-89311-3-git-send-email-xiakaixu@huawei.com> X-Mailer: git-send-email 1.8.3.4 In-Reply-To: <1440672142-89311-1-git-send-email-xiakaixu@huawei.com> References: <1440672142-89311-1-git-send-email-xiakaixu@huawei.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.107.193.250] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5321 Lines: 193 In order to make use of the new ability of eBPF programs to access hardware PMU counter, we need to get the event & map match. So we introduce the struct perf_event_map_def that contains struct bpf_map _def and struct perf_event_attr. We can get the necessary info from 'maps' section and store the pointers to struct perf_event in BPF_MAP_TYPE_PERF_EVENT_ARRAY maps. Signed-off-by: Kaixu Xia --- tools/lib/bpf/libbpf.c | 76 ++++++++++++++++++++++++++++++++++++++++---------- tools/lib/bpf/libbpf.h | 13 +++++++++ 2 files changed, 74 insertions(+), 15 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 1ff6a19..83d79c4 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -570,7 +570,7 @@ bpf_object__find_prog_by_idx(struct bpf_object *obj, int idx) static int bpf_program__collect_reloc(struct bpf_program *prog, - size_t nr_maps, GElf_Shdr *shdr, + size_t max_maps, GElf_Shdr *shdr, Elf_Data *data, Elf_Data *symbols) { int i, nrels; @@ -616,9 +616,9 @@ bpf_program__collect_reloc(struct bpf_program *prog, } map_idx = sym.st_value / sizeof(struct bpf_map_def); - if (map_idx >= nr_maps) { + if (map_idx >= max_maps) { pr_warning("bpf relocation: map_idx %d large than %d\n", - (int)map_idx, (int)nr_maps - 1); + (int)map_idx, (int)max_maps - 1); return -EINVAL; } @@ -629,11 +629,42 @@ bpf_program__collect_reloc(struct bpf_program *prog, } static int +bpf_object__collect_perf_event_maps(void *data, int **pfd) +{ + int i, event_fd; + int maps_fd = **pfd; + int attr_length = ATTR_LENGTH; + int nr_cpus = sysconf(_SC_NPROCESSORS_CONF); + struct perf_event_attr *attr; + + attr = (struct perf_event_attr *)(data + sizeof(struct bpf_map_def)); + if (attr->type != PERF_TYPE_RAW && + attr->type != PERF_TYPE_HARDWARE) + return -EINVAL; + attr->disabled = 1; + + do { + (*pfd)++; + **pfd = -1; + } while (--attr_length); + + for (i = 0; i < nr_cpus; i++) { + event_fd = perf_event_open(attr, -1/*pid*/, i/*cpu*/, -1/*group_fd*/, 0); + if (event_fd < 0) { + pr_warning("event syscall failed\n"); + return -EINVAL; + } + bpf_update_elem(maps_fd, &i, &event_fd, BPF_ANY); + } + return 0; +} + +static int bpf_object__create_maps(struct bpf_object *obj) { unsigned int i; - size_t nr_maps; - int *pfd; + size_t nr_maps, j; + int *pfd, err; nr_maps = obj->maps_buf_sz / sizeof(struct bpf_map_def); if (!obj->maps_buf || !nr_maps) { @@ -664,24 +695,37 @@ bpf_object__create_maps(struct bpf_object *obj) def.value_size, def.max_entries); if (*pfd < 0) { - size_t j; - int err = *pfd; - + err = *pfd; pr_warning("failed to create map: %s\n", strerror(errno)); - for (j = 0; j < i; j++) - zclose(obj->map_fds[j]); - obj->nr_map_fds = 0; - zfree(&obj->map_fds); - return err; + goto out_close; } pr_debug("create map: fd=%d\n", *pfd); + + if (def.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY) { + void *data = obj->maps_buf + i * sizeof(struct bpf_map_def); + + err = bpf_object__collect_perf_event_maps(data, &pfd); + if (err < 0) { + pr_warning("failed to collect perf_event maps: %s\n", + strerror(errno)); + goto out_close; + } + i += ATTR_LENGTH; + } pfd++; } zfree(&obj->maps_buf); obj->maps_buf_sz = 0; return 0; + +out_close: + for (j = 0; j < i; j++) + zclose(obj->map_fds[j]); + obj->nr_map_fds = 0; + zfree(&obj->map_fds); + return err; } static int @@ -705,6 +749,8 @@ bpf_program__relocate(struct bpf_program *prog, int *map_fds) return -ERANGE; } insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; + if (map_fds[map_idx] == -1) + return -EINVAL; insns[insn_idx].imm = map_fds[map_idx]; } @@ -748,7 +794,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) Elf_Data *data = obj->efile.reloc[i].data; int idx = shdr->sh_info; struct bpf_program *prog; - size_t nr_maps = obj->maps_buf_sz / + size_t max_maps = obj->maps_buf_sz / sizeof(struct bpf_map_def); if (shdr->sh_type != SHT_REL) { @@ -763,7 +809,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) return -ENOENT; } - err = bpf_program__collect_reloc(prog, nr_maps, + err = bpf_program__collect_reloc(prog, max_maps, shdr, data, obj->efile.symbols); if (err) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 9fa7b09..8361dd5 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -10,6 +10,7 @@ #include #include +#include /* * In include/linux/compiler-gcc.h, __printf is defined. However @@ -100,4 +101,16 @@ struct bpf_map_def { unsigned int max_entries; }; +#define ATTR_LENGTH ((sizeof(struct perf_event_attr) + \ + sizeof(struct bpf_map_def) - 1) /\ + sizeof(struct bpf_map_def)) + +struct perf_event_map_def { + struct bpf_map_def map_def; + union { + struct perf_event_attr attr; + struct bpf_map_def align[ATTR_LENGTH]; + }; +}; + #endif -- 1.8.3.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/