Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1291097 > unrolled thread

[PATCH v5 00/14] perf tools: BPF related update and other improvements

Started byWang Nan <wangnan0@huawei.com>
First post2015-12-14 11:50 +0100
Last post2015-12-18 10:00 +0100
Articles 16 — 5 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v5 00/14] perf tools: BPF related update and other improvements Wang Nan <wangnan0@huawei.com> - 2015-12-14 11:50 +0100
    [PATCH v5 08/14] perf tools: Support perf event alias name Wang Nan <wangnan0@huawei.com> - 2015-12-14 11:50 +0100
      Re: [PATCH v5 08/14] perf tools: Support perf event alias name Jiri Olsa <jolsa@redhat.com> - 2015-12-15 14:20 +0100
        Re: [PATCH v5 08/14] perf tools: Support perf event alias name "Wangnan (F)" <wangnan0@huawei.com> - 2015-12-16 03:00 +0100
    [PATCH v5 10/14] perf tools: Enable indices setting syntax for BPF maps Wang Nan <wangnan0@huawei.com> - 2015-12-14 11:50 +0100
      Re: [PATCH v5 10/14] perf tools: Enable indices setting syntax for  BPF maps Jiri Olsa <jolsa@redhat.com> - 2015-12-15 14:50 +0100
        Re: [PATCH v5 10/14] perf tools: Enable indices setting syntax for  BPF maps "Wangnan (F)" <wangnan0@huawei.com> - 2015-12-16 03:10 +0100
          Re: [PATCH v5 10/14] perf tools: Enable indices setting syntax for  BPF maps Jiri Olsa <jolsa@redhat.com> - 2015-12-16 09:00 +0100
      Re: [PATCH v5 10/14] perf tools: Enable indices setting syntax for  BPF maps Jiri Olsa <jolsa@redhat.com> - 2015-12-16 12:30 +0100
    [PATCH v5 05/14] perf tools: Enable BPF object configure syntax Wang Nan <wangnan0@huawei.com> - 2015-12-14 11:50 +0100
      Re: [PATCH v5 05/14] perf tools: Enable BPF object configure syntax Jiri Olsa <jolsa@redhat.com> - 2015-12-15 14:20 +0100
    [PATCH v5 01/14] perf tests: Fix incorrect free and false TEST_OK result Wang Nan <wangnan0@huawei.com> - 2015-12-14 11:50 +0100
    [PATCH v5 09/14] perf tools: Support setting different slots in a BPF map separately Wang Nan <wangnan0@huawei.com> - 2015-12-14 11:50 +0100
    [PATCH v5 13/14] perf tools: Always give options even it not compiled Wang Nan <wangnan0@huawei.com> - 2015-12-14 11:50 +0100
      Re: [PATCH v5 13/14] perf tools: Always give options even it not  compiled Arnaldo Carvalho de Melo <acme@kernel.org> - 2015-12-14 17:10 +0100
      [tip:perf/core] perf tools: Make options always available,   even if required libs not linked tip-bot for Wang Nan <tipbot@zytor.com> - 2015-12-18 10:00 +0100

#1291097 — [PATCH v5 00/14] perf tools: BPF related update and other improvements

FromWang Nan <wangnan0@huawei.com>
Date2015-12-14 11:50 +0100
Subject[PATCH v5 00/14] perf tools: BPF related update and other improvements
Message-ID<qFyRz-4Xv-7@gated-at.bofh.it>
Hi Arnaldo,

   Based on your suggestion here is v5. In this patchset:

   - Change patch order so patch 8/14 (event alias) won't confuse you.

   - Examples in commit messages are updated to use <uapi/linux/bpf.h>.

   - Update warning/error messages in 13/14.

   - 'perf test bpf' won't report 'FAILED!' on old kernel. Instead report 'Skip'.

   - Add Jiri Olsa to cc-list for every patches.

Thank you.

Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com

He Kuang (2):
  perf tools: Support perf event alias name
  perf record: Support custom vmlinux path

Wang Nan (12):
  perf tests: Fix incorrect free and false TEST_OK result
  perf tools: Prevent calling machine__delete() on non-allocated machine
  perf test: Check environment before start real BPF test
  perf tools: Add API to config maps in bpf object
  perf tools: Enable BPF object configure syntax
  perf record: Apply config to BPF objects before recording
  perf tools: Enable passing event to BPF object
  perf tools: Support setting different slots in a BPF map separately
  perf tools: Enable indices setting syntax for BPF maps
  perf tools: Introduce bpf-output event
  perf data: Support converting data from bpf_perf_event_output()
  perf tools: Always give options even it not compiled

 tools/perf/Documentation/perf-record.txt |  10 +-
 tools/perf/builtin-probe.c               |  15 +-
 tools/perf/builtin-record.c              |  36 +-
 tools/perf/tests/bpf.c                   |  37 ++
 tools/perf/tests/hists_common.c          |  15 +-
 tools/perf/tests/hists_common.h          |   1 +
 tools/perf/tests/hists_cumulate.c        |   6 +-
 tools/perf/tests/hists_filter.c          |   6 +-
 tools/perf/tests/hists_link.c            |   6 +-
 tools/perf/tests/hists_output.c          |   6 +-
 tools/perf/tests/vmlinux-kallsyms.c      |   4 +-
 tools/perf/util/bpf-loader.c             | 700 +++++++++++++++++++++++++++++++
 tools/perf/util/bpf-loader.h             |  59 +++
 tools/perf/util/data-convert-bt.c        | 115 ++++-
 tools/perf/util/evlist.c                 |  16 +
 tools/perf/util/evlist.h                 |   3 +
 tools/perf/util/evsel.c                  |   7 +
 tools/perf/util/evsel.h                  |   1 +
 tools/perf/util/machine.c                |  14 +-
 tools/perf/util/machine.h                |   3 +-
 tools/perf/util/parse-events.c           | 125 +++++-
 tools/perf/util/parse-events.h           |  20 +-
 tools/perf/util/parse-events.l           |  16 +-
 tools/perf/util/parse-events.y           | 123 +++++-
 tools/perf/util/parse-options.c          | 118 +++++-
 tools/perf/util/parse-options.h          |   5 +
 26 files changed, 1419 insertions(+), 48 deletions(-)

-- 
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/

[toc] | [next] | [standalone]


#1291098 — [PATCH v5 08/14] perf tools: Support perf event alias name

FromWang Nan <wangnan0@huawei.com>
Date2015-12-14 11:50 +0100
Subject[PATCH v5 08/14] perf tools: Support perf event alias name
Message-ID<qFyRA-4Xv-23@gated-at.bofh.it>
In reply to#1291097
From: He Kuang <hekuang@huawei.com>

This patch is useful when trying to pass a perf event to BPF map.
Before this patch we are unable to pass an event with config term to
BPF maps. For example:

 # perf record -a -e cycles/no-inherit,period=0x7fffffffffffffff/ \
                  -e './test_bpf_map_2.c/maps:pmu_map.event=cycles/no-inherit,period=0x7fffffffffffffff//' ls /
 event syntax error: '..ps:pmu_map.event=cycles/'
                                   \___ Event not found for map setting

Because those '/' and ',' embarrass parser.

This patch adds new bison rules for specifying an alias name to a perf
event, which allows cmdline refer to previous defined perf event through
its name. With this patch user can give alias name to a perf event using
following cmdline. The above goal can be achieved using:

 # perf record -a -e cyc=cycles/no-inherit,period=0x7fffffffffffffff/ \
                  -e './test_bpf_map_2.c/maps:pmu_map.event=cyc/' ls /

If alias is not provided (normal case):

 # perf record -e cycles ...

It will be set to event's name automatically ('cycles' in the above
example).

To allow parser refer to existing event selector, pass event list to
'struct parse_events_evlist'. perf_evlist__find_evsel_by_alias() is
introduced to get evsel through its alias.

Test result:
 # cat ./test_bpf_map_2.c
 /************************ BEGIN **************************/
 #include <uapi/linux/bpf.h>
 #define SEC(NAME) __attribute__((section(NAME), used))
 struct bpf_map_def {
     unsigned int type;
     unsigned int key_size;
     unsigned int value_size;
     unsigned int max_entries;
 };
 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_read)(struct bpf_map_def *, int) =
     (void *)BPF_FUNC_perf_event_read;

 struct bpf_map_def SEC("maps") pmu_map = {
     .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
     .key_size = sizeof(int),
     .value_size = sizeof(int),
     .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 = perf_event_read(&pmu_map, get_smp_processor_id());
     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 = perf_event_read(&pmu_map, get_smp_processor_id());
     trace_printk(fmt, sizeof(fmt), val);
     return 0;
 }
 char _license[] SEC("license") = "GPL";
 int _version SEC("version") = LINUX_VERSION_CODE;
 /************************* END ***************************/
 # echo "" > /sys/kernel/debug/tracing/trace
 # ./perf record -a -e cyc=cycles/no-inherit,period=0x7fffffffffffffff/ \
                    -e './test_bpf_map_2.c/maps:pmu_map.event=cyc/' ls /
 [ perf record: Woken up 1 times to write data ]
 [ perf record: Captured and wrote 0.755 MB perf.data ]
 # cat /sys/kernel/debug/tracing/trace | grep ls
               ls-25328 [002] d... 940138.313178: : sys_write:        pmu=4503165
               ls-25328 [002] dN.. 940138.313207: : sys_write_return: pmu=4582975
               ls-25328 [002] d... 940138.313211: : sys_write:        pmu=4599840
               ls-25328 [002] dN.. 940138.313220: : sys_write_return: pmu=4633352
 # ./perf report --stdio
 Error:
 The perf.data file has no samples!
 ...
 (This is expected because we set period of cycles to a very large
 value to period of cycles event because we want to use this event
 as a counter only, don't need sampling)

 # ./perf record -e cycles -e './test_bpf_map_2.c/maps:pmu_map.event=cycles/' ls /
 ERROR: Apply config to BPF failed: Doesn't support inherit event (Hint: use -i or use /no-inherit/ to turn off inherit)

Signed-off-by: He Kuang <hekuang@huawei.com>
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
---
 tools/perf/util/bpf-loader.c   |  2 +-
 tools/perf/util/evlist.c       |  4 ++--
 tools/perf/util/evsel.c        |  1 +
 tools/perf/util/evsel.h        |  1 +
 tools/perf/util/parse-events.c | 26 ++++++++++++++++++++++++++
 tools/perf/util/parse-events.h |  4 ++++
 tools/perf/util/parse-events.y | 15 ++++++++++++++-
 7 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 84b4581..2893b4e 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -1448,7 +1448,7 @@ int bpf__strerror_apply_obj_config(int err, char *buf, size_t size)
 	bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM,
 			    "Cannot set event to BPF maps in multi-thread tracing");
 	bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH,
-			    "%s (Hint: use -i to turn off inherit)", emsg);
+			    "%s (Hint: use -i or use /no-inherit/ to turn off inherit)", emsg);
 	bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE,
 			    "Can only put raw, hardware and BPF output event into a BPF map");
 	bpf__strerror_end(buf, size);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index d0a75c6..b65a941 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1745,9 +1745,9 @@ perf_evlist__find_evsel_by_str(struct perf_evlist *evlist,
 	struct perf_evsel *evsel;
 
 	evlist__for_each(evlist, evsel) {
-		if (!evsel->name)
+		if (!evsel->alias)
 			continue;
-		if (strcmp(str, evsel->name) == 0)
+		if (strcmp(str, evsel->alias) == 0)
 			return evsel;
 	}
 
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 47f0330..8e0e6f4 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1073,6 +1073,7 @@ void perf_evsel__exit(struct perf_evsel *evsel)
 	thread_map__put(evsel->threads);
 	zfree(&evsel->group_name);
 	zfree(&evsel->name);
+	zfree(&evsel->alias);
 	perf_evsel__object.fini(evsel);
 }
 
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 5ded1fc..5f6dd57 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -89,6 +89,7 @@ struct perf_evsel {
 	int			idx;
 	u32			ids;
 	char			*name;
+	char			*alias;
 	double			scale;
 	const char		*unit;
 	struct event_format	*tp_format;
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index a69c871..5d682dd 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1091,6 +1091,30 @@ int parse_events__modifier_group(struct list_head *list,
 	return parse_events__modifier_event(list, event_mod, true);
 }
 
+int parse_events__set_event_alias(struct parse_events_evlist *data,
+				  struct list_head *list,
+				  const char *str,
+				  void *loc_alias_)
+{
+	struct perf_evsel *evsel;
+	YYLTYPE *loc_alias = loc_alias_;
+
+	if (!str)
+		return 0;
+
+	if (!list_is_singular(list)) {
+		struct parse_events_error *err = data->error;
+
+		err->idx = loc_alias->first_column;
+		err->str = strdup("One alias can be applied to one event only");
+		return -EINVAL;
+	}
+
+	evsel = list_first_entry(list, struct perf_evsel, node);
+	evsel->alias = strdup(str);
+	return evsel->alias ? 0 : -ENOMEM;
+}
+
 void parse_events__set_leader(char *name, struct list_head *list)
 {
 	struct perf_evsel *leader;
@@ -1283,6 +1307,8 @@ int parse_events_name(struct list_head *list, char *name)
 	__evlist__for_each(list, evsel) {
 		if (!evsel->name)
 			evsel->name = strdup(name);
+		if (!evsel->alias)
+			evsel->alias = strdup(name);
 	}
 
 	return 0;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 2a2b172..20ad3c2 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -172,4 +172,8 @@ extern int is_valid_tracepoint(const char *event_string);
 int valid_event_mount(const char *eventfs);
 char *parse_events_formats_error_string(char *additional_terms);
 
+int parse_events__set_event_alias(struct parse_events_evlist *data,
+				  struct list_head *list,
+				  const char *str,
+				  void *loc_alias_);
 #endif /* __PERF_PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 8992d16..c3cbd7a 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -77,6 +77,7 @@ static inc_group_count(struct list_head *list,
 %type <head> event_bpf_file
 %type <head> event_def
 %type <head> event_mod
+%type <head> event_alias
 %type <head> event_name
 %type <head> event
 %type <head> events
@@ -193,13 +194,25 @@ event_name PE_MODIFIER_EVENT
 event_name
 
 event_name:
-PE_EVENT_NAME event_def
+PE_EVENT_NAME event_alias
 {
 	ABORT_ON(parse_events_name($2, $1));
 	free($1);
 	$$ = $2;
 }
 |
+event_alias
+
+event_alias:
+PE_NAME '=' event_def
+{
+	struct list_head *list = $3;
+	struct parse_events_evlist *data = _data;
+
+	ABORT_ON(parse_events__set_event_alias(data, list, $1, &@1));
+	$$ = list;
+}
+|
 event_def
 
 event_def: event_pmu |
-- 
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/

[toc] | [prev] | [next] | [standalone]


#1292171 — Re: [PATCH v5 08/14] perf tools: Support perf event alias name

FromJiri Olsa <jolsa@redhat.com>
Date2015-12-15 14:20 +0100
SubjectRe: [PATCH v5 08/14] perf tools: Support perf event alias name
Message-ID<qFXGi-4AF-19@gated-at.bofh.it>
In reply to#1291098
On Mon, Dec 14, 2015 at 10:39:17AM +0000, Wang Nan wrote:
> From: He Kuang <hekuang@huawei.com>
> 
> This patch is useful when trying to pass a perf event to BPF map.
> Before this patch we are unable to pass an event with config term to
> BPF maps. For example:
> 
>  # perf record -a -e cycles/no-inherit,period=0x7fffffffffffffff/ \
>                   -e './test_bpf_map_2.c/maps:pmu_map.event=cycles/no-inherit,period=0x7fffffffffffffff//' ls /
>  event syntax error: '..ps:pmu_map.event=cycles/'
>                                    \___ Event not found for map setting
> 
> Because those '/' and ',' embarrass parser.

we already have 'name=' term, but it's only for pmu events,
so I think your solution is better

> 
> This patch adds new bison rules for specifying an alias name to a perf
> event, which allows cmdline refer to previous defined perf event through
> its name. With this patch user can give alias name to a perf event using
> following cmdline. The above goal can be achieved using:
> 
>  # perf record -a -e cyc=cycles/no-inherit,period=0x7fffffffffffffff/ \
>                   -e './test_bpf_map_2.c/maps:pmu_map.event=cyc/' ls /
> 

so this alias should only help as a quick pointer
to setup the record session, right?

I'm not sure we want to see it as a part of name being stored
to perf.data and displayed by perf report and stat

  $ ./perf stat -e cyc=cycles ls

    Performance counter stats for 'ls':

         2,638,646      cyc=cycles                                                  

       0.001111614 seconds time elapsed

but I guess when you probably have a reason to use that
you want to see it in your report..  just a thought ;-)

anyway acking the change

Acked-by: Jiri Olsa <jolsa@kernel.org>

thanks,
jirka
--
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/

[toc] | [prev] | [next] | [standalone]


#1292695 — Re: [PATCH v5 08/14] perf tools: Support perf event alias name

From"Wangnan (F)" <wangnan0@huawei.com>
Date2015-12-16 03:00 +0100
SubjectRe: [PATCH v5 08/14] perf tools: Support perf event alias name
Message-ID<qG9xM-3JD-7@gated-at.bofh.it>
In reply to#1292171

On 2015/12/15 21:18, Jiri Olsa wrote:
> On Mon, Dec 14, 2015 at 10:39:17AM +0000, Wang Nan wrote:
>> From: He Kuang <hekuang@huawei.com>
>>
>> This patch is useful when trying to pass a perf event to BPF map.
>> Before this patch we are unable to pass an event with config term to
>> BPF maps. For example:
>>
>>   # perf record -a -e cycles/no-inherit,period=0x7fffffffffffffff/ \
>>                    -e './test_bpf_map_2.c/maps:pmu_map.event=cycles/no-inherit,period=0x7fffffffffffffff//' ls /
>>   event syntax error: '..ps:pmu_map.event=cycles/'
>>                                     \___ Event not found for map setting
>>
>> Because those '/' and ',' embarrass parser.
> we already have 'name=' term, but it's only for pmu events,
> so I think your solution is better

Thanks.
>
>> This patch adds new bison rules for specifying an alias name to a perf
>> event, which allows cmdline refer to previous defined perf event through
>> its name. With this patch user can give alias name to a perf event using
>> following cmdline. The above goal can be achieved using:
>>
>>   # perf record -a -e cyc=cycles/no-inherit,period=0x7fffffffffffffff/ \
>>                    -e './test_bpf_map_2.c/maps:pmu_map.event=cyc/' ls /
>>
> so this alias should only help as a quick pointer
> to setup the record session, right?

Yes.

> I'm not sure we want to see it as a part of name being stored
> to perf.data and displayed by perf report and stat
>
>    $ ./perf stat -e cyc=cycles ls
>
>      Performance counter stats for 'ls':
>
>           2,638,646      cyc=cycles
>
>         0.001111614 seconds time elapsed
>
> but I guess when you probably have a reason to use that
> you want to see it in your report..  just a thought ;-)

I thought about this problem. It seems useful. In following patches we will
support BPF output. Thinking about this case:

  # perf record -a -i -e a=bpf-output -e b=bpf-output \
                      -e mybpf.c/dataA=a,dataB=b/ ...

Here we pass two bpf-output events to the BPF script, they have different
meaning. For example, 'a' reports instructions costed by one function, 'b'
reports time between two events. We use CTF python binding to deal with
this report. Then aliases is a indicator to tell us which event is for what.
Without them we have to put some magic number in output data.

Thank you.

> anyway acking the change
>
> Acked-by: Jiri Olsa <jolsa@kernel.org>
>
> thanks,
> jirka


--
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/

[toc] | [prev] | [next] | [standalone]


#1291099 — [PATCH v5 10/14] perf tools: Enable indices setting syntax for BPF maps

FromWang Nan <wangnan0@huawei.com>
Date2015-12-14 11:50 +0100
Subject[PATCH v5 10/14] perf tools: Enable indices setting syntax for BPF maps
Message-ID<qFyRA-4Xv-21@gated-at.bofh.it>
In reply to#1291097
This patch introduce a new syntax to perf event parser:

 # perf record -e './test_bpf_map_3.c/maps:channel.value[0,1,2,3...5]=101/' usleep 2

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 **************************/
 #include <uapi/linux/bpf.h>
 #define SEC(NAME) __attribute__((section(NAME), used))
 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 *)BPF_FUNC_map_lookup_elem;
 static int (*trace_printk)(const char *fmt, int fmt_size, ...) =
 	(void *)BPF_FUNC_trace_printk;
 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;
 	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:[<arraymap>].value<indices>=[value]
      	maps:[<eventmap>].event<indices>=[event]

      	where <indices> 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 [<options>] [<command>]
     or: perf record [<options>] -- <command> [<options>]

     -e, --event <event>   event selector. use 'perf list' to list available events

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
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..abdf551 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:[<arraymap>].value=[value]\n"
-"     \tmaps:[<eventmap>].event=[event]\n"
+"     \tmaps:[<arraymap>].value<indices>=[value]\n"
+"     \tmaps:[<eventmap>].event<indices>=[event]\n"
 "\n"
+"     \twhere <indices> 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 <errno.h>
 #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}
 
 }
 
+<array>{
+"]"			{ BEGIN(config); return ']'; }
+{num_dec}		{ return value(yyscanner, 10); }
+{num_hex}		{ return value(yyscanner, 16); }
+,			{ return ','; }
+"\.\.\."		{ return PE_ARRAY_RANGE; }
+}
+
 <config>{
 	/*
 	 * 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 '['; }
 }
 
 <mem>{
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 <num> PE_VALUE
 %type <num> PE_VALUE_SYM_HW
 %type <num> PE_VALUE_SYM_SW
@@ -84,6 +85,9 @@ static inc_group_count(struct list_head *list,
 %type <head> group_def
 %type <head> group
 %type <head> groups
+%type <array> array
+%type <array> array_term
+%type <array> 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/

[toc] | [prev] | [next] | [standalone]


#1292195 — Re: [PATCH v5 10/14] perf tools: Enable indices setting syntax for BPF maps

FromJiri Olsa <jolsa@redhat.com>
Date2015-12-15 14:50 +0100
SubjectRe: [PATCH v5 10/14] perf tools: Enable indices setting syntax for BPF maps
Message-ID<qFY9k-4Mo-11@gated-at.bofh.it>
In reply to#1291099
On Mon, Dec 14, 2015 at 10:39:19AM +0000, Wang Nan wrote:
> This patch introduce a new syntax to perf event parser:
> 
>  # perf record -e './test_bpf_map_3.c/maps:channel.value[0,1,2,3...5]=101/' usleep 2

why 3 dots? I'd think the standard is 2 ? just curious
  [0,1,2,3..5]
3 made me think there's something speecial about it ;-)


jirka
--
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/

[toc] | [prev] | [next] | [standalone]


#1292698 — Re: [PATCH v5 10/14] perf tools: Enable indices setting syntax for BPF maps

From"Wangnan (F)" <wangnan0@huawei.com>
Date2015-12-16 03:10 +0100
SubjectRe: [PATCH v5 10/14] perf tools: Enable indices setting syntax for BPF maps
Message-ID<qG9Hr-429-3@gated-at.bofh.it>
In reply to#1292195

On 2015/12/15 21:42, Jiri Olsa wrote:
> On Mon, Dec 14, 2015 at 10:39:19AM +0000, Wang Nan wrote:
>> This patch introduce a new syntax to perf event parser:
>>
>>   # perf record -e './test_bpf_map_3.c/maps:channel.value[0,1,2,3...5]=101/' usleep 2
> why 3 dots? I'd think the standard is 2 ?

The standard (actually it is a gcc extension, not C standard) is 3 dots.
Please have a look at [1] and [2]. Although I also think '..' is better.

So after you seeing this, do you still think we should follow our
intuition instead of following GCC? If you still prefer '..' I'll
change it.

Thank you.

[1] https://lkml.org/lkml/2015/11/23/4
[2] https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html

Thank you.

> just curious
>    [0,1,2,3..5]
> 3 made me think there's something speecial about it ;-)
>
>
> jirka


--
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/

[toc] | [prev] | [next] | [standalone]


#1292805 — Re: [PATCH v5 10/14] perf tools: Enable indices setting syntax for BPF maps

FromJiri Olsa <jolsa@redhat.com>
Date2015-12-16 09:00 +0100
SubjectRe: [PATCH v5 10/14] perf tools: Enable indices setting syntax for BPF maps
Message-ID<qGfa9-7nA-1@gated-at.bofh.it>
In reply to#1292698
On Wed, Dec 16, 2015 at 10:02:28AM +0800, Wangnan (F) wrote:
> 
> 
> On 2015/12/15 21:42, Jiri Olsa wrote:
> >On Mon, Dec 14, 2015 at 10:39:19AM +0000, Wang Nan wrote:
> >>This patch introduce a new syntax to perf event parser:
> >>
> >>  # perf record -e './test_bpf_map_3.c/maps:channel.value[0,1,2,3...5]=101/' usleep 2
> >why 3 dots? I'd think the standard is 2 ?
> 
> The standard (actually it is a gcc extension, not C standard) is 3 dots.
> Please have a look at [1] and [2]. Although I also think '..' is better.
> 
> So after you seeing this, do you still think we should follow our
> intuition instead of following GCC? If you still prefer '..' I'll
> change it.

I'm ok with '...'

I think I only thought about '..' as a standard because of the way I use git log ;-)

thanks,
jirka

> 
> Thank you.
> 
> [1] https://lkml.org/lkml/2015/11/23/4
> [2] https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html
> 
> Thank you.
> 
> >just curious
> >   [0,1,2,3..5]
> >3 made me think there's something speecial about it ;-)
> >
> >
> >jirka
> 
> 
--
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/

[toc] | [prev] | [next] | [standalone]


#1292912 — Re: [PATCH v5 10/14] perf tools: Enable indices setting syntax for BPF maps

FromJiri Olsa <jolsa@redhat.com>
Date2015-12-16 12:30 +0100
SubjectRe: [PATCH v5 10/14] perf tools: Enable indices setting syntax for BPF maps
Message-ID<qGirp-175-45@gated-at.bofh.it>
In reply to#1291099
On Mon, Dec 14, 2015 at 10:39:19AM +0000, Wang Nan wrote:

SNIP

>  # 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:[<arraymap>].value<indices>=[value]
>       	maps:[<eventmap>].event<indices>=[event]
> 
>       	where <indices> 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 [<options>] [<command>]
>      or: perf record [<options>] -- <command> [<options>]
> 
>      -e, --event <event>   event selector. use 'perf list' to list available events
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> Cc: Alexei Starovoitov <ast@kernel.org>
> Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
> Cc: Jiri Olsa <jolsa@kernel.org>
> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Cc: Namhyung Kim <namhyung@kernel.org>
> Cc: Zefan Li <lizefan@huawei.com>
> 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 ++++++++++++++++++++++++++++++++++++++++++

Acked-by: Jiri Olsa <jolsa@kernel.org>

thanks,
jirka
--
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/

[toc] | [prev] | [next] | [standalone]


#1291100 — [PATCH v5 05/14] perf tools: Enable BPF object configure syntax

FromWang Nan <wangnan0@huawei.com>
Date2015-12-14 11:50 +0100
Subject[PATCH v5 05/14] perf tools: Enable BPF object configure syntax
Message-ID<qFyRA-4Xv-27@gated-at.bofh.it>
In reply to#1291097
This patch adds the final step for BPF map configuration. A new syntax
is appended into parser so user can config BPF objects through '/' '/'
enclosed config terms.

After this patch, following syntax is available:

 # perf record -e ./test_bpf_map_1.c/maps:channel.value=10/ ...

It would takes effect after appling following commits.

Test result:

 # cat ./test_bpf_map_1.c
 /************************ BEGIN **************************/
 #include <uapi/linux/bpf.h>
 #define SEC(NAME) __attribute__((section(NAME), used))
 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 *)BPF_FUNC_map_lookup_elem;
 static int (*trace_printk)(const char *fmt, int fmt_size, ...) =
     (void *)BPF_FUNC_trace_printk;
 struct bpf_map_def SEC("maps") channel = {
     .type = BPF_MAP_TYPE_ARRAY,
     .key_size = sizeof(int),
     .value_size = sizeof(int),
     .max_entries = 1,
 };
 SEC("func=sys_nanosleep")
 int func(void *ctx)
 {
     int key = 0;
     char fmt[] = "%d\n";
     int *pval = map_lookup_elem(&channel, &key);
     if (!pval)
         return 0;
     trace_printk(fmt, sizeof(fmt), *pval);
     return 0;
 }
 char _license[] SEC("license") = "GPL";
 int _version SEC("version") = LINUX_VERSION_CODE;
 /************************* END ***************************/

 - Normal case:
 # ./perf record -e './test_bpf_map_1.c/maps:channel.value=10/' usleep 10
 [ perf record: Woken up 1 times to write data ]
 [ perf record: Captured and wrote 0.012 MB perf.data ]

 - Error case:

 # ./perf record -e './test_bpf_map_1.c/maps:channel.value/' usleep 10
 event syntax error: '..ps:channel:value/'
                                   \___ Config value not set (lost '=')
 Hint:	Valid config term:
      	maps:[<arraymap>]:value=[value]
	     	(add -v to see detail)
	Run 'perf list' for a list of valid events

 Usage: perf record [<options>] [<command>]
    or: perf record [<options>] -- <command> [<options>]

    -e, --event <event>   event selector. use 'perf list' to list available events

 # ./perf record -e './test_bpf_map_1.c/xmaps:channel.value=10/' usleep 10
 event syntax error: '..pf_map_1.c/xmaps:channel.value=10/'
                                   \___ Invalid object config option
 [SNIP]

 # ./perf record -e './test_bpf_map_1.c/maps:xchannel.value=10/' usleep 10
 event syntax error: '..p_1.c/maps:xchannel.value=10/'
                                   \___ Target map not exist
 [SNIP]

 # ./perf record -e './test_bpf_map_1.c/maps:channel.xvalue=10/' usleep 10
 event syntax error: '..ps:channel.xvalue=10/'
                                   \___ Invalid object maps config option
 [SNIP]

 # ./perf record -e './test_bpf_map_1.c/maps:channel.value=x10/' usleep 10
 event syntax error: '..nnel.value=x10/'
                                   \___ Incorrect value type for map
 [SNIP]

 Change BPF_MAP_TYPE_ARRAY to '1':

 # ./perf record -e './test_bpf_map_1.c/maps:channel.value=10/' usleep 10
 event syntax error: '..ps:channel.value=10/'
                                   \___ Can't use this config term to this type of map

 Hint:	Valid config term:
     	maps:[<arraymap>].value=[value]
     	(add -v to see detail)

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: He Kuang <hekuang@huawei.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
---
 tools/perf/util/parse-events.c | 56 +++++++++++++++++++++++++++++++++++++++---
 tools/perf/util/parse-events.h |  3 ++-
 tools/perf/util/parse-events.l |  2 +-
 tools/perf/util/parse-events.y | 23 ++++++++++++++---
 4 files changed, 75 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 6fc8cd7..95775fe 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -628,17 +628,64 @@ errout:
 	return err;
 }
 
+static int
+parse_events_config_bpf(struct parse_events_evlist *data,
+		       struct bpf_object *obj,
+		       struct list_head *head_config)
+{
+	struct parse_events_term *term;
+	int error_pos;
+
+	if (!head_config || list_empty(head_config))
+		return 0;
+
+	list_for_each_entry(term, head_config, list) {
+		char errbuf[BUFSIZ];
+		int err;
+
+		if (term->type_term != PARSE_EVENTS__TERM_TYPE_USER) {
+			snprintf(errbuf, sizeof(errbuf),
+				 "Invalid config term for BPF object");
+			errbuf[BUFSIZ - 1] = '\0';
+
+			data->error->idx = term->err_term;
+			data->error->str = strdup(errbuf);
+			return -EINVAL;
+		}
+
+		err = bpf__config_obj(obj, term, NULL, &error_pos);
+		if (err) {
+			bpf__strerror_config_obj(obj, term, NULL,
+						 &error_pos, err, errbuf,
+						 sizeof(errbuf));
+			data->error->help = strdup(
+"Hint:\tValid config term:\n"
+"     \tmaps:[<arraymap>].value=[value]\n"
+"     \t(add -v to see detail)");
+			data->error->str = strdup(errbuf);
+			if (err == -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE)
+				data->error->idx = term->err_val;
+			else
+				data->error->idx = term->err_term + error_pos;
+			return err;
+		}
+	}
+	return 0;
+
+}
+
 int parse_events_load_bpf(struct parse_events_evlist *data,
 			  struct list_head *list,
 			  char *bpf_file_name,
-			  bool source)
+			  bool source,
+			  struct list_head *head_config)
 {
 	struct bpf_object *obj;
+	int err;
 
 	obj = bpf__prepare_load(bpf_file_name, source);
 	if (IS_ERR(obj)) {
 		char errbuf[BUFSIZ];
-		int err;
 
 		err = PTR_ERR(obj);
 
@@ -656,7 +703,10 @@ int parse_events_load_bpf(struct parse_events_evlist *data,
 		return err;
 	}
 
-	return parse_events_load_bpf_obj(data, list, obj);
+	err = parse_events_load_bpf_obj(data, list, obj);
+	if (err)
+		return err;
+	return parse_events_config_bpf(data, obj, head_config);
 }
 
 static int
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index f1a6db1..84694f3 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -126,7 +126,8 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
 int parse_events_load_bpf(struct parse_events_evlist *data,
 			  struct list_head *list,
 			  char *bpf_file_name,
-			  bool source);
+			  bool source,
+			  struct list_head *head_config);
 /* Provide this function for perf test */
 struct bpf_object;
 int parse_events_load_bpf_obj(struct parse_events_evlist *data,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 58c5831..4387728 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -122,7 +122,7 @@ num_dec		[0-9]+
 num_hex		0x[a-fA-F0-9]+
 num_raw_hex	[a-fA-F0-9]+
 name		[a-zA-Z_*?][a-zA-Z0-9_*?.]*
-name_minus	[a-zA-Z_*?][a-zA-Z0-9\-_*?.]*
+name_minus	[a-zA-Z_*?][a-zA-Z0-9\-_*?.:]*
 /* If you add a modifier you need to update check_modifier() */
 modifier_event	[ukhpPGHSDI]+
 modifier_bp	[rwx]{1,3}
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index ad37996..8992d16 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -64,6 +64,7 @@ static inc_group_count(struct list_head *list,
 %type <str> PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT
 %type <num> value_sym
 %type <head> event_config
+%type <head> event_bpf_config
 %type <term> event_term
 %type <head> event_pmu
 %type <head> event_legacy_symbol
@@ -455,27 +456,41 @@ PE_RAW
 }
 
 event_bpf_file:
-PE_BPF_OBJECT
+PE_BPF_OBJECT event_bpf_config
 {
 	struct parse_events_evlist *data = _data;
 	struct parse_events_error *error = data->error;
 	struct list_head *list;
 
 	ALLOC_LIST(list);
-	ABORT_ON(parse_events_load_bpf(data, list, $1, false));
+	ABORT_ON(parse_events_load_bpf(data, list, $1, false, $2));
+	if ($2)
+		parse_events__free_terms($2);
 	$$ = list;
 }
 |
-PE_BPF_SOURCE
+PE_BPF_SOURCE event_bpf_config
 {
 	struct parse_events_evlist *data = _data;
 	struct list_head *list;
 
 	ALLOC_LIST(list);
-	ABORT_ON(parse_events_load_bpf(data, list, $1, true));
+	ABORT_ON(parse_events_load_bpf(data, list, $1, true, $2));
+	if ($2)
+		parse_events__free_terms($2);
 	$$ = list;
 }
 
+event_bpf_config:
+'/' event_config '/'
+{
+	$$ = $2;
+}
+|
+{
+	$$ = NULL;
+}
+
 start_terms: event_config
 {
 	struct parse_events_terms *data = _data;
-- 
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/

[toc] | [prev] | [next] | [standalone]


#1292163 — Re: [PATCH v5 05/14] perf tools: Enable BPF object configure syntax

FromJiri Olsa <jolsa@redhat.com>
Date2015-12-15 14:20 +0100
SubjectRe: [PATCH v5 05/14] perf tools: Enable BPF object configure syntax
Message-ID<qFXGh-4AF-1@gated-at.bofh.it>
In reply to#1291100
On Mon, Dec 14, 2015 at 10:39:14AM +0000, Wang Nan wrote:

SNIP

>     -e, --event <event>   event selector. use 'perf list' to list available events
> 
>  # ./perf record -e './test_bpf_map_1.c/xmaps:channel.value=10/' usleep 10
>  event syntax error: '..pf_map_1.c/xmaps:channel.value=10/'
>                                    \___ Invalid object config option
>  [SNIP]
> 
>  # ./perf record -e './test_bpf_map_1.c/maps:xchannel.value=10/' usleep 10
>  event syntax error: '..p_1.c/maps:xchannel.value=10/'
>                                    \___ Target map not exist
>  [SNIP]
> 
>  # ./perf record -e './test_bpf_map_1.c/maps:channel.xvalue=10/' usleep 10
>  event syntax error: '..ps:channel.xvalue=10/'
>                                    \___ Invalid object maps config option
>  [SNIP]
> 
>  # ./perf record -e './test_bpf_map_1.c/maps:channel.value=x10/' usleep 10
>  event syntax error: '..nnel.value=x10/'
>                                    \___ Incorrect value type for map
>  [SNIP]
> 
>  Change BPF_MAP_TYPE_ARRAY to '1':
> 
>  # ./perf record -e './test_bpf_map_1.c/maps:channel.value=10/' usleep 10
>  event syntax error: '..ps:channel.value=10/'
>                                    \___ Can't use this config term to this type of map
> 
>  Hint:	Valid config term:
>      	maps:[<arraymap>].value=[value]
>      	(add -v to see detail)
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> Signed-off-by: He Kuang <hekuang@huawei.com>
> Cc: Alexei Starovoitov <ast@kernel.org>
> Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
> Cc: Jiri Olsa <jolsa@kernel.org>
> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Cc: Namhyung Kim <namhyung@kernel.org>
> Cc: Zefan Li <lizefan@huawei.com>
> Cc: pi3orama@163.com
> ---
>  tools/perf/util/parse-events.c | 56 +++++++++++++++++++++++++++++++++++++++---
>  tools/perf/util/parse-events.h |  3 ++-
>  tools/perf/util/parse-events.l |  2 +-
>  tools/perf/util/parse-events.y | 23 ++++++++++++++---
>  4 files changed, 75 insertions(+), 9 deletions(-)

I don't understand the bpf stuff, but as far as config terms this
change look ok to me, so for bison/flex parser related changes:

Acked-by: Jiri Olsa <jolsa@kernel.org>

thanks,
jirka
--
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/

[toc] | [prev] | [next] | [standalone]


#1291101 — [PATCH v5 01/14] perf tests: Fix incorrect free and false TEST_OK result

FromWang Nan <wangnan0@huawei.com>
Date2015-12-14 11:50 +0100
Subject[PATCH v5 01/14] perf tests: Fix incorrect free and false TEST_OK result
Message-ID<qFyRA-4Xv-29@gated-at.bofh.it>
In reply to#1291097
Commit cc1121ab9687d660cc02f50b1a4974112f87a8e6 ('perf machine: Fix
machine.vmlinux_maps to make sure to clear the old one') reveals a bug
in 'perf test' that in all test cases which use setup_fake_machine()
incorrectly call free() when failure, because all users of
setup_fake_machine() use static allocated 'machines' structure, but
setup_fake_machine() calls machine__delete() which try to free() it.

If a normal user try those test cases this problem can be seen:
 $ cat /proc/sys/kernel/kptr_restrict
 1
 $ ./perf test 'hist'
 15: Test matching and linking multiple hists                 :*** Error in `./perf': munmap_chunk(): invalid pointer: 0x00007ffd6e900090 ***
 ======= Backtrace: =========
 /lib64/libc.so.6(+0x6eeef)[0x7fcec97e1eef]
 /lib64/libc.so.6(+0x78cae)[0x7fcec97ebcae]
 ./perf(setup_fake_machine+0x1cd)[0x4721ad]
 ./perf(test__hists_link+0xbf)[0x472d3f]
 ./perf[0x4648df]
 ./perf(cmd_test+0x589)[0x464ec9]
 ./perf[0x47fd11]
 ./perf(main+0x5f6)[0x432b96]
 /lib64/libc.so.6(__libc_start_main+0xf5)[0x7fcec9794bd5]
 ./perf[0x432cc5]
 ======= Memory map: ========
 ...
 25: Test filtering hist entries                              :*** Error in `./perf': munmap_chunk(): invalid pointer: 0x00007ffd6e900080 ***
 ======= Backtrace: =========
 /lib64/libc.so.6(+0x6eeef)[0x7fcec97e1eef]
 /lib64/libc.so.6(+0x78cae)[0x7fcec97ebcae]
 ./perf(setup_fake_machine+0x1cd)[0x4721ad]
 ./perf(test__hists_filter+0xc6)[0x4730f6]
 ./perf[0x4648df]
 ./perf(cmd_test+0x589)[0x464ec9]
 ./perf[0x47fd11]
 ./perf(main+0x5f6)[0x432b96]
 /lib64/libc.so.6(__libc_start_main+0xf5)[0x7fcec9794bd5]
 ./perf[0x432cc5]
 ======= Memory map: ========
 ...
 ...

Actually, all users of 'machines__init()' should avoid calling
machine__delete(). We can further add a flag in machine structure to
enforce this restriction.

After changing machine__delete() to machine__exit() another problem
arises:

 $ ./perf test 'hist'
 15: Test matching and linking multiple hists                 : Ok
 25: Test filtering hist entries                              : Ok
 28: Test output sorting of hist entries                      : Ok
 29: Test cumulation of child hist entries                    : Ok

The result is not true:

 $ ./perf test -v 'hist'
 15: Test matching and linking multiple hists                 :
 --- start ---
 test child forked, pid 17657
 Not enough memory for machine setup
 Not enough memory for machine setup
 test child finished with 0
 ---- end ----
 Test matching and linking multiple hists: Ok
 25: Test filtering hist entries                              :
 --- start ---
 test child forked, pid 17658
 Not enough memory for machine setup
 Not enough memory for machine setup
 test child finished with 0
 ---- end ----
 Test filtering hist entries: Ok
 28: Test output sorting of hist entries                      :
 --- start ---
 test child forked, pid 17659
 Not enough memory for machine setup
 Not enough memory for machine setup
 test child finished with 0
 ---- end ----
 Test output sorting of hist entries: Ok
 29: Test cumulation of child hist entries                    :
 --- start ---
 test child forked, pid 17660
 Not enough memory for machine setup
 Not enough memory for machine setup
 test child finished with 0
 ---- end ----
 Test cumulation of child hist entries: Ok

Because the test body is not executed at all.

The reason is that *ALL* hists test cases forget to reset err after
using it to hold an error code:

  err = TEST_FAIL;
  ...
  err = parse_events(evlist, "cpu-clock", NULL);
  if (err)
      goto out;
  /* err is already 0 here */
  ...
  machine = setup_fake_machine(&machines);
  if (!machine)
      goto out;
  ...
 out:
  ...
  return err;

This patch ensure err is reset.

In case when kptr_restrict prevent normal user get kernel address, this
test should be skipped, not fail. This patch use linux/err.h to store
error code in return value of setup_fake_machine(), and let 'EACCES' to
indicate this problem.

Also, the debug message 'Not enough memory for machine setup' is not
true and should be fixed.

Here is the final result:
 $ ./perf test 'hist'
 15: Test matching and linking multiple hists                 : Skip
 25: Test filtering hist entries                              : Skip
 28: Test output sorting of hist entries                      : Skip
 29: Test cumulation of child hist entries                    : Skip

 $ ./perf test -v 'hist'
 15: Test matching and linking multiple hists                 :
 --- start ---
 test child forked, pid 20177
 Failed to create kernel maps
 Hint: Check /proc/sys/kernel/kptr_restrict.
 Failed for machine setup
 test child finished with -2
 ---- end ----
 Test matching and linking multiple hists: Skip
 25: Test filtering hist entries
 ...

 $ sudo ./perf test hist
 15: Test matching and linking multiple hists                 : Ok
 25: Test filtering hist entries                              : Ok
 28: Test output sorting of hist entries                      : Ok
 29: Test cumulation of child hist entries                    : Ok

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
---
 tools/perf/tests/hists_common.c   | 15 ++++++++++-----
 tools/perf/tests/hists_common.h   |  1 +
 tools/perf/tests/hists_cumulate.c |  6 +++++-
 tools/perf/tests/hists_filter.c   |  6 +++++-
 tools/perf/tests/hists_link.c     |  6 +++++-
 tools/perf/tests/hists_output.c   |  6 +++++-
 6 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
index 46f453b..4cd8cad 100644
--- a/tools/perf/tests/hists_common.c
+++ b/tools/perf/tests/hists_common.c
@@ -81,14 +81,19 @@ struct machine *setup_fake_machine(struct machines *machines)
 {
 	struct machine *machine = machines__find(machines, HOST_KERNEL_ID);
 	size_t i;
+	int err = -ENOMEM;
 
 	if (machine == NULL) {
 		pr_debug("Not enough memory for machine setup\n");
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 	}
 
 	if (machine__create_kernel_maps(machine)) {
-		pr_debug("Not enough memory for machine setup\n");
+		pr_debug("Failed to create kernel maps\n");
+		if (symbol_conf.kptr_restrict) {
+			pr_debug("Hint: Check /proc/sys/kernel/kptr_restrict.\n");
+			err = -EACCES;
+		}
 		goto out;
 	}
 
@@ -153,10 +158,10 @@ struct machine *setup_fake_machine(struct machines *machines)
 	return machine;
 
 out:
-	pr_debug("Not enough memory for machine setup\n");
+	pr_debug("Failed for machine setup\n");
 	machine__delete_threads(machine);
-	machine__delete(machine);
-	return NULL;
+	machine__exit(machine);
+	return ERR_PTR(err);
 }
 
 void print_hists_in(struct hists *hists)
diff --git a/tools/perf/tests/hists_common.h b/tools/perf/tests/hists_common.h
index 888254e..0252eae 100644
--- a/tools/perf/tests/hists_common.h
+++ b/tools/perf/tests/hists_common.h
@@ -1,5 +1,6 @@
 #ifndef __PERF_TESTS__HISTS_COMMON_H__
 #define __PERF_TESTS__HISTS_COMMON_H__
+#include <linux/err.h>
 
 struct machine;
 struct machines;
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 8292948..c211075 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -706,13 +706,17 @@ int test__hists_cumulate(int subtest __maybe_unused)
 	err = parse_events(evlist, "cpu-clock", NULL);
 	if (err)
 		goto out;
+	err = TEST_FAIL;
 
 	machines__init(&machines);
 
 	/* setup threads/dso/map/symbols also */
 	machine = setup_fake_machine(&machines);
-	if (!machine)
+	if (IS_ERR(machine)) {
+		if (PTR_ERR(machine) == -EACCES)
+			err = TEST_SKIP;
 		goto out;
+	}
 
 	if (verbose > 1)
 		machine__fprintf(machine, stderr);
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index ccb5b49..795a04d 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -120,6 +120,7 @@ int test__hists_filter(int subtest __maybe_unused)
 	err = parse_events(evlist, "task-clock", NULL);
 	if (err)
 		goto out;
+	err = TEST_FAIL;
 
 	/* default sort order (comm,dso,sym) will be used */
 	if (setup_sorting() < 0)
@@ -129,8 +130,11 @@ int test__hists_filter(int subtest __maybe_unused)
 
 	/* setup threads/dso/map/symbols also */
 	machine = setup_fake_machine(&machines);
-	if (!machine)
+	if (IS_ERR(machine)) {
+		if (PTR_ERR(machine) == -EACCES)
+			err = TEST_SKIP;
 		goto out;
+	}
 
 	if (verbose > 1)
 		machine__fprintf(machine, stderr);
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 6243e2b..f5f37ef9 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -293,6 +293,7 @@ int test__hists_link(int subtest __maybe_unused)
 	if (err)
 		goto out;
 
+	err = TEST_FAIL;
 	/* default sort order (comm,dso,sym) will be used */
 	if (setup_sorting() < 0)
 		goto out;
@@ -301,8 +302,11 @@ int test__hists_link(int subtest __maybe_unused)
 
 	/* setup threads/dso/map/symbols also */
 	machine = setup_fake_machine(&machines);
-	if (!machine)
+	if (IS_ERR(machine)) {
+		if (PTR_ERR(machine) == -EACCES)
+			err = TEST_SKIP;
 		goto out;
+	}
 
 	if (verbose > 1)
 		machine__fprintf(machine, stderr);
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index 248beec..cc570cf 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -597,13 +597,17 @@ int test__hists_output(int subtest __maybe_unused)
 	err = parse_events(evlist, "cpu-clock", NULL);
 	if (err)
 		goto out;
+	err = TEST_FAIL;
 
 	machines__init(&machines);
 
 	/* setup threads/dso/map/symbols also */
 	machine = setup_fake_machine(&machines);
-	if (!machine)
+	if (IS_ERR(machine)) {
+		if (PTR_ERR(machine) == -EACCES)
+			err = TEST_SKIP;
 		goto out;
+	}
 
 	if (verbose > 1)
 		machine__fprintf(machine, stderr);
-- 
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/

[toc] | [prev] | [next] | [standalone]


#1291102 — [PATCH v5 09/14] perf tools: Support setting different slots in a BPF map separately

FromWang Nan <wangnan0@huawei.com>
Date2015-12-14 11:50 +0100
Subject[PATCH v5 09/14] perf tools: Support setting different slots in a BPF map separately
Message-ID<qFyRA-4Xv-31@gated-at.bofh.it>
In reply to#1291097
This patch introduces basic facilities to support config different
slots in a BPF map one by one.

array.nr_ranges and array.ranges are introduced into 'struct
parse_events_term', where ranges is an array of indices range (start,
length) which will be configured by this config term. nr_ranges
is the size of the array. The array is passed to 'struct bpf_map_priv'.
To indicate the new type of configuration, BPF_MAP_KEY_RANGES is
added as a new key type. bpf_map_config_foreach_key() is extended to
iterate over those indices instead of all possible keys.

Code in this commit will be enabled by following commit which enables
the indices syntax for array configuration.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
---
 tools/perf/util/bpf-loader.c   | 132 ++++++++++++++++++++++++++++++++++++++---
 tools/perf/util/bpf-loader.h   |   1 +
 tools/perf/util/parse-events.c |  33 ++++++++++-
 tools/perf/util/parse-events.h |  12 ++++
 4 files changed, 170 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 2893b4e..6c25de8 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -17,6 +17,7 @@
 #include "llvm-utils.h"
 #include "probe-event.h"
 #include "probe-finder.h" // for MAX_PROBES
+#include "parse-events.h"
 #include "llvm-utils.h"
 
 #define DEFINE_PRINT_FN(name, level) \
@@ -747,6 +748,7 @@ enum bpf_map_op_type {
 
 enum bpf_map_key_type {
 	BPF_MAP_KEY_ALL,
+	BPF_MAP_KEY_RANGES,
 };
 
 struct bpf_map_op {
@@ -754,6 +756,9 @@ struct bpf_map_op {
 	enum bpf_map_op_type op_type;
 	enum bpf_map_key_type key_type;
 	union {
+		struct parse_events_array array;
+	} k;
+	union {
 		u64 value;
 		struct perf_evsel *evsel;
 	} v;
@@ -779,6 +784,8 @@ bpf_map_op__free(struct bpf_map_op *op)
 	 */
 	if ((list->next != LIST_POISON1) && (list->prev != LIST_POISON2))
 		list_del(list);
+	if (op->key_type == BPF_MAP_KEY_RANGES)
+		parse_events__clear_array(&op->k.array);
 	free(op);
 }
 
@@ -794,8 +801,30 @@ bpf_map_priv__clear(struct bpf_map *map __maybe_unused,
 	free(priv);
 }
 
+static int
+bpf_map_op_setkey(struct bpf_map_op *op, struct parse_events_term *term,
+		  const char *map_name)
+{
+	op->key_type = BPF_MAP_KEY_ALL;
+
+	if (term->array.nr_ranges) {
+		size_t memsz = term->array.nr_ranges *
+				sizeof(op->k.array.ranges[0]);
+
+		op->k.array.ranges = memdup(term->array.ranges, memsz);
+		if (!op->k.array.ranges) {
+			pr_debug("No enough memory to alloc indices for %s\n",
+				 map_name);
+			return -ENOMEM;
+		}
+		op->key_type = BPF_MAP_KEY_RANGES;
+		op->k.array.nr_ranges = term->array.nr_ranges;
+	}
+	return 0;
+}
+
 static struct bpf_map_op *
-bpf_map_op__alloc(struct bpf_map *map)
+bpf_map_op__alloc(struct bpf_map *map, struct parse_events_term *term)
 {
 	struct bpf_map_op *op;
 	struct bpf_map_priv *priv;
@@ -829,7 +858,12 @@ bpf_map_op__alloc(struct bpf_map *map)
 		return ERR_PTR(-ENOMEM);
 	}
 
-	op->key_type = BPF_MAP_KEY_ALL;
+	err = bpf_map_op_setkey(op, term, map_name);
+	if (err) {
+		free(op);
+		return ERR_PTR(err);
+	}
+
 	list_add_tail(&op->list, &priv->ops_list);
 	return op;
 }
@@ -872,7 +906,7 @@ bpf__obj_config_map_array_value(struct bpf_map *map,
 		return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE;
 	}
 
-	op = bpf_map_op__alloc(map);
+	op = bpf_map_op__alloc(map, term);
 	if (IS_ERR(op))
 		return PTR_ERR(op);
 	op->op_type = BPF_MAP_OP_SET_VALUE;
@@ -933,7 +967,7 @@ bpf__obj_config_map_array_event(struct bpf_map *map,
 		return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE;
 	}
 
-	op = bpf_map_op__alloc(map);
+	op = bpf_map_op__alloc(map, term);
 	if (IS_ERR(op))
 		return PTR_ERR(op);
 
@@ -972,6 +1006,44 @@ struct bpf_obj_config_map_func bpf_obj_config_map_funcs[] = {
 };
 
 static int
+config_map_indices_range_check(struct parse_events_term *term,
+			       struct bpf_map *map,
+			       const char *map_name)
+{
+	struct parse_events_array *array = &term->array;
+	struct bpf_map_def def;
+	unsigned int i;
+	int err;
+
+	if (!array->nr_ranges)
+		return 0;
+	if (!array->ranges) {
+		pr_debug("ERROR: map %s: array->nr_ranges is %d but range array is NULL\n",
+			 map_name, (int)array->nr_ranges);
+		return -BPF_LOADER_ERRNO__INTERNAL;
+	}
+
+	err = bpf_map__get_def(map, &def);
+	if (err) {
+		pr_debug("ERROR: Unable to get map definition from '%s'\n",
+			 map_name);
+		return -BPF_LOADER_ERRNO__INTERNAL;
+	}
+
+	for (i = 0; i < array->nr_ranges; i++) {
+		unsigned int start = array->ranges[i].start;
+		size_t length = array->ranges[i].length;
+		unsigned int idx = start + length - 1;
+
+		if (idx >= def.max_entries) {
+			pr_debug("ERROR: index %d too large\n", idx);
+			return -BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG;
+		}
+	}
+	return 0;
+}
+
+static int
 bpf__obj_config_map(struct bpf_object *obj,
 		    struct parse_events_term *term,
 		    struct perf_evlist *evlist,
@@ -1007,6 +1079,13 @@ bpf__obj_config_map(struct bpf_object *obj,
 	}
 
 	*key_scan_pos += map_opt - map_name;
+
+	*key_scan_pos += strlen(map_opt);
+	err = config_map_indices_range_check(term, map, map_name);
+	if (err)
+		goto out;
+	*key_scan_pos -= strlen(map_opt);
+
 	for (i = 0; i < ARRAY_SIZE(bpf_obj_config_map_funcs); i++) {
 		struct bpf_obj_config_map_func *func =
 				&bpf_obj_config_map_funcs[i];
@@ -1077,6 +1156,33 @@ foreach_key_array_all(map_config_func_t func,
 }
 
 static int
+foreach_key_array_ranges(map_config_func_t func, void *arg,
+			 const char *name, int map_fd,
+			 struct bpf_map_def *pdef,
+			 struct bpf_map_op *op)
+{
+	unsigned int i, j;
+	int err;
+
+	for (i = 0; i < op->k.array.nr_ranges; i++) {
+		unsigned int start = op->k.array.ranges[i].start;
+		size_t length = op->k.array.ranges[i].length;
+
+		for (j = 0; j < length; j++) {
+			unsigned int idx = start + j;
+
+			err = func(name, map_fd, pdef, op, &idx, arg);
+			if (err) {
+				pr_debug("ERROR: failed to insert value to %s[%u]\n",
+					 name, idx);
+				return err;
+			}
+		}
+	}
+	return 0;
+}
+
+static int
 bpf_map_config_foreach_key(struct bpf_map *map,
 			   map_config_func_t func,
 			   void *arg)
@@ -1116,13 +1222,24 @@ bpf_map_config_foreach_key(struct bpf_map *map,
 		case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
 			switch (op->key_type) {
 			case BPF_MAP_KEY_ALL:
-				return foreach_key_array_all(func, arg, name,
-							     map_fd, &def, op);
+				err = foreach_key_array_all(func, arg, name,
+							    map_fd, &def, op);
+				if (err)
+					return err;
+				break;
+			case BPF_MAP_KEY_RANGES:
+				err = foreach_key_array_ranges(func, arg, name,
+							       map_fd, &def,
+							       op);
+				if (err)
+					return err;
+				break;
 			default:
 				pr_debug("ERROR: keytype for map '%s' invalid\n",
 					 name);
 				return -BPF_LOADER_ERRNO__INTERNAL;
-		}
+			}
+			break;
 		default:
 			pr_debug("ERROR: type of '%s' incorrect\n", name);
 			return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE;
@@ -1309,6 +1426,7 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = {
 	[ERRCODE_OFFSET(OBJCONF_MAP_EVTDIM)]	= "Event dimension too large",
 	[ERRCODE_OFFSET(OBJCONF_MAP_EVTINH)]	= "Doesn't support inherit event",
 	[ERRCODE_OFFSET(OBJCONF_MAP_EVTTYPE)]	= "Wrong event type for map",
+	[ERRCODE_OFFSET(OBJCONF_MAP_IDX2BIG)]	= "Index too large",
 };
 
 static int
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index c9ce792..30ee519 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -38,6 +38,7 @@ enum bpf_loader_errno {
 	BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM,	/* Event dimension too large */
 	BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH,	/* Doesn't support inherit event */
 	BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE,	/* Wrong event type for map */
+	BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG,	/* Index too large */
 	__BPF_LOADER_ERRNO__END,
 };
 
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5d682dd..af3d657 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -2148,8 +2148,39 @@ void parse_events__free_terms(struct list_head *terms)
 {
 	struct parse_events_term *term, *h;
 
-	list_for_each_entry_safe(term, h, terms, list)
+	list_for_each_entry_safe(term, h, terms, list) {
+		if (term->array.nr_ranges)
+			free(term->array.ranges);
 		free(term);
+	}
+}
+
+int parse_events__merge_arrays(struct parse_events_array *dest,
+			       struct parse_events_array *another)
+{
+	struct parse_events_array new;
+
+	if (!dest || !another)
+		return -EINVAL;
+
+	new.nr_ranges = dest->nr_ranges + another->nr_ranges;
+	new.ranges = malloc(sizeof(new.ranges[0]) * new.nr_ranges);
+	if (!new.ranges)
+		return -ENOMEM;
+
+	memcpy(&new.ranges[0], dest->ranges,
+	       sizeof(new.ranges[0]) * dest->nr_ranges);
+	memcpy(&new.ranges[dest->nr_ranges], another->ranges,
+	       sizeof(new.ranges[0]) * another->nr_ranges);
+	free(dest->ranges);
+	free(another->ranges);
+	*dest = new;
+	return 0;
+}
+
+void parse_events__clear_array(struct parse_events_array *a)
+{
+	free(a->ranges);
 }
 
 void parse_events_evlist_error(struct parse_events_evlist *data,
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 20ad3c2..c34615f 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -71,8 +71,17 @@ enum {
 	PARSE_EVENTS__TERM_TYPE_INHERIT
 };
 
+struct parse_events_array {
+	size_t nr_ranges;
+	struct {
+		unsigned int start;
+		size_t length;
+	} *ranges;
+};
+
 struct parse_events_term {
 	char *config;
+	struct parse_events_array array;
 	union {
 		char *str;
 		u64  num;
@@ -117,6 +126,9 @@ int parse_events_term__sym_hw(struct parse_events_term **term,
 int parse_events_term__clone(struct parse_events_term **new,
 			     struct parse_events_term *term);
 void parse_events__free_terms(struct list_head *terms);
+int parse_events__merge_arrays(struct parse_events_array *dest,
+			       struct parse_events_array *another);
+void parse_events__clear_array(struct parse_events_array *a);
 int parse_events__modifier_event(struct list_head *list, char *str, bool add);
 int parse_events__modifier_group(struct list_head *list, char *event_mod);
 int parse_events_name(struct list_head *list, char *name);
-- 
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/

[toc] | [prev] | [next] | [standalone]


#1291104 — [PATCH v5 13/14] perf tools: Always give options even it not compiled

FromWang Nan <wangnan0@huawei.com>
Date2015-12-14 11:50 +0100
Subject[PATCH v5 13/14] perf tools: Always give options even it not compiled
Message-ID<qFyRB-4Xv-41@gated-at.bofh.it>
In reply to#1291097
This patch keeps options of perf builtins same in all conditions. If
one option is disabled because of compiling options, users should be
notified.

Masami suggested another implementation in [1] that, by adding a
OPTION_NEXT_DEPENDS option before those options in the 'struct option'
array, options parser knows an option is disabled. However, in some
cases this array is reordered (options__order()). In addition, in
parse-option.c that array is const, so we can't simply merge
information in decorator option into the affacted option.

This patch chooses a simpler implementation that, introducing a
set_option_nobuild() function and two option parsing flags. Builtins
with such options should call set_option_nobuild() before option
parsing. The complexity of this patch is because we want some of options
can be skipped safely. In this case their arguments should also be
consumed.

Options in 'perf record' and 'perf probe' are fixed in this patch.

[1] http://lkml.kernel.org/g/50399556C9727B4D88A595C8584AAB3752627CD4@GSjpTKYDCembx32.service.hitachi.net

Test result:

Normal case:

# ./perf probe --vmlinux /tmp/vmlinux sys_write
Added new event:
  probe:sys_write      (on sys_write)

You can now use it in all perf tools, such as:

	perf record -e probe:sys_write -aR sleep 1


Build with NO_DWARF=1:

# ./perf probe -L sys_write
  Error: switch `L' is not available because NO_DWARF=1

 Usage: perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]
    or: perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]
    or: perf probe [<options>] --del '[GROUP:]EVENT' ...
    or: perf probe --list [GROUP:]EVENT ...
    or: perf probe [<options>] --funcs

    -L, --line <FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]>
                          Show source code lines.
                          (not built-in because NO_DWARF=1)

# ./perf probe -k /tmp/vmlinux sys_write
  Warning: switch `k' is being ignored because NO_DWARF=1
Added new event:
  probe:sys_write      (on sys_write)

You can now use it in all perf tools, such as:

	perf record -e probe:sys_write -aR sleep 1

# ./perf probe --vmlinux /tmp/vmlinux sys_write
  Warning: option `vmlinux' is being ignored because NO_DWARF=1
Added new event:
[SNIP]

# ./perf probe -l
 Usage: perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]
    or: perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]
...
    -k, --vmlinux <file>  vmlinux pathname
                          (not built-in because NO_DWARF=1)
    -L, --line <FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]>
                          Show source code lines.
                          (not built-in because NO_DWARF=1)
...
    -V, --vars <FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT>
                          Show accessible variables on PROBEDEF
                          (not built-in because NO_DWARF=1)
        --externs         Show external variables too (with --vars only)
                          (not built-in because NO_DWARF=1)
        --no-inlines      Don't search inlined functions
                          (not built-in because NO_DWARF=1)
        --range           Show variables location range in scope (with --vars only)
                          (not built-in because NO_DWARF=1)

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
---
 tools/perf/builtin-probe.c      |  15 ++++-
 tools/perf/builtin-record.c     |   9 ++-
 tools/perf/util/parse-options.c | 118 +++++++++++++++++++++++++++++++++++++---
 tools/perf/util/parse-options.h |   5 ++
 4 files changed, 134 insertions(+), 13 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 132afc9..dbe2ea5 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -249,6 +249,9 @@ static int opt_show_vars(const struct option *opt,
 
 	return ret;
 }
+#else
+# define opt_show_lines NULL
+# define opt_show_vars NULL
 #endif
 static int opt_add_probe_event(const struct option *opt,
 			      const char *str, int unset __maybe_unused)
@@ -473,7 +476,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 		opt_add_probe_event),
 	OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
 		    " with existing name"),
-#ifdef HAVE_DWARF_SUPPORT
 	OPT_CALLBACK('L', "line", NULL,
 		     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
 		     "Show source code lines.", opt_show_lines),
@@ -490,7 +492,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 		   "directory", "path to kernel source"),
 	OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines,
 		"Don't search inlined functions"),
-#endif
 	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes,
 		 "Set how many probe points can be found for a probe."),
@@ -521,6 +522,16 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 #ifdef HAVE_DWARF_SUPPORT
 	set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
 	set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE);
+#else
+# define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_DWARF=1", c)
+	set_nobuild('L', "line", false);
+	set_nobuild('V', "vars", false);
+	set_nobuild('\0', "externs", false);
+	set_nobuild('\0', "range", false);
+	set_nobuild('k', "vmlinux", true);
+	set_nobuild('s', "source", true);
+	set_nobuild('\0', "no-inlines", true);
+# undef set_nobuild
 #endif
 	set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE);
 
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8479821..11bf32d 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1124,12 +1124,10 @@ struct option __record_options[] = {
 			"per thread proc mmap processing timeout in ms"),
 	OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
 		    "Record context switch events"),
-#ifdef HAVE_LIBBPF_SUPPORT
 	OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
 		   "clang binary to use for compiling BPF scriptlets"),
 	OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
 		   "options passed to clang when compiling BPF scriptlets"),
-#endif
 	OPT_END()
 };
 
@@ -1141,6 +1139,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
 	struct record *rec = &record;
 	char errbuf[BUFSIZ];
 
+#ifndef HAVE_LIBBPF_SUPPORT
+# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c)
+	set_nobuild('\0', "clang-path", true);
+	set_nobuild('\0', "clang-opt", true);
+# undef set_nobuild
+#endif
+
 	rec->evlist = perf_evlist__new();
 	if (rec->evlist == NULL)
 		return -ENOMEM;
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index de3290b..e22fbde 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -18,20 +18,34 @@ static int opterror(const struct option *opt, const char *reason, int flags)
 	return error("option `%s' %s", opt->long_name, reason);
 }
 
+static void optwarning(const struct option *opt, const char *reason, int flags)
+{
+	if (flags & OPT_SHORT)
+		warning("switch `%c' %s", opt->short_name, reason);
+	else if (flags & OPT_UNSET)
+		warning("option `no-%s' %s", opt->long_name, reason);
+	else
+		warning("option `%s' %s", opt->long_name, reason);
+}
+
 static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
 		   int flags, const char **arg)
 {
+	const char *res;
+
 	if (p->opt) {
-		*arg = p->opt;
+		res = p->opt;
 		p->opt = NULL;
 	} else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
 		    **(p->argv + 1) == '-')) {
-		*arg = (const char *)opt->defval;
+		res = (const char *)opt->defval;
 	} else if (p->argc > 1) {
 		p->argc--;
-		*arg = *++p->argv;
+		res = *++p->argv;
 	} else
 		return opterror(opt, "requires a value", flags);
+	if (arg)
+		*arg = res;
 	return 0;
 }
 
@@ -91,6 +105,64 @@ static int get_value(struct parse_opt_ctx_t *p,
 		}
 	}
 
+	if (opt->flags & PARSE_OPT_NOBUILD) {
+		char reason[128];
+		bool noarg = false;
+
+		err = snprintf(reason, sizeof(reason),
+				opt->flags & PARSE_OPT_CANSKIP ?
+					"is being ignored because %s " :
+					"is not available because %s",
+				opt->build_opt);
+		reason[sizeof(reason) - 1] = '\0';
+
+		if (err < 0)
+			strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
+					"is being ignored" :
+					"is not available",
+					sizeof(reason));
+
+		if (!(opt->flags & PARSE_OPT_CANSKIP))
+			return opterror(opt, reason, flags);
+
+		err = 0;
+		if (unset)
+			noarg = true;
+		if (opt->flags & PARSE_OPT_NOARG)
+			noarg = true;
+		if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+			noarg = true;
+
+		switch (opt->type) {
+		case OPTION_BOOLEAN:
+		case OPTION_INCR:
+		case OPTION_BIT:
+		case OPTION_SET_UINT:
+		case OPTION_SET_PTR:
+		case OPTION_END:
+		case OPTION_ARGUMENT:
+		case OPTION_GROUP:
+			noarg = true;
+			break;
+		case OPTION_CALLBACK:
+		case OPTION_STRING:
+		case OPTION_INTEGER:
+		case OPTION_UINTEGER:
+		case OPTION_LONG:
+		case OPTION_U64:
+		default:
+			break;
+		}
+
+		if (!noarg)
+			err = get_arg(p, opt, flags, NULL);
+		if (err)
+			return err;
+
+		optwarning(opt, reason, flags);
+		return 0;
+	}
+
 	switch (opt->type) {
 	case OPTION_BIT:
 		if (unset)
@@ -645,6 +717,10 @@ static void print_option_help(const struct option *opts, int full)
 		pad = USAGE_OPTS_WIDTH;
 	}
 	fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
+	if (opts->flags & PARSE_OPT_NOBUILD)
+		fprintf(stderr, "%*s(not built-in because %s)\n",
+			USAGE_OPTS_WIDTH + USAGE_GAP, "",
+			opts->build_opt);
 }
 
 static int option__cmp(const void *va, const void *vb)
@@ -848,15 +924,39 @@ int parse_opt_verbosity_cb(const struct option *opt,
 	return 0;
 }
 
-void set_option_flag(struct option *opts, int shortopt, const char *longopt,
-		     int flag)
+static struct option *
+find_option(struct option *opts, int shortopt, const char *longopt)
 {
 	for (; opts->type != OPTION_END; opts++) {
 		if ((shortopt && opts->short_name == shortopt) ||
 		    (opts->long_name && longopt &&
-		     !strcmp(opts->long_name, longopt))) {
-			opts->flags |= flag;
-			break;
-		}
+		     !strcmp(opts->long_name, longopt)))
+			return opts;
 	}
+	return NULL;
+}
+
+void set_option_flag(struct option *opts, int shortopt, const char *longopt,
+		     int flag)
+{
+	struct option *opt = find_option(opts, shortopt, longopt);
+
+	if (opt)
+		opt->flags |= flag;
+	return;
+}
+
+void set_option_nobuild(struct option *opts, int shortopt,
+			const char *longopt,
+			const char *build_opt,
+			bool can_skip)
+{
+	struct option *opt = find_option(opts, shortopt, longopt);
+
+	if (!opt)
+		return;
+
+	opt->flags |= PARSE_OPT_NOBUILD;
+	opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
+	opt->build_opt = build_opt;
 }
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index a8e407b..2cac2aa 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -41,6 +41,8 @@ enum parse_opt_option_flags {
 	PARSE_OPT_DISABLED = 32,
 	PARSE_OPT_EXCLUSIVE = 64,
 	PARSE_OPT_NOEMPTY  = 128,
+	PARSE_OPT_NOBUILD  = 256,
+	PARSE_OPT_CANSKIP  = 512,
 };
 
 struct option;
@@ -96,6 +98,7 @@ struct option {
 	void *value;
 	const char *argh;
 	const char *help;
+	const char *build_opt;
 
 	int flags;
 	parse_opt_cb *callback;
@@ -226,4 +229,6 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
 extern const char *parse_options_fix_filename(const char *prefix, const char *file);
 
 void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag);
+void set_option_nobuild(struct option *opts, int shortopt, const char *longopt,
+			const char *build_opt, bool can_skip);
 #endif /* __PERF_PARSE_OPTIONS_H */
-- 
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/

[toc] | [prev] | [next] | [standalone]


#1291315 — Re: [PATCH v5 13/14] perf tools: Always give options even it not compiled

FromArnaldo Carvalho de Melo <acme@kernel.org>
Date2015-12-14 17:10 +0100
SubjectRe: [PATCH v5 13/14] perf tools: Always give options even it not compiled
Message-ID<qFDRg-8pJ-11@gated-at.bofh.it>
In reply to#1291104
Em Mon, Dec 14, 2015 at 10:39:22AM +0000, Wang Nan escreveu:
> This patch keeps options of perf builtins same in all conditions. If
> one option is disabled because of compiling options, users should be
> notified.
> 
> Masami suggested another implementation in [1] that, by adding a
> OPTION_NEXT_DEPENDS option before those options in the 'struct option'
> array, options parser knows an option is disabled. However, in some
> cases this array is reordered (options__order()). In addition, in
> parse-option.c that array is const, so we can't simply merge
> information in decorator option into the affacted option.
> 
> This patch chooses a simpler implementation that, introducing a
> set_option_nobuild() function and two option parsing flags. Builtins
> with such options should call set_option_nobuild() before option
> parsing. The complexity of this patch is because we want some of options
> can be skipped safely. In this case their arguments should also be
> consumed.
> 
> Options in 'perf record' and 'perf probe' are fixed in this patch.
> 
> [1] http://lkml.kernel.org/g/50399556C9727B4D88A595C8584AAB3752627CD4@GSjpTKYDCembx32.service.hitachi.net
> 
> Test result:
> 
> Normal case:
> 
> # ./perf probe --vmlinux /tmp/vmlinux sys_write

Please add two spaces before command output, even more so when the first
character is a '#', because that will make git consider it as comments
and will then suppress it from the commit logs.

Thanks, tested and applied!

- Arnaldo

> Added new event:
>   probe:sys_write      (on sys_write)
> 
> You can now use it in all perf tools, such as:
> 
> 	perf record -e probe:sys_write -aR sleep 1
> 
> 
> Build with NO_DWARF=1:
> 
> # ./perf probe -L sys_write
>   Error: switch `L' is not available because NO_DWARF=1
> 
>  Usage: perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]
>     or: perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]
>     or: perf probe [<options>] --del '[GROUP:]EVENT' ...
>     or: perf probe --list [GROUP:]EVENT ...
>     or: perf probe [<options>] --funcs
> 
>     -L, --line <FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]>
>                           Show source code lines.
>                           (not built-in because NO_DWARF=1)
> 
> # ./perf probe -k /tmp/vmlinux sys_write
>   Warning: switch `k' is being ignored because NO_DWARF=1
> Added new event:
>   probe:sys_write      (on sys_write)
> 
> You can now use it in all perf tools, such as:
> 
> 	perf record -e probe:sys_write -aR sleep 1
> 
> # ./perf probe --vmlinux /tmp/vmlinux sys_write
>   Warning: option `vmlinux' is being ignored because NO_DWARF=1
> Added new event:
> [SNIP]
> 
> # ./perf probe -l
>  Usage: perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]
>     or: perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]
> ...
>     -k, --vmlinux <file>  vmlinux pathname
>                           (not built-in because NO_DWARF=1)
>     -L, --line <FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]>
>                           Show source code lines.
>                           (not built-in because NO_DWARF=1)
> ...
>     -V, --vars <FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT>
>                           Show accessible variables on PROBEDEF
>                           (not built-in because NO_DWARF=1)
>         --externs         Show external variables too (with --vars only)
>                           (not built-in because NO_DWARF=1)
>         --no-inlines      Don't search inlined functions
>                           (not built-in because NO_DWARF=1)
>         --range           Show variables location range in scope (with --vars only)
>                           (not built-in because NO_DWARF=1)
> 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> Cc: Alexei Starovoitov <ast@kernel.org>
> Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
> Cc: Namhyung Kim <namhyung@kernel.org>
> Cc: Zefan Li <lizefan@huawei.com>
> Cc: pi3orama@163.com
> ---
>  tools/perf/builtin-probe.c      |  15 ++++-
>  tools/perf/builtin-record.c     |   9 ++-
>  tools/perf/util/parse-options.c | 118 +++++++++++++++++++++++++++++++++++++---
>  tools/perf/util/parse-options.h |   5 ++
>  4 files changed, 134 insertions(+), 13 deletions(-)
> 
> diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
> index 132afc9..dbe2ea5 100644
> --- a/tools/perf/builtin-probe.c
> +++ b/tools/perf/builtin-probe.c
> @@ -249,6 +249,9 @@ static int opt_show_vars(const struct option *opt,
>  
>  	return ret;
>  }
> +#else
> +# define opt_show_lines NULL
> +# define opt_show_vars NULL
>  #endif
>  static int opt_add_probe_event(const struct option *opt,
>  			      const char *str, int unset __maybe_unused)
> @@ -473,7 +476,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
>  		opt_add_probe_event),
>  	OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
>  		    " with existing name"),
> -#ifdef HAVE_DWARF_SUPPORT
>  	OPT_CALLBACK('L', "line", NULL,
>  		     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
>  		     "Show source code lines.", opt_show_lines),
> @@ -490,7 +492,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
>  		   "directory", "path to kernel source"),
>  	OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines,
>  		"Don't search inlined functions"),
> -#endif
>  	OPT__DRY_RUN(&probe_event_dry_run),
>  	OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes,
>  		 "Set how many probe points can be found for a probe."),
> @@ -521,6 +522,16 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
>  #ifdef HAVE_DWARF_SUPPORT
>  	set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
>  	set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE);
> +#else
> +# define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_DWARF=1", c)
> +	set_nobuild('L', "line", false);
> +	set_nobuild('V', "vars", false);
> +	set_nobuild('\0', "externs", false);
> +	set_nobuild('\0', "range", false);
> +	set_nobuild('k', "vmlinux", true);
> +	set_nobuild('s', "source", true);
> +	set_nobuild('\0', "no-inlines", true);
> +# undef set_nobuild
>  #endif
>  	set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE);
>  
> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
> index 8479821..11bf32d 100644
> --- a/tools/perf/builtin-record.c
> +++ b/tools/perf/builtin-record.c
> @@ -1124,12 +1124,10 @@ struct option __record_options[] = {
>  			"per thread proc mmap processing timeout in ms"),
>  	OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
>  		    "Record context switch events"),
> -#ifdef HAVE_LIBBPF_SUPPORT
>  	OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
>  		   "clang binary to use for compiling BPF scriptlets"),
>  	OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
>  		   "options passed to clang when compiling BPF scriptlets"),
> -#endif
>  	OPT_END()
>  };
>  
> @@ -1141,6 +1139,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
>  	struct record *rec = &record;
>  	char errbuf[BUFSIZ];
>  
> +#ifndef HAVE_LIBBPF_SUPPORT
> +# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c)
> +	set_nobuild('\0', "clang-path", true);
> +	set_nobuild('\0', "clang-opt", true);
> +# undef set_nobuild
> +#endif
> +
>  	rec->evlist = perf_evlist__new();
>  	if (rec->evlist == NULL)
>  		return -ENOMEM;
> diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
> index de3290b..e22fbde 100644
> --- a/tools/perf/util/parse-options.c
> +++ b/tools/perf/util/parse-options.c
> @@ -18,20 +18,34 @@ static int opterror(const struct option *opt, const char *reason, int flags)
>  	return error("option `%s' %s", opt->long_name, reason);
>  }
>  
> +static void optwarning(const struct option *opt, const char *reason, int flags)
> +{
> +	if (flags & OPT_SHORT)
> +		warning("switch `%c' %s", opt->short_name, reason);
> +	else if (flags & OPT_UNSET)
> +		warning("option `no-%s' %s", opt->long_name, reason);
> +	else
> +		warning("option `%s' %s", opt->long_name, reason);
> +}
> +
>  static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
>  		   int flags, const char **arg)
>  {
> +	const char *res;
> +
>  	if (p->opt) {
> -		*arg = p->opt;
> +		res = p->opt;
>  		p->opt = NULL;
>  	} else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
>  		    **(p->argv + 1) == '-')) {
> -		*arg = (const char *)opt->defval;
> +		res = (const char *)opt->defval;
>  	} else if (p->argc > 1) {
>  		p->argc--;
> -		*arg = *++p->argv;
> +		res = *++p->argv;
>  	} else
>  		return opterror(opt, "requires a value", flags);
> +	if (arg)
> +		*arg = res;
>  	return 0;
>  }
>  
> @@ -91,6 +105,64 @@ static int get_value(struct parse_opt_ctx_t *p,
>  		}
>  	}
>  
> +	if (opt->flags & PARSE_OPT_NOBUILD) {
> +		char reason[128];
> +		bool noarg = false;
> +
> +		err = snprintf(reason, sizeof(reason),
> +				opt->flags & PARSE_OPT_CANSKIP ?
> +					"is being ignored because %s " :
> +					"is not available because %s",
> +				opt->build_opt);
> +		reason[sizeof(reason) - 1] = '\0';
> +
> +		if (err < 0)
> +			strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
> +					"is being ignored" :
> +					"is not available",
> +					sizeof(reason));
> +
> +		if (!(opt->flags & PARSE_OPT_CANSKIP))
> +			return opterror(opt, reason, flags);
> +
> +		err = 0;
> +		if (unset)
> +			noarg = true;
> +		if (opt->flags & PARSE_OPT_NOARG)
> +			noarg = true;
> +		if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
> +			noarg = true;
> +
> +		switch (opt->type) {
> +		case OPTION_BOOLEAN:
> +		case OPTION_INCR:
> +		case OPTION_BIT:
> +		case OPTION_SET_UINT:
> +		case OPTION_SET_PTR:
> +		case OPTION_END:
> +		case OPTION_ARGUMENT:
> +		case OPTION_GROUP:
> +			noarg = true;
> +			break;
> +		case OPTION_CALLBACK:
> +		case OPTION_STRING:
> +		case OPTION_INTEGER:
> +		case OPTION_UINTEGER:
> +		case OPTION_LONG:
> +		case OPTION_U64:
> +		default:
> +			break;
> +		}
> +
> +		if (!noarg)
> +			err = get_arg(p, opt, flags, NULL);
> +		if (err)
> +			return err;
> +
> +		optwarning(opt, reason, flags);
> +		return 0;
> +	}
> +
>  	switch (opt->type) {
>  	case OPTION_BIT:
>  		if (unset)
> @@ -645,6 +717,10 @@ static void print_option_help(const struct option *opts, int full)
>  		pad = USAGE_OPTS_WIDTH;
>  	}
>  	fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
> +	if (opts->flags & PARSE_OPT_NOBUILD)
> +		fprintf(stderr, "%*s(not built-in because %s)\n",
> +			USAGE_OPTS_WIDTH + USAGE_GAP, "",
> +			opts->build_opt);
>  }
>  
>  static int option__cmp(const void *va, const void *vb)
> @@ -848,15 +924,39 @@ int parse_opt_verbosity_cb(const struct option *opt,
>  	return 0;
>  }
>  
> -void set_option_flag(struct option *opts, int shortopt, const char *longopt,
> -		     int flag)
> +static struct option *
> +find_option(struct option *opts, int shortopt, const char *longopt)
>  {
>  	for (; opts->type != OPTION_END; opts++) {
>  		if ((shortopt && opts->short_name == shortopt) ||
>  		    (opts->long_name && longopt &&
> -		     !strcmp(opts->long_name, longopt))) {
> -			opts->flags |= flag;
> -			break;
> -		}
> +		     !strcmp(opts->long_name, longopt)))
> +			return opts;
>  	}
> +	return NULL;
> +}
> +
> +void set_option_flag(struct option *opts, int shortopt, const char *longopt,
> +		     int flag)
> +{
> +	struct option *opt = find_option(opts, shortopt, longopt);
> +
> +	if (opt)
> +		opt->flags |= flag;
> +	return;
> +}
> +
> +void set_option_nobuild(struct option *opts, int shortopt,
> +			const char *longopt,
> +			const char *build_opt,
> +			bool can_skip)
> +{
> +	struct option *opt = find_option(opts, shortopt, longopt);
> +
> +	if (!opt)
> +		return;
> +
> +	opt->flags |= PARSE_OPT_NOBUILD;
> +	opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
> +	opt->build_opt = build_opt;
>  }
> diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
> index a8e407b..2cac2aa 100644
> --- a/tools/perf/util/parse-options.h
> +++ b/tools/perf/util/parse-options.h
> @@ -41,6 +41,8 @@ enum parse_opt_option_flags {
>  	PARSE_OPT_DISABLED = 32,
>  	PARSE_OPT_EXCLUSIVE = 64,
>  	PARSE_OPT_NOEMPTY  = 128,
> +	PARSE_OPT_NOBUILD  = 256,
> +	PARSE_OPT_CANSKIP  = 512,
>  };
>  
>  struct option;
> @@ -96,6 +98,7 @@ struct option {
>  	void *value;
>  	const char *argh;
>  	const char *help;
> +	const char *build_opt;
>  
>  	int flags;
>  	parse_opt_cb *callback;
> @@ -226,4 +229,6 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
>  extern const char *parse_options_fix_filename(const char *prefix, const char *file);
>  
>  void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag);
> +void set_option_nobuild(struct option *opts, int shortopt, const char *longopt,
> +			const char *build_opt, bool can_skip);
>  #endif /* __PERF_PARSE_OPTIONS_H */
> -- 
> 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/

[toc] | [prev] | [next] | [standalone]


#1294538 — [tip:perf/core] perf tools: Make options always available, even if required libs not linked

Fromtip-bot for Wang Nan <tipbot@zytor.com>
Date2015-12-18 10:00 +0100
Subject[tip:perf/core] perf tools: Make options always available, even if required libs not linked
Message-ID<qGZ3l-3mL-37@gated-at.bofh.it>
In reply to#1291104
Commit-ID:  48e1cab1ba4db84fbc26379b887ba94a180347fe
Gitweb:     http://git.kernel.org/tip/48e1cab1ba4db84fbc26379b887ba94a180347fe
Author:     Wang Nan <wangnan0@huawei.com>
AuthorDate: Mon, 14 Dec 2015 10:39:22 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 14 Dec 2015 12:57:32 -0300

perf tools: Make options always available, even if required libs not linked

This patch keeps options of perf builtins same in all conditions. If
one option is disabled because of compiling options, users should be
notified.

Masami suggested another implementation in [1] that, by adding a
OPTION_NEXT_DEPENDS option before those options in the 'struct option'
array, options parser knows an option is disabled. However, in some
cases this array is reordered (options__order()). In addition, in
parse-option.c that array is const, so we can't simply merge
information in decorator option into the affacted option.

This patch chooses a simpler implementation that, introducing a
set_option_nobuild() function and two option parsing flags. Builtins
with such options should call set_option_nobuild() before option
parsing. The complexity of this patch is because we want some of options
can be skipped safely. In this case their arguments should also be
consumed.

Options in 'perf record' and 'perf probe' are fixed in this patch.

[1] http://lkml.kernel.org/g/50399556C9727B4D88A595C8584AAB3752627CD4@GSjpTKYDCembx32.service.hitachi.net

Test result:

Normal case:

  # ./perf probe --vmlinux /tmp/vmlinux sys_write
  Added new event:
    probe:sys_write      (on sys_write)

  You can now use it in all perf tools, such as:

	perf record -e probe:sys_write -aR sleep 1

Build with NO_DWARF=1:

  # ./perf probe -L sys_write
    Error: switch `L' is not available because NO_DWARF=1

   Usage: perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]
      or: perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]
      or: perf probe [<options>] --del '[GROUP:]EVENT' ...
      or: perf probe --list [GROUP:]EVENT ...
      or: perf probe [<options>] --funcs

    -L, --line <FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]>
                          Show source code lines.
                          (not built-in because NO_DWARF=1)

  # ./perf probe -k /tmp/vmlinux sys_write
    Warning: switch `k' is being ignored because NO_DWARF=1
  Added new event:
    probe:sys_write      (on sys_write)

  You can now use it in all perf tools, such as:

	perf record -e probe:sys_write -aR sleep 1

  # ./perf probe --vmlinux /tmp/vmlinux sys_write
    Warning: option `vmlinux' is being ignored because NO_DWARF=1
  Added new event:
  [SNIP]

  # ./perf probe -l
   Usage: perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]
      or: perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]
...
    -k, --vmlinux <file>  vmlinux pathname
                          (not built-in because NO_DWARF=1)
    -L, --line <FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]>
                          Show source code lines.
                          (not built-in because NO_DWARF=1)
...
    -V, --vars <FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT>
                          Show accessible variables on PROBEDEF
                          (not built-in because NO_DWARF=1)
        --externs         Show external variables too (with --vars only)
                          (not built-in because NO_DWARF=1)
        --no-inlines      Don't search inlined functions
                          (not built-in because NO_DWARF=1)
        --range           Show variables location range in scope (with --vars only)
                          (not built-in because NO_DWARF=1)

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1450089563-122430-14-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/builtin-probe.c      |  15 ++++-
 tools/perf/builtin-record.c     |   9 ++-
 tools/perf/util/parse-options.c | 118 +++++++++++++++++++++++++++++++++++++---
 tools/perf/util/parse-options.h |   5 ++
 4 files changed, 134 insertions(+), 13 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 132afc9..dbe2ea5 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -249,6 +249,9 @@ static int opt_show_vars(const struct option *opt,
 
 	return ret;
 }
+#else
+# define opt_show_lines NULL
+# define opt_show_vars NULL
 #endif
 static int opt_add_probe_event(const struct option *opt,
 			      const char *str, int unset __maybe_unused)
@@ -473,7 +476,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 		opt_add_probe_event),
 	OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
 		    " with existing name"),
-#ifdef HAVE_DWARF_SUPPORT
 	OPT_CALLBACK('L', "line", NULL,
 		     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
 		     "Show source code lines.", opt_show_lines),
@@ -490,7 +492,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 		   "directory", "path to kernel source"),
 	OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines,
 		"Don't search inlined functions"),
-#endif
 	OPT__DRY_RUN(&probe_event_dry_run),
 	OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes,
 		 "Set how many probe points can be found for a probe."),
@@ -521,6 +522,16 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 #ifdef HAVE_DWARF_SUPPORT
 	set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
 	set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE);
+#else
+# define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_DWARF=1", c)
+	set_nobuild('L', "line", false);
+	set_nobuild('V', "vars", false);
+	set_nobuild('\0', "externs", false);
+	set_nobuild('\0', "range", false);
+	set_nobuild('k', "vmlinux", true);
+	set_nobuild('s', "source", true);
+	set_nobuild('\0', "no-inlines", true);
+# undef set_nobuild
 #endif
 	set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE);
 
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 199fc31..c2ba377e 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1113,12 +1113,10 @@ struct option __record_options[] = {
 			"per thread proc mmap processing timeout in ms"),
 	OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
 		    "Record context switch events"),
-#ifdef HAVE_LIBBPF_SUPPORT
 	OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
 		   "clang binary to use for compiling BPF scriptlets"),
 	OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
 		   "options passed to clang when compiling BPF scriptlets"),
-#endif
 	OPT_END()
 };
 
@@ -1130,6 +1128,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
 	struct record *rec = &record;
 	char errbuf[BUFSIZ];
 
+#ifndef HAVE_LIBBPF_SUPPORT
+# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c)
+	set_nobuild('\0', "clang-path", true);
+	set_nobuild('\0', "clang-opt", true);
+# undef set_nobuild
+#endif
+
 	rec->evlist = perf_evlist__new();
 	if (rec->evlist == NULL)
 		return -ENOMEM;
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 14b2bee..0ad1384 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -18,20 +18,34 @@ static int opterror(const struct option *opt, const char *reason, int flags)
 	return error("option `%s' %s", opt->long_name, reason);
 }
 
+static void optwarning(const struct option *opt, const char *reason, int flags)
+{
+	if (flags & OPT_SHORT)
+		warning("switch `%c' %s", opt->short_name, reason);
+	else if (flags & OPT_UNSET)
+		warning("option `no-%s' %s", opt->long_name, reason);
+	else
+		warning("option `%s' %s", opt->long_name, reason);
+}
+
 static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
 		   int flags, const char **arg)
 {
+	const char *res;
+
 	if (p->opt) {
-		*arg = p->opt;
+		res = p->opt;
 		p->opt = NULL;
 	} else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
 		    **(p->argv + 1) == '-')) {
-		*arg = (const char *)opt->defval;
+		res = (const char *)opt->defval;
 	} else if (p->argc > 1) {
 		p->argc--;
-		*arg = *++p->argv;
+		res = *++p->argv;
 	} else
 		return opterror(opt, "requires a value", flags);
+	if (arg)
+		*arg = res;
 	return 0;
 }
 
@@ -91,6 +105,64 @@ static int get_value(struct parse_opt_ctx_t *p,
 		}
 	}
 
+	if (opt->flags & PARSE_OPT_NOBUILD) {
+		char reason[128];
+		bool noarg = false;
+
+		err = snprintf(reason, sizeof(reason),
+				opt->flags & PARSE_OPT_CANSKIP ?
+					"is being ignored because %s " :
+					"is not available because %s",
+				opt->build_opt);
+		reason[sizeof(reason) - 1] = '\0';
+
+		if (err < 0)
+			strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
+					"is being ignored" :
+					"is not available",
+					sizeof(reason));
+
+		if (!(opt->flags & PARSE_OPT_CANSKIP))
+			return opterror(opt, reason, flags);
+
+		err = 0;
+		if (unset)
+			noarg = true;
+		if (opt->flags & PARSE_OPT_NOARG)
+			noarg = true;
+		if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+			noarg = true;
+
+		switch (opt->type) {
+		case OPTION_BOOLEAN:
+		case OPTION_INCR:
+		case OPTION_BIT:
+		case OPTION_SET_UINT:
+		case OPTION_SET_PTR:
+		case OPTION_END:
+		case OPTION_ARGUMENT:
+		case OPTION_GROUP:
+			noarg = true;
+			break;
+		case OPTION_CALLBACK:
+		case OPTION_STRING:
+		case OPTION_INTEGER:
+		case OPTION_UINTEGER:
+		case OPTION_LONG:
+		case OPTION_U64:
+		default:
+			break;
+		}
+
+		if (!noarg)
+			err = get_arg(p, opt, flags, NULL);
+		if (err)
+			return err;
+
+		optwarning(opt, reason, flags);
+		return 0;
+	}
+
 	switch (opt->type) {
 	case OPTION_BIT:
 		if (unset)
@@ -645,6 +717,10 @@ static void print_option_help(const struct option *opts, int full)
 		pad = USAGE_OPTS_WIDTH;
 	}
 	fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
+	if (opts->flags & PARSE_OPT_NOBUILD)
+		fprintf(stderr, "%*s(not built-in because %s)\n",
+			USAGE_OPTS_WIDTH + USAGE_GAP, "",
+			opts->build_opt);
 }
 
 static int option__cmp(const void *va, const void *vb)
@@ -848,15 +924,39 @@ int parse_opt_verbosity_cb(const struct option *opt,
 	return 0;
 }
 
-void set_option_flag(struct option *opts, int shortopt, const char *longopt,
-		     int flag)
+static struct option *
+find_option(struct option *opts, int shortopt, const char *longopt)
 {
 	for (; opts->type != OPTION_END; opts++) {
 		if ((shortopt && opts->short_name == shortopt) ||
 		    (opts->long_name && longopt &&
-		     !strcmp(opts->long_name, longopt))) {
-			opts->flags |= flag;
-			break;
-		}
+		     !strcmp(opts->long_name, longopt)))
+			return opts;
 	}
+	return NULL;
+}
+
+void set_option_flag(struct option *opts, int shortopt, const char *longopt,
+		     int flag)
+{
+	struct option *opt = find_option(opts, shortopt, longopt);
+
+	if (opt)
+		opt->flags |= flag;
+	return;
+}
+
+void set_option_nobuild(struct option *opts, int shortopt,
+			const char *longopt,
+			const char *build_opt,
+			bool can_skip)
+{
+	struct option *opt = find_option(opts, shortopt, longopt);
+
+	if (!opt)
+		return;
+
+	opt->flags |= PARSE_OPT_NOBUILD;
+	opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
+	opt->build_opt = build_opt;
 }
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index dd1236d..1231960 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -41,6 +41,8 @@ enum parse_opt_option_flags {
 	PARSE_OPT_DISABLED = 32,
 	PARSE_OPT_EXCLUSIVE = 64,
 	PARSE_OPT_NOEMPTY  = 128,
+	PARSE_OPT_NOBUILD  = 256,
+	PARSE_OPT_CANSKIP  = 512,
 };
 
 struct option;
@@ -96,6 +98,7 @@ struct option {
 	void *value;
 	const char *argh;
 	const char *help;
+	const char *build_opt;
 
 	int flags;
 	parse_opt_cb *callback;
@@ -217,4 +220,6 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
 extern const char *parse_options_fix_filename(const char *prefix, const char *file);
 
 void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag);
+void set_option_nobuild(struct option *opts, int shortopt, const char *longopt,
+			const char *build_opt, bool can_skip);
 #endif /* __PERF_PARSE_OPTIONS_H */
--
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/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web