Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753302AbbK3Hjg (ORCPT ); Mon, 30 Nov 2015 02:39:36 -0500 Received: from szxga01-in.huawei.com ([58.251.152.64]:28555 "EHLO szxga01-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753251AbbK3Hcj (ORCPT ); Mon, 30 Nov 2015 02:32:39 -0500 From: Wang Nan To: , , , CC: , , , Wang Nan , Arnaldo Carvalho de Melo Subject: [PATCH v3 08/13] perf tools: Enable indices setting syntax for BPF maps Date: Mon, 30 Nov 2015 07:32:08 +0000 Message-ID: <1448868733-225582-9-git-send-email-wangnan0@huawei.com> X-Mailer: git-send-email 1.8.3.4 In-Reply-To: <1448868733-225582-1-git-send-email-wangnan0@huawei.com> References: <1448868733-225582-1-git-send-email-wangnan0@huawei.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.107.193.248] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A090201.565BFB94.005C,ss=1,re=0.000,recu=0.000,reip=0.000,cl=1,cld=1,fgs=0, ip=0.0.0.0, so=2013-06-18 04:22:30, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: 8ff6328f2fe9eccbaf5414748c49ce58 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8906 Lines: 291 This patch introduce a new syntax to perf event parser: # perf record -e bpf_file.c/maps.mymap.value[0,3...5,7]=1234/ ... By utilizing the basic facilities in bpf-loader.c which allow setting different slots in a BPF map separately, the newly introduced syntax allows perf to control specific elements in a BPF map. Test result: # cat ./test_bpf_map_3.c /************************ BEGIN **************************/ #define SEC(NAME) __attribute__((section(NAME), used)) enum bpf_map_type { BPF_MAP_TYPE_ARRAY = 2, }; struct bpf_map_def { unsigned int type; unsigned int key_size; unsigned int value_size; unsigned int max_entries; }; static void *(*map_lookup_elem)(struct bpf_map_def *, void *) = (void *)1; static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = (void *)6; struct bpf_map_def SEC("maps") channel = { .type = BPF_MAP_TYPE_ARRAY, .key_size = sizeof(int), .value_size = sizeof(unsigned char), .max_entries = 100, }; SEC("func=hrtimer_nanosleep rqtp->tv_nsec") int func(void *ctx, int err, long nsec) { char fmt[] = "%ld\n"; long usec = nsec * 0x10624dd3 >> 38; // nsec / 1000 int key = (int)usec; unsigned char *pval = map_lookup_elem(&channel, &key); if (!pval) return 0; bpf_trace_printk(fmt, sizeof(fmt), (unsigned char)*pval); return 0; } char _license[] SEC("license") = "GPL"; int _version SEC("version") = LINUX_VERSION_CODE; /************************* END ***************************/ Normal case: # echo "" > /sys/kernel/debug/tracing/trace # ./perf record -e './test_bpf_map_3.c/maps:channel.value[0,1,2,3...5]=101/' usleep 2 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.012 MB perf.data ] # cat /sys/kernel/debug/tracing/trace | grep usleep usleep-405 [004] d... 2745423.547822: : 101 # ./perf record -e './test_bpf_map_3.c/maps:channel.value[0...9,20...29]=102,maps:channel.value[10...19]=103/' usleep 3 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.012 MB perf.data ] # ./perf record -e './test_bpf_map_3.c/maps:channel.value[0...9,20...29]=102,maps:channel.value[10...19]=103/' usleep 15 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.012 MB perf.data ] # cat /sys/kernel/debug/tracing/trace | grep usleep usleep-405 [004] d... 2745423.547822: : 101 usleep-655 [006] d... 2745434.122814: : 102 usleep-904 [006] d... 2745439.916264: : 103 # ./perf record -e './test_bpf_map_3.c/maps:channel.value[all]=104/' usleep 99 # cat /sys/kernel/debug/tracing/trace | grep usleep usleep-405 [004] d... 2745423.547822: : 101 usleep-655 [006] d... 2745434.122814: : 102 usleep-904 [006] d... 2745439.916264: : 103 usleep-1537 [003] d... 2745538.053737: : 104 Error case: # ./perf record -e './test_bpf_map_3.c/maps:channel.value[10...1000]=104/' usleep 99 event syntax error: '..annel.value[10...1000]=104/' \___ Index too large Hint: Valid config terms: maps:[].value=[value] maps:[].event=[event] where is something like [0,3...5] or [all] (add -v to see detail) 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 Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Arnaldo Carvalho de Melo Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com --- tools/perf/util/parse-events.c | 5 ++- tools/perf/util/parse-events.l | 13 ++++++- tools/perf/util/parse-events.y | 85 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index af3d657..c485b32 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -660,9 +660,10 @@ parse_events_config_bpf(struct parse_events_evlist *data, sizeof(errbuf)); data->error->help = strdup( "Hint:\tValid config terms:\n" -" \tmaps:[].value=[value]\n" -" \tmaps:[].event=[event]\n" +" \tmaps:[].value=[value]\n" +" \tmaps:[].event=[event]\n" "\n" +" \twhere is something like [0,3...5] or [all]\n" " \t(add -v to see detail)"); data->error->str = strdup(errbuf); if (err == -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE) diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 4387728..8bb3437 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -9,8 +9,8 @@ %{ #include #include "../perf.h" -#include "parse-events-bison.h" #include "parse-events.h" +#include "parse-events-bison.h" char *parse_events_get_text(yyscan_t yyscanner); YYSTYPE *parse_events_get_lval(yyscan_t yyscanner); @@ -111,6 +111,7 @@ do { \ %x mem %s config %x event +%x array group [^,{}/]*[{][^}]*[}][^,{}/]* event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* @@ -176,6 +177,14 @@ modifier_bp [rwx]{1,3} } +{ +"]" { BEGIN(config); return ']'; } +{num_dec} { return value(yyscanner, 10); } +{num_hex} { return value(yyscanner, 16); } +, { return ','; } +"\.\.\." { return PE_ARRAY_RANGE; } +} + { /* * Please update parse_events_formats_error_string any time @@ -196,6 +205,8 @@ no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } , { return ','; } "/" { BEGIN(INITIAL); return '/'; } {name_minus} { return str(yyscanner, PE_NAME); } +\[all\] { return PE_ARRAY_ALL; } +"[" { BEGIN(array); return '['; } } { diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index c3cbd7a..7e93b9f 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -48,6 +48,7 @@ static inc_group_count(struct list_head *list, %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP %token PE_ERROR %token PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT +%token PE_ARRAY_ALL PE_ARRAY_RANGE %type PE_VALUE %type PE_VALUE_SYM_HW %type PE_VALUE_SYM_SW @@ -84,6 +85,9 @@ static inc_group_count(struct list_head *list, %type group_def %type group %type groups +%type array +%type array_term +%type array_terms %union { @@ -95,6 +99,7 @@ static inc_group_count(struct list_head *list, char *sys; char *event; } tracepoint_name; + struct parse_events_array array; } %% @@ -601,6 +606,86 @@ PE_TERM ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1, &@1, NULL)); $$ = term; } +| +PE_NAME array '=' PE_NAME +{ + struct parse_events_term *term; + int i; + + ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, + $1, $4, &@1, &@4)); + + term->array = $2; + $$ = term; +} +| +PE_NAME array '=' PE_VALUE +{ + struct parse_events_term *term; + + ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, + $1, $4, &@1, &@4)); + term->array = $2; + $$ = term; +} + +array: +'[' array_terms ']' +{ + $$ = $2; +} +| +PE_ARRAY_ALL +{ + $$.nr_ranges = 0; + $$.ranges = NULL; +} + +array_terms: +array_terms ',' array_term +{ + struct parse_events_array new_array; + + new_array.nr_ranges = $1.nr_ranges + $3.nr_ranges; + new_array.ranges = malloc(sizeof(new_array.ranges[0]) * + new_array.nr_ranges); + ABORT_ON(!new_array.ranges); + memcpy(&new_array.ranges[0], $1.ranges, + $1.nr_ranges * sizeof(new_array.ranges[0])); + memcpy(&new_array.ranges[$1.nr_ranges], $3.ranges, + $3.nr_ranges * sizeof(new_array.ranges[0])); + free($1.ranges); + free($3.ranges); + $$ = new_array; +} +| +array_term + +array_term: +PE_VALUE +{ + struct parse_events_array array; + + array.nr_ranges = 1; + array.ranges = malloc(sizeof(array.ranges[0])); + ABORT_ON(!array.ranges); + array.ranges[0].start = $1; + array.ranges[0].length = 1; + $$ = array; +} +| +PE_VALUE PE_ARRAY_RANGE PE_VALUE +{ + struct parse_events_array array; + + ABORT_ON($3 < $1); + array.nr_ranges = 1; + array.ranges = malloc(sizeof(array.ranges[0])); + ABORT_ON(!array.ranges); + array.ranges[0].start = $1; + array.ranges[0].length = $3 - $1 + 1; + $$ = array; +} sep_dc: ':' | -- 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/