From patchwork Sun Sep 6 07:13:20 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wang Nan X-Patchwork-Id: 53173 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-wi0-f197.google.com (mail-wi0-f197.google.com [209.85.212.197]) by patches.linaro.org (Postfix) with ESMTPS id CFF0C22B05 for ; Sun, 6 Sep 2015 07:15:56 +0000 (UTC) Received: by wicmn1 with SMTP id mn1sf17590560wic.1 for ; Sun, 06 Sep 2015 00:15:56 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:delivered-to:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-type:sender:precedence :list-id:x-original-sender:x-original-authentication-results :mailing-list:list-post:list-help:list-archive:list-unsubscribe; bh=i3WHNw3/6gqPYUFkoe+qP25u7lyYfcbzvZ2Xt3rl2Z4=; b=DDQErVQKd80HXou5hVeZUw2vIJog5sbZm9ufkdZLcRClIhXB/tSe8CnndOMxB0anrE OcCPfHFafTJRnwQUHqB5mDHnH+dldVWWyM+NDG5ZeatbQ/0BDtkW988oIvSUYhQnqR9s 6gmyP+Jcb8Bg/sUIKqzAYRVDXe8NOeKaS44tHb/wYoRJ3JiBdwjVvp0a0PZXsEtb9SVP s/BCN1980xldtXGfFDezaeGUf8j98TdQaYzYDpSWXCOXzJ5oJHjMaIDOmsYuy7ru/ZCx 5/QAeHLyt6tWhULl8arNC04kCmWw3+VxSBdIgi9oClYLKmzCN6XCfxpCFRdw4B96YZhk DIiA== X-Gm-Message-State: ALoCoQkLEnqjq+cSR2CSst+MWsYMTytw7i8hKSAXK51zDLkOwKWxgQe740ozZOqAaTaAeK5C2A68 X-Received: by 10.195.12.83 with SMTP id eo19mr3337334wjd.0.1441523756172; Sun, 06 Sep 2015 00:15:56 -0700 (PDT) X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.5.105 with SMTP id r9ls462481lar.15.gmail; Sun, 06 Sep 2015 00:15:56 -0700 (PDT) X-Received: by 10.152.6.194 with SMTP id d2mr11571965laa.93.1441523755974; Sun, 06 Sep 2015 00:15:55 -0700 (PDT) Received: from mail-la0-f45.google.com (mail-la0-f45.google.com. [209.85.215.45]) by mx.google.com with ESMTPS id gb9si7243200lbc.19.2015.09.06.00.15.55 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 06 Sep 2015 00:15:55 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.45 as permitted sender) client-ip=209.85.215.45; Received: by lagj9 with SMTP id j9so35903583lag.2 for ; Sun, 06 Sep 2015 00:15:55 -0700 (PDT) X-Received: by 10.152.5.228 with SMTP id v4mr11625733lav.36.1441523755819; Sun, 06 Sep 2015 00:15:55 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.164.42 with SMTP id yn10csp843643lbb; Sun, 6 Sep 2015 00:15:54 -0700 (PDT) X-Received: by 10.68.253.65 with SMTP id zy1mr30359160pbc.159.1441523752131; Sun, 06 Sep 2015 00:15:52 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id yr4si13732023pbc.140.2015.09.06.00.15.51; Sun, 06 Sep 2015 00:15:52 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752283AbbIFHPm (ORCPT + 28 others); Sun, 6 Sep 2015 03:15:42 -0400 Received: from szxga01-in.huawei.com ([58.251.152.64]:7360 "EHLO szxga01-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751167AbbIFHOl (ORCPT ); Sun, 6 Sep 2015 03:14:41 -0400 Received: from 172.24.1.48 (EHLO SZXEML423-HUB.china.huawei.com) ([172.24.1.48]) by szxrg01-dlp.huawei.com (MOS 4.3.7-GA FastPath queued) with ESMTP id CUK94020; Sun, 06 Sep 2015 15:14:05 +0800 (CST) Received: from linux-4hy3.site (10.107.193.248) by SZXEML423-HUB.china.huawei.com (10.82.67.154) with Microsoft SMTP Server id 14.3.235.1; Sun, 6 Sep 2015 15:13:57 +0800 From: Wang Nan To: , , , CC: , , , , , , , , , , , Subject: [PATCH 04/27] perf tools: Enable passing bpf object file to --event Date: Sun, 6 Sep 2015 07:13:20 +0000 Message-ID: <1441523623-152703-5-git-send-email-wangnan0@huawei.com> X-Mailer: git-send-email 1.8.3.4 In-Reply-To: <1441523623-152703-1-git-send-email-wangnan0@huawei.com> References: <1441523623-152703-1-git-send-email-wangnan0@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.107.193.248] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: wangnan0@huawei.com X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.45 as permitted sender) smtp.mailfrom=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , By introducing new rules in tools/perf/util/parse-events.[ly], this patch enables 'perf record --event bpf_file.o' to select events by an eBPF object file. It calls parse_events_load_bpf() to load that file, which uses bpf__prepare_load() and finally calls bpf_object__open() for the object files. Instead of introducing evsel to evlist during parsing, events selected by eBPF object files are appended separately. The reason is: 1. During parsing, the probing points have not been initialized. 2. Currently we are unable to call add_perf_probe_events() twice, therefore we have to wait until all such events are collected, then probe all points by one call. The real probing and selecting is reside in following patches. To make it compatible with other events, we insert a dummy event onto evlist. Its name field can be used to connect path of the object file. Since bpf__prepare_load() is possible to be called during cmdline parsing, all builtin commands which are possible to call parse_events_option() should release bpf resources during cleanup. Add bpf__clear() to stat, record, top and trace commands, although currently we are going to support 'perf record' only. Commiter note: Testing if the event parsing changes indeed call the BPF loading routines: [root@felicio ~]# ls -la foo.o ls: cannot access foo.o: No such file or directory [root@felicio ~]# perf record --event foo.o sleep libbpf: failed to open foo.o: No such file or directory bpf: failed to load foo.o invalid or unsupported event: 'foo.o' Run 'perf list' for a list of valid events usage: perf record [] [] or: perf record [] -- [] -e, --event event selector. use 'perf list' to list available events [root@felicio ~]# Yes, it does this time around. Signed-off-by: Wang Nan Acked-by: Alexei Starovoitov Tested-by: Arnaldo Carvalho de Melo Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/n/1436445342-1402-19-git-send-email-wangnan0@huawei.com [ The veprintf() and bpf loader parts were split from this one; Add bpf__clear() into stat, record, top and trace commands. Add dummy evsel as place holder of BPF objects. ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 7 ++++-- tools/perf/builtin-stat.c | 8 ++++-- tools/perf/builtin-top.c | 10 +++++--- tools/perf/builtin-trace.c | 6 ++++- tools/perf/util/Build | 1 + tools/perf/util/parse-events.c | 55 ++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/parse-events.h | 3 +++ tools/perf/util/parse-events.l | 3 +++ tools/perf/util/parse-events.y | 18 +++++++++++++- 9 files changed, 102 insertions(+), 9 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 142eeb3..f886706 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -31,6 +31,7 @@ #include "util/auxtrace.h" #include "util/parse-branch-options.h" #include "util/parse-regs-options.h" +#include "util/bpf-loader.h" #include #include @@ -1132,13 +1133,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) if (!rec->itr) { rec->itr = auxtrace_record__init(rec->evlist, &err); if (err) - return err; + goto out_bpf_clear; } err = auxtrace_parse_snapshot_options(rec->itr, &rec->opts, rec->opts.auxtrace_snapshot_opts); if (err) - return err; + goto out_bpf_clear; err = -ENOMEM; @@ -1201,6 +1202,8 @@ out_symbol_exit: perf_evlist__delete(rec->evlist); symbol__exit(); auxtrace_record__free(rec->itr); +out_bpf_clear: + bpf__clear(); return err; } diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 77e5781..65506eb 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -59,6 +59,7 @@ #include "util/thread.h" #include "util/thread_map.h" #include "util/counts.h" +#include "util/bpf-loader.h" #include #include @@ -1224,7 +1225,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) output = fopen(output_name, mode); if (!output) { perror("failed to create output file"); - return -1; + status = -1; + goto out; } clock_gettime(CLOCK_REALTIME, &tm); fprintf(output, "# started on %s\n", ctime(&tm.tv_sec)); @@ -1233,7 +1235,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) output = fdopen(output_fd, mode); if (!output) { perror("Failed opening logfd"); - return -errno; + status = -errno; + goto out; } } @@ -1366,5 +1369,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) perf_evlist__free_stats(evsel_list); out: perf_evlist__delete(evsel_list); + bpf__clear(); return status; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 8c465c8..384ca2e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -41,6 +41,7 @@ #include "util/sort.h" #include "util/intlist.h" #include "util/parse-branch-options.h" +#include "util/bpf-loader.h" #include "arch/common.h" #include "util/debug.h" @@ -1270,8 +1271,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) symbol_conf.priv_size = sizeof(struct annotation); symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); - if (symbol__init(NULL) < 0) - return -1; + if (symbol__init(NULL) < 0) { + status = -1; + goto out_bpf_clear; + } sort__setup_elide(stdout); @@ -1289,6 +1292,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) out_delete_evlist: perf_evlist__delete(top.evlist); - +out_bpf_clear: + bpf__clear(); return status; } diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 2156532..ac96242 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -31,6 +31,7 @@ #include "util/intlist.h" #include "util/thread_map.h" #include "util/stat.h" +#include "util/bpf-loader.h" #include "trace-event.h" #include "util/parse-events.h" @@ -3109,6 +3110,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) if (trace.evlist->nr_entries > 0) evlist__set_evsel_handler(trace.evlist, trace__event_handler); + /* trace__record calls cmd_record, which calls bpf__clear() */ if ((argc >= 1) && (strcmp(argv[0], "record") == 0)) return trace__record(&trace, argc-1, &argv[1]); @@ -3119,7 +3121,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) if (!trace.trace_syscalls && !trace.trace_pgfaults && trace.evlist->nr_entries == 0 /* Was --events used? */) { pr_err("Please specify something to trace.\n"); - return -1; + err = -1; + goto out; } if (output_name != NULL) { @@ -3178,5 +3181,6 @@ out_close: if (output_name != NULL) fclose(trace.output); out: + bpf__clear(); return err; } diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 349bc96..f5e9569 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -85,6 +85,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-bts.o libperf-y += parse-branch-options.o libperf-y += parse-regs-options.o +libperf-$(CONFIG_LIBBPF) += bpf-loader.o libperf-$(CONFIG_LIBELF) += symbol-elf.o libperf-$(CONFIG_LIBELF) += probe-file.o libperf-$(CONFIG_LIBELF) += probe-event.o diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 07ce501..b560f5f 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -19,6 +19,7 @@ #include "thread_map.h" #include "cpumap.h" #include "asm/bug.h" +#include "bpf-loader.h" #define MAX_NAME_LEN 100 @@ -481,6 +482,60 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, return add_tracepoint_event(list, idx, sys, event); } +int parse_events_load_bpf(struct parse_events_evlist *data, + struct list_head *list, + char *bpf_file_name) +{ + int err; + char errbuf[BUFSIZ]; + struct perf_evsel *dummy_evsel; + + /* + * Currently don't link useful event to list. BPF object files + * should be saved to a seprated list and processed together. + * + * Things could be changed if we solve perf probe reentering + * problem. After that probe events file by file is possible. + * However, probing cost is still need to be considered. + * + * We should still link something onto evlist to make it + * compatible with other events, or we have to find another + * way to collect --filter options and modifiers (currently + * modifiers are not allowed lexicically). evsel->tracking + * is another thing needs to be considered. Fortunately we have + * dummy evsel, which is originally designed for collecting + * evsel->tracking. + */ + err = parse_events_add_numeric(data, list, PERF_TYPE_SOFTWARE, + PERF_COUNT_SW_DUMMY, NULL); + if (err) + return err; + if (list_empty(list) || !list_is_singular(list)) { + data->error->str = strdup( + "Internal error: failed to alloc dummy evsel"); + return -ENOENT; + } + + dummy_evsel = list_entry(list->prev, struct perf_evsel, node); + + /* Give it a better name so we can connect this list to the object */ + zfree(&dummy_evsel->name); + dummy_evsel->name = strdup(bpf_file_name); + + err = bpf__prepare_load(bpf_file_name); + if (err) { + bpf__strerror_prepare_load(bpf_file_name, err, + errbuf, sizeof(errbuf)); + list_del_init(&dummy_evsel->node); + perf_evsel__delete(dummy_evsel); + data->error->str = strdup(errbuf); + data->error->help = strdup("(add -v to see detail)"); + return err; + } + + return 0; +} + static int parse_breakpoint_type(const char *type, struct perf_event_attr *attr) { diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index a09b0e2..3652387 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -119,6 +119,9 @@ int parse_events__modifier_group(struct list_head *list, char *event_mod); int parse_events_name(struct list_head *list, char *name); int parse_events_add_tracepoint(struct list_head *list, int *idx, char *sys, char *event); +int parse_events_load_bpf(struct parse_events_evlist *data, + struct list_head *list, + char *bpf_file_name); int parse_events_add_numeric(struct parse_events_evlist *data, struct list_head *list, u32 type, u64 config, diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 936d566..22e8f93 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -115,6 +115,7 @@ do { \ group [^,{}/]*[{][^}]*[}][^,{}/]* event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* event [^,{}/]+ +bpf_object .*\.(o|bpf) num_dec [0-9]+ num_hex 0x[a-fA-F0-9]+ @@ -159,6 +160,7 @@ modifier_bp [rwx]{1,3} } {event_pmu} | +{bpf_object} | {event} { BEGIN(INITIAL); REWIND(1); @@ -264,6 +266,7 @@ r{num_raw_hex} { return raw(yyscanner); } {num_hex} { return value(yyscanner, 16); } {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } +{bpf_object} { return str(yyscanner, PE_BPF_OBJECT); } {name} { return pmu_str_check(yyscanner); } "/" { BEGIN(config); return '/'; } - { return '-'; } diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 591905a..3ee3a32 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -42,6 +42,7 @@ static inc_group_count(struct list_head *list, %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM %token PE_EVENT_NAME %token PE_NAME +%token PE_BPF_OBJECT %token PE_MODIFIER_EVENT PE_MODIFIER_BP %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP @@ -53,6 +54,7 @@ static inc_group_count(struct list_head *list, %type PE_RAW %type PE_TERM %type PE_NAME +%type PE_BPF_OBJECT %type PE_NAME_CACHE_TYPE %type PE_NAME_CACHE_OP_RESULT %type PE_MODIFIER_EVENT @@ -69,6 +71,7 @@ static inc_group_count(struct list_head *list, %type event_legacy_tracepoint %type event_legacy_numeric %type event_legacy_raw +%type event_bpf_file %type event_def %type event_mod %type event_name @@ -198,7 +201,8 @@ event_def: event_pmu | event_legacy_mem | event_legacy_tracepoint sep_dc | event_legacy_numeric sep_dc | - event_legacy_raw sep_dc + event_legacy_raw sep_dc | + event_bpf_file event_pmu: PE_NAME '/' event_config '/' @@ -420,6 +424,18 @@ PE_RAW $$ = list; } +event_bpf_file: +PE_BPF_OBJECT +{ + struct parse_events_evlist *data = _data; + struct list_head *list; + + ALLOC_LIST(list); + ABORT_ON(parse_events_load_bpf(data, list, $1)); + $$ = list; +} + + start_terms: event_config { struct parse_events_terms *data = _data;