From 35a23ff928b066b00a826d0a9ed9411b8ab479ef Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 12 Jun 2015 14:08:20 +0900 Subject: perf probe: Cut off the gcc optimization postfixes from function name Cut off the postfixes which gcc added for optimized routines from the event name automatically generated from symbol name, since *probe-events doesn't accept it. Those symbols will be used if we don't use debuginfo to find target functions. E.g. without this fix; ----- # perf probe -va alloc_buf.isra.23 probe-definition(0): alloc_buf.isra.23 symbol:alloc_buf.isra.23 file:(null) line:0 offset:0 return:0 lazy:(null) [...] Opening /sys/kernel/debug/tracing/kprobe_events write=1 Added new event: Writing event: p:probe/alloc_buf.isra.23 _text+4869328 Failed to write event: Invalid argument Error: Failed to add events. Reason: Invalid argument (Code: -22) ----- With this fix; ----- perf probe -va alloc_buf.isra.23 probe-definition(0): alloc_buf.isra.23 symbol:alloc_buf.isra.23 file:(null) line:0 offset:0 return:0 lazy:(null) [...] Opening /sys/kernel/debug/tracing/kprobe_events write=1 Added new event: Writing event: p:probe/alloc_buf _text+4869328 probe:alloc_buf (on alloc_buf.isra.23) You can now use it in all perf tools, such as: perf record -e probe:alloc_buf -aR sleep 1 ----- Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Naohiro Aota Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20150612050820.20548.41625.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tools/perf') diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index d4cf50b91839..daa24a249e05 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2316,6 +2316,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base, struct strlist *namelist, bool allow_suffix) { int i, ret; + char *p; if (*base == '.') base++; @@ -2326,6 +2327,10 @@ static int get_new_event_name(char *buf, size_t len, const char *base, pr_debug("snprintf() failed: %d\n", ret); return ret; } + /* Cut off the postfixes (e.g. .const, .isra)*/ + p = strchr(buf, '.'); + if (p && p != buf) + *p = '\0'; if (!strlist__has_entry(namelist, buf)) return 0; -- cgit v1.2.1 From 5c24b67aae72f54c5d2a6898be4bae9726df63bb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 15 Jun 2015 23:29:51 -0300 Subject: perf tools: Replace map->referenced & maps->removed_maps with map->refcnt Use just reference counts, so that when no more hist_entry instances references a map and the thread instance goes away by processing a PERF_RECORD_EXIT, we can delete the maps. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-oym7lfhcc7ss6xpz44h7nbxs@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 37 +++++++++++++++++++------------- tools/perf/util/map.c | 58 ++------------------------------------------------ tools/perf/util/map.h | 10 +++++++-- 3 files changed, 32 insertions(+), 73 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index f53d017c7c22..6f28d53d4e46 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -313,8 +313,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, memset(&he->stat, 0, sizeof(he->stat)); } - if (he->ms.map) - he->ms.map->referenced = true; + map__get(he->ms.map); if (he->branch_info) { /* @@ -324,6 +323,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, */ he->branch_info = malloc(sizeof(*he->branch_info)); if (he->branch_info == NULL) { + map__zput(he->ms.map); free(he->stat_acc); free(he); return NULL; @@ -332,17 +332,13 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, memcpy(he->branch_info, template->branch_info, sizeof(*he->branch_info)); - if (he->branch_info->from.map) - he->branch_info->from.map->referenced = true; - if (he->branch_info->to.map) - he->branch_info->to.map->referenced = true; + map__get(he->branch_info->from.map); + map__get(he->branch_info->to.map); } if (he->mem_info) { - if (he->mem_info->iaddr.map) - he->mem_info->iaddr.map->referenced = true; - if (he->mem_info->daddr.map) - he->mem_info->daddr.map->referenced = true; + map__get(he->mem_info->iaddr.map); + map__get(he->mem_info->daddr.map); } if (symbol_conf.use_callchain) @@ -407,9 +403,8 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists, * the history counter to increment. */ if (he->ms.map != entry->ms.map) { - he->ms.map = entry->ms.map; - if (he->ms.map) - he->ms.map->referenced = true; + map__put(he->ms.map); + he->ms.map = map__get(entry->ms.map); } goto out; } @@ -933,8 +928,20 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) void hist_entry__delete(struct hist_entry *he) { thread__zput(he->thread); - zfree(&he->branch_info); - zfree(&he->mem_info); + map__zput(he->ms.map); + + if (he->branch_info) { + map__zput(he->branch_info->from.map); + map__zput(he->branch_info->to.map); + zfree(&he->branch_info); + } + + if (he->mem_info) { + map__zput(he->mem_info->iaddr.map); + map__zput(he->mem_info->daddr.map); + zfree(&he->mem_info); + } + zfree(&he->stat_acc); free_srcline(he->srcline); free_callchain(he->callchain); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 1241ab989cf5..b5a5e9c02437 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -137,7 +137,6 @@ void map__init(struct map *map, enum map_type type, map->unmap_ip = map__unmap_ip; RB_CLEAR_NODE(&map->rb_node); map->groups = NULL; - map->referenced = false; map->erange_warned = false; atomic_set(&map->refcnt, 1); } @@ -439,7 +438,6 @@ static void maps__init(struct maps *maps) { maps->entries = RB_ROOT; pthread_rwlock_init(&maps->lock, NULL); - INIT_LIST_HEAD(&maps->removed_maps); } void map_groups__init(struct map_groups *mg, struct machine *machine) @@ -466,21 +464,10 @@ static void __maps__purge(struct maps *maps) } } -static void __maps__purge_removed_maps(struct maps *maps) -{ - struct map *pos, *n; - - list_for_each_entry_safe(pos, n, &maps->removed_maps, node) { - list_del_init(&pos->node); - map__put(pos); - } -} - static void maps__exit(struct maps *maps) { pthread_rwlock_wrlock(&maps->lock); __maps__purge(maps); - __maps__purge_removed_maps(maps); pthread_rwlock_unlock(&maps->lock); } @@ -499,8 +486,6 @@ bool map_groups__empty(struct map_groups *mg) for (i = 0; i < MAP__NR_TYPES; ++i) { if (maps__first(&mg->maps[i])) return false; - if (!list_empty(&mg->maps[i].removed_maps)) - return false; } return true; @@ -621,7 +606,7 @@ size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type, return printed += maps__fprintf(&mg->maps[type], fp); } -static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp) +size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) { size_t printed = 0, i; for (i = 0; i < MAP__NR_TYPES; ++i) @@ -629,39 +614,6 @@ static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp) return printed; } -static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, - enum map_type type, FILE *fp) -{ - struct map *pos; - size_t printed = 0; - - list_for_each_entry(pos, &mg->maps[type].removed_maps, node) { - printed += fprintf(fp, "Map:"); - printed += map__fprintf(pos, fp); - if (verbose > 1) { - printed += dso__fprintf(pos->dso, type, fp); - printed += fprintf(fp, "--\n"); - } - } - return printed; -} - -static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, - FILE *fp) -{ - size_t printed = 0, i; - for (i = 0; i < MAP__NR_TYPES; ++i) - printed += __map_groups__fprintf_removed_maps(mg, i, fp); - return printed; -} - -size_t map_groups__fprintf(struct map_groups *mg, FILE *fp) -{ - size_t printed = map_groups__fprintf_maps(mg, fp); - printed += fprintf(fp, "Removed maps:\n"); - return printed + map_groups__fprintf_removed_maps(mg, fp); -} - static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) { struct rb_root *root; @@ -719,13 +671,7 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp map__fprintf(after, fp); } put_map: - /* - * If we have references, just move them to a separate list. - */ - if (pos->referenced) - list_add_tail(&pos->node, &maps->removed_maps); - else - map__put(pos); + map__put(pos); if (err) goto out; diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index b8df09d94aca..d73e687b224e 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -34,7 +34,6 @@ struct map { u64 start; u64 end; u8 /* enum map_type */ type; - bool referenced; bool erange_warned; u32 priv; u32 prot; @@ -63,7 +62,6 @@ struct kmap { struct maps { struct rb_root entries; pthread_rwlock_t lock; - struct list_head removed_maps; }; struct map_groups { @@ -161,6 +159,14 @@ static inline struct map *map__get(struct map *map) void map__put(struct map *map); +static inline void __map__zput(struct map **map) +{ + map__put(*map); + *map = NULL; +} + +#define map__zput(map) __map__zput(&map) + int map__overlap(struct map *l, struct map *r); size_t map__fprintf(struct map *map, FILE *fp); size_t map__fprintf_dsoname(struct map *map, FILE *fp); -- cgit v1.2.1 From a35489a6a217f0396c979009b0c875d871434737 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Fri, 12 Jun 2015 03:17:11 +0000 Subject: tools lib traceevent: Fix python/perf.so compiling error 'make build-test' finds an error that make_python_perf_so fails due to missing of libtraceevent-dynamic-list: '.../python2' util/setup.py \ --quiet build_ext; \ mkdir -p python && \ cp python_ext_build/lib/perf.so python/ /path/to/ld: cannot open linker script file /path/to/kernel/tools/lib/traceevent/libtraceevent-dynamic-list: No such file or directory collect2: error: ld returned 1 exit status error: command 'x86_64-linux-gcc' failed with exit status 1 cp: cannot stat 'python_ext_build/lib/perf.so': No such file or directory make[3]: *** [python/perf.so] Error 1 make[2]: *** [python/perf.so] Error 2 test: test -f ./python/perf.so make[1]: *** [make_python_perf_so] Error 1 make: *** [build-test] Error 2 make: Leaving directory `/path/to/kernel/tools/perf' This is caused by commit e3d09ec8126fe2c9a3ade661e2126e215ca27a80 ("tools lib traceevent: Export dynamic symbols used by traceevent plugins") that, it adds the list file to LDFLAGS but forgot to add it to dependency list of python/perf.so. This patch fixes this problem. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: He Kuang Cc: Peter Zijlstra Cc: Zefan Li Link: http://lkml.kernel.org/r/1434079031-123162-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf') diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index b1dfcd8e93e3..374378322db9 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -190,7 +190,7 @@ python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPI) -$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) +$(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBTRACEEVENT_DYNAMIC_LIST) $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ --quiet build_ext; \ mkdir -p $(OUTPUT)python && \ -- cgit v1.2.1 From ba7ecb02e7b89b09d8cdf4c1514a386af8916c4b Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 13 Jun 2015 10:31:16 +0900 Subject: perf probe: List probes in stdout Since commit 5e17b28f1e24 ("perf probe: Add --quiet option to suppress output result message") have replaced printf with pr_info, perf probe -l outputs its result in stderr. However, that is not what the commit expected. E.g.: # perf probe -l > /dev/null probe:vfs_read (on vfs_read@ksrc/linux-3/fs/read_write.c) With this fix: # perf probe -l > list # cat list probe:vfs_read (on vfs_read@ksrc/linux-3/fs/read_write.c) Of course, --quiet(-q) still works on --add/--del. # perf probe -q vfs_write # perf probe -l probe:vfs_read (on vfs_read@ksrc/linux-3/fs/read_write.c) probe:vfs_write (on vfs_write@ksrc/linux-3/fs/read_write.c) ----- Reported-by: Naohiro Aota Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Naohiro Aota Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20150613013116.24402.2923.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 49 ++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 14 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index daa24a249e05..c4ab58870fcc 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2126,9 +2126,9 @@ kprobe_blacklist__find_by_address(struct list_head *blacklist, return NULL; } -/* Show an event */ -static int show_perf_probe_event(struct perf_probe_event *pev, - const char *module) +static int perf_probe_event__sprintf(struct perf_probe_event *pev, + const char *module, + struct strbuf *result) { int i, ret; char buf[128]; @@ -2141,27 +2141,47 @@ static int show_perf_probe_event(struct perf_probe_event *pev, ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); if (ret < 0) - return ret; + goto out; - pr_info(" %-20s (on %s", buf, place); + strbuf_addf(result, " %-20s (on %s", buf, place); if (module) - pr_info(" in %s", module); + strbuf_addf(result, " in %s", module); if (pev->nargs > 0) { - pr_info(" with"); + strbuf_addstr(result, " with"); for (i = 0; i < pev->nargs; i++) { ret = synthesize_perf_probe_arg(&pev->args[i], buf, 128); if (ret < 0) - break; - pr_info(" %s", buf); + goto out; + strbuf_addf(result, " %s", buf); } } - pr_info(")\n"); + strbuf_addch(result, ')'); +out: free(place); return ret; } +/* Show an event */ +static int show_perf_probe_event(struct perf_probe_event *pev, + const char *module, bool use_stdout) +{ + struct strbuf buf = STRBUF_INIT; + int ret; + + ret = perf_probe_event__sprintf(pev, module, &buf); + if (ret >= 0) { + if (use_stdout) + printf("%s\n", buf.buf); + else + pr_info("%s\n", buf.buf); + } + strbuf_release(&buf); + + return ret; +} + static bool filter_probe_trace_event(struct probe_trace_event *tev, struct strfilter *filter) { @@ -2200,9 +2220,10 @@ static int __show_perf_probe_events(int fd, bool is_kprobe, goto next; ret = convert_to_perf_probe_event(&tev, &pev, is_kprobe); - if (ret >= 0) - ret = show_perf_probe_event(&pev, - tev.point.module); + if (ret < 0) + goto next; + ret = show_perf_probe_event(&pev, tev.point.module, + true); } next: clear_perf_probe_event(&pev); @@ -2468,7 +2489,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, group = pev->group; pev->event = tev->event; pev->group = tev->group; - show_perf_probe_event(pev, tev->point.module); + show_perf_probe_event(pev, tev->point.module, false); /* Trick here - restore current event/group */ pev->event = (char *)event; pev->group = (char *)group; -- cgit v1.2.1 From b45f65e8fddc89ac6b46388908d3f6ac728be372 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 14 Jun 2015 10:19:16 +0200 Subject: perf tools: Introduce xyarray__reset function To zero all the xyarray contents. It will be used in following patches. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1434269985-521-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/xyarray.c | 8 ++++++++ tools/perf/util/xyarray.h | 2 ++ 2 files changed, 10 insertions(+) (limited to 'tools/perf') diff --git a/tools/perf/util/xyarray.c b/tools/perf/util/xyarray.c index 22afbf6c536a..c10ba41ef3f6 100644 --- a/tools/perf/util/xyarray.c +++ b/tools/perf/util/xyarray.c @@ -9,11 +9,19 @@ struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size) if (xy != NULL) { xy->entry_size = entry_size; xy->row_size = row_size; + xy->entries = xlen * ylen; } return xy; } +void xyarray__reset(struct xyarray *xy) +{ + size_t n = xy->entries * xy->entry_size; + + memset(xy->contents, 0, n); +} + void xyarray__delete(struct xyarray *xy) { free(xy); diff --git a/tools/perf/util/xyarray.h b/tools/perf/util/xyarray.h index c488a07275dd..7f30af371b7e 100644 --- a/tools/perf/util/xyarray.h +++ b/tools/perf/util/xyarray.h @@ -6,11 +6,13 @@ struct xyarray { size_t row_size; size_t entry_size; + size_t entries; char contents[]; }; struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size); void xyarray__delete(struct xyarray *xy); +void xyarray__reset(struct xyarray *xy); static inline void *xyarray__entry(struct xyarray *xy, int x, int y) { -- cgit v1.2.1 From 9d7e8c3a96e5a903a4e0951e08f7fa6957170bef Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 14 Jun 2015 10:19:17 +0200 Subject: perf tools: Add thread_map__(alloc|realloc) helpers In order to have 'struct thread_map' allocation on single place and can change it easily in following patch. Using alloc|realloc for static helpers, because thread_map__new is already used in public interface. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1434269985-521-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/thread_map.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index f93b9734735b..f4822bd03709 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c @@ -20,6 +20,15 @@ static int filter(const struct dirent *dir) return 1; } +static struct thread_map *thread_map__realloc(struct thread_map *map, int nr) +{ + size_t size = sizeof(*map) + sizeof(pid_t) * nr; + + return realloc(map, size); +} + +#define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr) + struct thread_map *thread_map__new_by_pid(pid_t pid) { struct thread_map *threads; @@ -33,7 +42,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) if (items <= 0) return NULL; - threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); + threads = thread_map__alloc(items); if (threads != NULL) { for (i = 0; i < items; i++) threads->map[i] = atoi(namelist[i]->d_name); @@ -49,7 +58,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) struct thread_map *thread_map__new_by_tid(pid_t tid) { - struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t)); + struct thread_map *threads = thread_map__alloc(1); if (threads != NULL) { threads->map[0] = tid; @@ -65,8 +74,8 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) int max_threads = 32, items, i; char path[256]; struct dirent dirent, *next, **namelist = NULL; - struct thread_map *threads = malloc(sizeof(*threads) + - max_threads * sizeof(pid_t)); + struct thread_map *threads = thread_map__alloc(max_threads); + if (threads == NULL) goto out; @@ -185,8 +194,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) goto out_free_threads; total_tasks += items; - nt = realloc(threads, (sizeof(*threads) + - sizeof(pid_t) * total_tasks)); + nt = thread_map__realloc(threads, total_tasks); if (nt == NULL) goto out_free_namelist; @@ -216,7 +224,7 @@ out_free_threads: struct thread_map *thread_map__new_dummy(void) { - struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t)); + struct thread_map *threads = thread_map__alloc(1); if (threads != NULL) { threads->map[0] = -1; @@ -253,7 +261,7 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) continue; ntasks++; - nt = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks); + nt = thread_map__realloc(threads, ntasks); if (nt == NULL) goto out_free_threads; -- cgit v1.2.1 From a9a3a4d92d8f2fb68f4b99d98505bebc70518599 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 14 Jun 2015 10:19:26 +0200 Subject: perf tools: Move perf_evsel__(alloc|free|reset)_counts into stat object It's stat specific. Updating python build objects with stat.c. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1434269985-521-12-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/openat-syscall-all-cpus.c | 1 + tools/perf/util/evsel.c | 19 +------------------ tools/perf/util/evsel.h | 3 --- tools/perf/util/python-ext-sources | 1 + tools/perf/util/stat.c | 18 ++++++++++++++++++ tools/perf/util/stat.h | 3 +++ 6 files changed, 24 insertions(+), 21 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index e34dfdf96b5a..9a7a116e09b8 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -3,6 +3,7 @@ #include "thread_map.h" #include "cpumap.h" #include "debug.h" +#include "stat.h" int test__openat_syscall_event_on_all_cpus(void) { diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index d4f9994ae47f..33449decf7bd 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -26,6 +26,7 @@ #include "perf_regs.h" #include "debug.h" #include "trace-event.h" +#include "stat.h" static struct { bool sample_id_all; @@ -851,19 +852,6 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) return 0; } -void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) -{ - memset(evsel->counts, 0, (sizeof(*evsel->counts) + - (ncpus * sizeof(struct perf_counts_values)))); -} - -int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) -{ - evsel->counts = zalloc((sizeof(*evsel->counts) + - (ncpus * sizeof(struct perf_counts_values)))); - return evsel->counts != NULL ? 0 : -ENOMEM; -} - static void perf_evsel__free_fd(struct perf_evsel *evsel) { xyarray__delete(evsel->fd); @@ -891,11 +879,6 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) } } -void perf_evsel__free_counts(struct perf_evsel *evsel) -{ - zfree(&evsel->counts); -} - void perf_evsel__exit(struct perf_evsel *evsel) { assert(list_empty(&evsel->node)); diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 21ec08247d47..bb0579e8a10a 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -170,9 +170,6 @@ const char *perf_evsel__group_name(struct perf_evsel *evsel); int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); -int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); -void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); -void perf_evsel__free_counts(struct perf_evsel *evsel); void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 4d28624a1eca..5925fec90562 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources @@ -16,6 +16,7 @@ util/util.c util/xyarray.c util/cgroup.c util/rblist.c +util/stat.c util/strlist.c util/trace-event.c ../../lib/rbtree.c diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 60b92822f655..ac589b6b8bce 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -94,3 +94,21 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel) } } } + +void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) +{ + memset(evsel->counts, 0, (sizeof(*evsel->counts) + + (ncpus * sizeof(struct perf_counts_values)))); +} + +int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) +{ + evsel->counts = zalloc((sizeof(*evsel->counts) + + (ncpus * sizeof(struct perf_counts_values)))); + return evsel->counts != NULL ? 0 : -ENOMEM; +} + +void perf_evsel__free_counts(struct perf_evsel *evsel) +{ + zfree(&evsel->counts); +} diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 615c779eb42a..6a782601c1c7 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -62,4 +62,7 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, double avg, int cpu, enum aggr_mode aggr); +void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); +int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); +void perf_evsel__free_counts(struct perf_evsel *evsel); #endif -- cgit v1.2.1 From 9df38e82e2a103cf42177c164a4de9d58052ac3a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 14 Jun 2015 10:19:27 +0200 Subject: perf stat: Introduce perf_counts__(new|delete|reset) functions Move 'struct perf_counts' allocation|free|reset code into separate functions. Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1434269985-521-13-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 19 +++++++------------ tools/perf/util/stat.c | 28 +++++++++++++++++++++++----- tools/perf/util/stat.h | 3 +++ 3 files changed, 33 insertions(+), 17 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index b24ecee95fec..fcf99bdeb19e 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -178,24 +178,19 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) { - void *addr; - size_t sz; + struct perf_counts *counts; - sz = sizeof(*evsel->counts) + - (perf_evsel__nr_cpus(evsel) * sizeof(struct perf_counts_values)); + counts = perf_counts__new(perf_evsel__nr_cpus(evsel)); + if (counts) + evsel->prev_raw_counts = counts; - addr = zalloc(sz); - if (!addr) - return -ENOMEM; - - evsel->prev_raw_counts = addr; - - return 0; + return counts ? 0 : -ENOMEM; } static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) { - zfree(&evsel->prev_raw_counts); + perf_counts__delete(evsel->prev_raw_counts); + evsel->prev_raw_counts = NULL; } static void perf_evlist__free_stats(struct perf_evlist *evlist) diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index ac589b6b8bce..4014b709f956 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -95,20 +95,38 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel) } } +struct perf_counts *perf_counts__new(int ncpus) +{ + int size = sizeof(struct perf_counts) + + ncpus * sizeof(struct perf_counts_values); + + return zalloc(size); +} + +void perf_counts__delete(struct perf_counts *counts) +{ + free(counts); +} + +static void perf_counts__reset(struct perf_counts *counts, int ncpus) +{ + memset(counts, 0, (sizeof(*counts) + + (ncpus * sizeof(struct perf_counts_values)))); +} + void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) { - memset(evsel->counts, 0, (sizeof(*evsel->counts) + - (ncpus * sizeof(struct perf_counts_values)))); + perf_counts__reset(evsel->counts, ncpus); } int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) { - evsel->counts = zalloc((sizeof(*evsel->counts) + - (ncpus * sizeof(struct perf_counts_values)))); + evsel->counts = perf_counts__new(ncpus); return evsel->counts != NULL ? 0 : -ENOMEM; } void perf_evsel__free_counts(struct perf_evsel *evsel) { - zfree(&evsel->counts); + perf_counts__delete(evsel->counts); + evsel->counts = NULL; } diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 6a782601c1c7..093dc3cb28dd 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -62,6 +62,9 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, double avg, int cpu, enum aggr_mode aggr); +struct perf_counts *perf_counts__new(int ncpus); +void perf_counts__delete(struct perf_counts *counts); + void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); void perf_evsel__free_counts(struct perf_evsel *evsel); -- cgit v1.2.1 From f005813afb89bae92faf254130c544dc68984c6b Mon Sep 17 00:00:00 2001 From: Hou Pengyang Date: Tue, 16 Jun 2015 11:16:35 +0000 Subject: perf unwind: Fix a compile error When libunwind is on, there is a compile error as : util/unwind-libunwind.c:363:21: error: 'dso' undeclared (first use in this function) dso__data_put_fd(dso); This patch fixes it. Signed-off-by: Hou Pengyang Cc: Namhyung Kim Cc: Wang Nan Fixes: 4bb11d012ab248d0 ("perf tools: Add dso__data_get/put_fd()") Link: http://lkml.kernel.org/r/1434453395-10560-1-git-send-email-houpengyang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/unwind-libunwind.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf') diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index f079b63f0b7f..4c00507ee3fd 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -360,7 +360,7 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, unw_word_t base = is_exec ? 0 : map->start; if (fd >= 0) - dso__data_put_fd(dso); + dso__data_put_fd(map->dso); memset(&di, 0, sizeof(di)); if (dwarf_find_debug_frame(0, &di, ip, base, map->dso->name, -- cgit v1.2.1 From b031220d520238075bd99513a420e65cf37866ad Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 16 Jun 2015 20:50:55 +0900 Subject: perf probe: Fix to return error if no probe is added Fix perf probe to return an error if no probe is added due to the given probe point being on the blacklist. To fix this problem, this moves the blacklist checking to right after finding symbols/probe-points and marks them as skipped. If all the symbols are skipped, "perf probe" returns an error as it fails to find the corresponding probe address. E.g. currently if a blacklisted probe is given: # perf probe do_trap && echo 'succeed' Added new event: Warning: Skipped probing on blacklisted function: sync_regs succeed No! It must fail! With this patch, it correctly fails: # perf probe do_trap && echo 'succeed' do_trap is blacklisted function, skip it. Probe point 'do_trap' not found. Error: Failed to add events. Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Naohiro Aota Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20150616115055.19906.31359.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 113 ++++++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 42 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index c4ab58870fcc..85c8207c25cc 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -246,6 +246,20 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) clear_probe_trace_event(tevs + i); } +static bool kprobe_blacklist__listed(unsigned long address); +static bool kprobe_warn_out_range(const char *symbol, unsigned long address) +{ + /* Get the address of _etext for checking non-probable text symbol */ + if (kernel_get_symbol_address_by_name("_etext", false) < address) + pr_warning("%s is out of .text, skip it.\n", symbol); + else if (kprobe_blacklist__listed(address)) + pr_warning("%s is blacklisted function, skip it.\n", symbol); + else + return false; + + return true; +} + #ifdef HAVE_DWARF_SUPPORT static int kernel_get_module_dso(const char *module, struct dso **pdso) @@ -559,7 +573,6 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs, bool uprobe) { struct ref_reloc_sym *reloc_sym; - u64 etext_addr; char *tmp; int i, skipped = 0; @@ -575,31 +588,28 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs, pr_warning("Relocated base symbol is not found!\n"); return -EINVAL; } - /* Get the address of _etext for checking non-probable text symbol */ - etext_addr = kernel_get_symbol_address_by_name("_etext", false); for (i = 0; i < ntevs; i++) { - if (tevs[i].point.address && !tevs[i].point.retprobe) { - /* If we found a wrong one, mark it by NULL symbol */ - if (etext_addr < tevs[i].point.address) { - pr_warning("%s+%lu is out of .text, skip it.\n", - tevs[i].point.symbol, tevs[i].point.offset); - tmp = NULL; - skipped++; - } else { - tmp = strdup(reloc_sym->name); - if (!tmp) - return -ENOMEM; - } - /* If we have no realname, use symbol for it */ - if (!tevs[i].point.realname) - tevs[i].point.realname = tevs[i].point.symbol; - else - free(tevs[i].point.symbol); - tevs[i].point.symbol = tmp; - tevs[i].point.offset = tevs[i].point.address - - reloc_sym->unrelocated_addr; + if (!tevs[i].point.address || tevs[i].point.retprobe) + continue; + /* If we found a wrong one, mark it by NULL symbol */ + if (kprobe_warn_out_range(tevs[i].point.symbol, + tevs[i].point.address)) { + tmp = NULL; + skipped++; + } else { + tmp = strdup(reloc_sym->name); + if (!tmp) + return -ENOMEM; } + /* If we have no realname, use symbol for it */ + if (!tevs[i].point.realname) + tevs[i].point.realname = tevs[i].point.symbol; + else + free(tevs[i].point.symbol); + tevs[i].point.symbol = tmp; + tevs[i].point.offset = tevs[i].point.address - + reloc_sym->unrelocated_addr; } return skipped; } @@ -2126,6 +2136,27 @@ kprobe_blacklist__find_by_address(struct list_head *blacklist, return NULL; } +static LIST_HEAD(kprobe_blacklist); + +static void kprobe_blacklist__init(void) +{ + if (!list_empty(&kprobe_blacklist)) + return; + + if (kprobe_blacklist__load(&kprobe_blacklist) < 0) + pr_debug("No kprobe blacklist support, ignored\n"); +} + +static void kprobe_blacklist__release(void) +{ + kprobe_blacklist__delete(&kprobe_blacklist); +} + +static bool kprobe_blacklist__listed(unsigned long address) +{ + return !!kprobe_blacklist__find_by_address(&kprobe_blacklist, address); +} + static int perf_probe_event__sprintf(struct perf_probe_event *pev, const char *module, struct strbuf *result) @@ -2409,8 +2440,6 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, char buf[64]; const char *event, *group; struct strlist *namelist; - LIST_HEAD(blacklist); - struct kprobe_blacklist_node *node; bool safename; if (pev->uprobes) @@ -2430,28 +2459,15 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, ret = -ENOMEM; goto close_out; } - /* Get kprobe blacklist if exists */ - if (!pev->uprobes) { - ret = kprobe_blacklist__load(&blacklist); - if (ret < 0) - pr_debug("No kprobe blacklist support, ignored\n"); - } safename = (pev->point.function && !strisglob(pev->point.function)); ret = 0; pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); for (i = 0; i < ntevs; i++) { tev = &tevs[i]; - /* Skip if the symbol is out of .text (marked previously) */ + /* Skip if the symbol is out of .text or blacklisted */ if (!tev->point.symbol) continue; - /* Ensure that the address is NOT blacklisted */ - node = kprobe_blacklist__find_by_address(&blacklist, - tev->point.address); - if (node) { - pr_warning("Warning: Skipped probing on blacklisted function: %s\n", node->symbol); - continue; - } if (pev->event) event = pev->event; @@ -2513,7 +2529,6 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, tev->event); } - kprobe_blacklist__delete(&blacklist); strlist__delete(namelist); close_out: close(fd); @@ -2563,7 +2578,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, struct perf_probe_point *pp = &pev->point; struct probe_trace_point *tp; int num_matched_functions; - int ret, i, j; + int ret, i, j, skipped = 0; map = get_target_map(pev->target, pev->uprobes); if (!map) { @@ -2631,7 +2646,12 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, } /* Add one probe point */ tp->address = map->unmap_ip(map, sym->start) + pp->offset; - if (reloc_sym) { + /* If we found a wrong one, mark it by NULL symbol */ + if (!pev->uprobes && + kprobe_warn_out_range(sym->name, tp->address)) { + tp->symbol = NULL; /* Skip it */ + skipped++; + } else if (reloc_sym) { tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out); tp->offset = tp->address - reloc_sym->addr; } else { @@ -2667,6 +2687,10 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, } arch__fix_tev_from_maps(pev, tev, map); } + if (ret == skipped) { + ret = -ENOENT; + goto err_out; + } out: put_target_map(map, pev->uprobes); @@ -2737,6 +2761,9 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs) /* Loop 1: convert all events */ for (i = 0; i < npevs; i++) { pkgs[i].pev = &pevs[i]; + /* Init kprobe blacklist if needed */ + if (!pkgs[i].pev->uprobes) + kprobe_blacklist__init(); /* Convert with or without debuginfo */ ret = convert_to_probe_trace_events(pkgs[i].pev, &pkgs[i].tevs); @@ -2744,6 +2771,8 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs) goto end; pkgs[i].ntevs = ret; } + /* This just release blacklist only if allocated */ + kprobe_blacklist__release(); /* Loop 2: add all events */ for (i = 0; i < npevs; i++) { -- cgit v1.2.1 From 386299735e7056455bcead28f6ffa4357116ce38 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 17 Jun 2015 11:59:18 +0000 Subject: perf tools: Ignore .config-detected in .gitignore Commit fcfd6611fbccdbf2593bd949097a5c0e45cd96da ("tools build: Add detected config support") dynamically creates .config-detected. Add it to .gitignore. Signed-off-by: Wang Nan Cc: Jiri Olsa Cc: Zefan Li Link: http://lkml.kernel.org/r/1434542358-5430-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/.gitignore | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/perf') diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index 812f904193e8..09db62ba5786 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore @@ -28,3 +28,4 @@ config.mak.autogen *-flex.* *.pyc *.pyo +.config-detected -- cgit v1.2.1 From b30b617292462ca7ee68834b117a7833f4a52e16 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 17 Jun 2015 09:56:39 +0000 Subject: perf tools: Fix a problem when opening old perf.data with different byte order Following error occurs when trying to use 'perf report' on x86_64 to cross analysis a perf.data generated by an old perf on a big-endian machine: # perf report *** Error in `/home/w00229757/perf': free(): invalid next size (fast): 0x00000000032c99f0 *** ======= Backtrace: ========= /lib64/libc.so.6(+0x6eeef)[0x7ff6ff7e2eef] /lib64/libc.so.6(+0x78cae)[0x7ff6ff7eccae] /lib64/libc.so.6(+0x79987)[0x7ff6ff7ed987] /path/to/perf[0x4ac734] /path/to/perf[0x4ac829] /path/to/perf(perf_header__process_sections+0x129)[0x4ad2c9] /path/to/perf(perf_session__read_header+0x2e1)[0x4ad9e1] /path/to/perf(perf_session__new+0x168)[0x4bd458] /path/to/perf(cmd_report+0xfa0)[0x43eb70] /path/to/perf[0x47adc3] /path/to/perf(main+0x5f6)[0x42fd06] /lib64/libc.so.6(__libc_start_main+0xf5)[0x7ff6ff795bd5] /path/to/perf[0x42fe35] ======= Memory map: ======== [SNIP] The bug is in perf_event__attr_swap(). It swaps all fields in 'struct perf_event_attr' without checking whether the swapped field exist or not. In addition, in read_event_desc() allocs memory for attr according to size read from perf.data. Therefore, if the perf.data is collected by an old perf (without aux_watermark, for example), when perf_event__attr_swap() swaping attr->aux_watermark it destroy malloc's metadata. This patch introduces boundary checking in perf_event__attr_swap(). It adds macros bswap_field_64 and bswap_field_32 into perf_event__attr_swap() to make it only swap exist fields. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: Ingo Molnar Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1434534999-85347-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 50 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 14 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f31e024ddf7d..e1cd17c2afab 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -517,20 +517,42 @@ void perf_event__attr_swap(struct perf_event_attr *attr) { attr->type = bswap_32(attr->type); attr->size = bswap_32(attr->size); - attr->config = bswap_64(attr->config); - attr->sample_period = bswap_64(attr->sample_period); - attr->sample_type = bswap_64(attr->sample_type); - attr->read_format = bswap_64(attr->read_format); - attr->wakeup_events = bswap_32(attr->wakeup_events); - attr->bp_type = bswap_32(attr->bp_type); - attr->bp_addr = bswap_64(attr->bp_addr); - attr->bp_len = bswap_64(attr->bp_len); - attr->branch_sample_type = bswap_64(attr->branch_sample_type); - attr->sample_regs_user = bswap_64(attr->sample_regs_user); - attr->sample_stack_user = bswap_32(attr->sample_stack_user); - attr->aux_watermark = bswap_32(attr->aux_watermark); - - swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); + +#define bswap_safe(f, n) \ + (attr->size > (offsetof(struct perf_event_attr, f) + \ + sizeof(attr->f) * (n))) +#define bswap_field(f, sz) \ +do { \ + if (bswap_safe(f, 0)) \ + attr->f = bswap_##sz(attr->f); \ +} while(0) +#define bswap_field_32(f) bswap_field(f, 32) +#define bswap_field_64(f) bswap_field(f, 64) + + bswap_field_64(config); + bswap_field_64(sample_period); + bswap_field_64(sample_type); + bswap_field_64(read_format); + bswap_field_32(wakeup_events); + bswap_field_32(bp_type); + bswap_field_64(bp_addr); + bswap_field_64(bp_len); + bswap_field_64(branch_sample_type); + bswap_field_64(sample_regs_user); + bswap_field_32(sample_stack_user); + bswap_field_32(aux_watermark); + + /* + * After read_format are bitfields. Check read_format because + * we are unable to use offsetof on bitfield. + */ + if (bswap_safe(read_format, 1)) + swap_bitfield((u8 *) (&attr->read_format + 1), + sizeof(u64)); +#undef bswap_field_64 +#undef bswap_field_32 +#undef bswap_field +#undef bswap_safe } static void perf_event__hdr_attr_swap(union perf_event *event, -- cgit v1.2.1 From 5d618324dd4442d20dbdb039176787199ba2f12b Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 17 Jun 2015 14:46:29 +0000 Subject: perf tools: Move libtraceevent dynamic list to separated LDFLAGS variable Commit e3d09ec8126fe2c9a3ade661e2126e215ca27a80 ("tools lib traceevent: Export dynamic symbols used by traceevent plugins") adds libtraceevent dynamic list directly into LDFLAGS, which makes all targets depend on that list through LDFLAGS. This is not good since some of targets like libgtk.so doesn't use plugin at all, but require the existance of that list because of linker options. This patch isolates the -Xlink option into LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS, makes only perf and perf.so use it. Signed-off-by: Wang Nan Acked-by: Jiri Olsa Cc: He Kuang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1434552389-89144-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 374378322db9..1af0cfeb7a57 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -174,7 +174,7 @@ LIBTRACEEVENT = $(TE_PATH)libtraceevent.a export LIBTRACEEVENT LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list -LDFLAGS += -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST) +LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST) LIBAPI = $(LIB_PATH)libapi.a export LIBAPI @@ -191,7 +191,8 @@ PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPI) $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) $(LIBTRACEEVENT_DYNAMIC_LIST) - $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ + $(QUIET_GEN)CFLAGS='$(CFLAGS)' LDFLAGS='$(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS)' \ + $(PYTHON_WORD) util/setup.py \ --quiet build_ext; \ mkdir -p $(OUTPUT)python && \ cp $(PYTHON_EXTBUILD_LIB)perf.so $(OUTPUT)python/ @@ -282,7 +283,8 @@ $(PERF_IN): $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h FORCE $(Q)$(MAKE) $(build)=perf $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) - $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(PERF_IN) $(LIBS) -o $@ + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \ + $(PERF_IN) $(LIBS) -o $@ $(GTK_IN): FORCE $(Q)$(MAKE) $(build)=gtk -- cgit v1.2.1 From d350bd571ffa89fc3bd07cfa9685d5210f459be8 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 16 Jun 2015 20:50:57 +0900 Subject: perf probe: Show usage even if the last event is skipped When the last part of converted events are blacklisted or out-of-text, those are skipped and perf probe doesn't show usage examples. This fixes it to show the example even if the last part of event list is skipped. E.g. without this patch, events are added, but suddenly end: # perf probe vfs_* vfs_caches_init_early is out of .text, skip it. vfs_caches_init is out of .text, skip it. Added new events: probe:vfs_fallocate (on vfs_*) probe:vfs_open (on vfs_*) ... probe:vfs_dentry_acceptable (on vfs_*) probe:vfs_load_quota_inode (on vfs_*) # With this fix: # perf probe vfs_* vfs_caches_init_early is out of .text, skip it. vfs_caches_init is out of .text, skip it. Added new events: probe:vfs_fallocate (on vfs_*) ... probe:vfs_load_quota_inode (on vfs_*) You can now use it in all perf tools, such as: perf record -e probe:vfs_load_quota_inode -aR sleep 1 Note that this can be reproduced ONLY IF the vfs_caches_init* is the last part of matched symbol list. I've checked this happens on "3.19.0-generic #18-Ubuntu" kernel binary. Signed-off-by: Masami Hiramatsu Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Naohiro Aota Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20150616115057.19906.5502.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 85c8207c25cc..65a1c8252270 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2157,7 +2157,8 @@ static bool kprobe_blacklist__listed(unsigned long address) return !!kprobe_blacklist__find_by_address(&kprobe_blacklist, address); } -static int perf_probe_event__sprintf(struct perf_probe_event *pev, +static int perf_probe_event__sprintf(const char *group, const char *event, + struct perf_probe_event *pev, const char *module, struct strbuf *result) { @@ -2170,7 +2171,7 @@ static int perf_probe_event__sprintf(struct perf_probe_event *pev, if (!place) return -EINVAL; - ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); + ret = e_snprintf(buf, 128, "%s:%s", group, event); if (ret < 0) goto out; @@ -2195,13 +2196,14 @@ out: } /* Show an event */ -static int show_perf_probe_event(struct perf_probe_event *pev, +static int show_perf_probe_event(const char *group, const char *event, + struct perf_probe_event *pev, const char *module, bool use_stdout) { struct strbuf buf = STRBUF_INIT; int ret; - ret = perf_probe_event__sprintf(pev, module, &buf); + ret = perf_probe_event__sprintf(group, event, pev, module, &buf); if (ret >= 0) { if (use_stdout) printf("%s\n", buf.buf); @@ -2253,7 +2255,8 @@ static int __show_perf_probe_events(int fd, bool is_kprobe, is_kprobe); if (ret < 0) goto next; - ret = show_perf_probe_event(&pev, tev.point.module, + ret = show_perf_probe_event(pev.group, pev.event, + &pev, tev.point.module, true); } next: @@ -2438,7 +2441,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, int i, fd, ret; struct probe_trace_event *tev = NULL; char buf[64]; - const char *event, *group; + const char *event = NULL, *group = NULL; struct strlist *namelist; bool safename; @@ -2500,15 +2503,12 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, /* Add added event name to namelist */ strlist__add(namelist, event); - /* Trick here - save current event/group */ - event = pev->event; - group = pev->group; - pev->event = tev->event; - pev->group = tev->group; - show_perf_probe_event(pev, tev->point.module, false); - /* Trick here - restore current event/group */ - pev->event = (char *)event; - pev->group = (char *)group; + /* We use tev's name for showing new events */ + show_perf_probe_event(tev->group, tev->event, pev, + tev->point.module, false); + /* Save the last valid name */ + event = tev->event; + group = tev->group; /* * Probes after the first probe which comes from same @@ -2522,11 +2522,10 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, warn_uprobe_event_compat(tev); /* Note that it is possible to skip all events because of blacklist */ - if (ret >= 0 && tev->event) { + if (ret >= 0 && event) { /* Show how to use the event. */ pr_info("\nYou can now use it in all perf tools, such as:\n\n"); - pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, - tev->event); + pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", group, event); } strlist__delete(namelist); -- cgit v1.2.1 From 7737af010b097f3c1e2aeded21774d58b4aa2698 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 17 Jun 2015 23:58:54 +0900 Subject: perf probe: Speed up perf probe --list by caching debuginfo Speed up the "perf probe --list" by caching the last used debuginfo. perf probe --list always open and load debuginfo for each entry of probe list. This takes very a long time. E.g. with vfs_* events (total 96 probes) [root@localhost perf]# time ./perf probe -l &> /dev/null real 0m25.376s user 0m24.381s sys 0m1.012s To solve this issue, this adds debuginfo_cache to cache the last used debuginfo on memory. With this fix, the perf-probe --list significantly improves its speed. [root@localhost perf]# time ./perf probe -l &> /dev/null real 0m0.161s user 0m0.136s sys 0m0.025s Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Naohiro Aota Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20150617145854.19715.15314.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 48 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 65a1c8252270..076527b639bd 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -429,6 +429,41 @@ static struct debuginfo *open_debuginfo(const char *module, bool silent) return ret; } +/* For caching the last debuginfo */ +static struct debuginfo *debuginfo_cache; +static char *debuginfo_cache_path; + +static struct debuginfo *debuginfo_cache__open(const char *module, bool silent) +{ + if ((debuginfo_cache_path && !strcmp(debuginfo_cache_path, module)) || + (!debuginfo_cache_path && !module && debuginfo_cache)) + goto out; + + /* Copy module path */ + free(debuginfo_cache_path); + if (module) { + debuginfo_cache_path = strdup(module); + if (!debuginfo_cache_path) { + debuginfo__delete(debuginfo_cache); + debuginfo_cache = NULL; + goto out; + } + } + + debuginfo_cache = open_debuginfo(module, silent); + if (!debuginfo_cache) + zfree(&debuginfo_cache_path); +out: + return debuginfo_cache; +} + +static void debuginfo_cache__exit(void) +{ + debuginfo__delete(debuginfo_cache); + debuginfo_cache = NULL; + zfree(&debuginfo_cache_path); +} + static int get_text_start_address(const char *exec, unsigned long *address) { @@ -490,12 +525,11 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp, pr_debug("try to find information at %" PRIx64 " in %s\n", addr, tp->module ? : "kernel"); - dinfo = open_debuginfo(tp->module, verbose == 0); - if (dinfo) { + dinfo = debuginfo_cache__open(tp->module, verbose == 0); + if (dinfo) ret = debuginfo__find_probe_point(dinfo, (unsigned long)addr, pp); - debuginfo__delete(dinfo); - } else + else ret = -ENOENT; if (ret > 0) { @@ -930,6 +964,10 @@ out: #else /* !HAVE_DWARF_SUPPORT */ +static void debuginfo_cache__exit(void) +{ +} + static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused, struct perf_probe_point *pp __maybe_unused, @@ -2266,6 +2304,8 @@ next: break; } strlist__delete(rawlist); + /* Cleanup cached debuginfo if needed */ + debuginfo_cache__exit(); return ret; } -- cgit v1.2.1 From 7951722da2963cc1f1a7831a37aa2311ac927056 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Fri, 12 Jun 2015 01:28:36 -0400 Subject: perf trace: Fix race condition at the end of started workloads I get following crash on multiple systems and across several releases (at least since v3.18). Core was generated by `/tmp/perf trace sleep 0.2 '. Program terminated with signal SIGSEGV, Segmentation fault. #0 perf_mmap__read_head (mm=0x3fff9bf30070) at util/evlist.h:195 195 u64 head = ACCESS_ONCE(pc->data_head); (gdb) bt #0 perf_mmap__read_head (mm=0x3fff9bf30070) at util/evlist.h:195 #1 perf_evlist__mmap_read (evlist=0x10027f11910, idx=) at util/evlist.c:637 #2 0x000000001003ce4c in trace__run (argv=, argc=, trace=0x3fffd7b28288) at builtin-trace.c:2259 #3 cmd_trace (argc=, argv=, prefix=) at builtin-trace.c:2799 #4 0x00000000100657b8 in run_builtin (p=0x10176798 , argc=3, argv=0x3fffd7b2b550) at perf.c:370 #5 0x00000000100063e8 in handle_internal_command (argv=0x3fffd7b2b550, argc=3) at perf.c:429 #6 run_argv (argv=0x3fffd7b2af70, argcp=0x3fffd7b2af7c) at perf.c:473 #7 main (argc=3, argv=0x3fffd7b2b550) at perf.c:588 The problem seems to be a race condition, when the application has just exited. Some/all fds associated with the perf-events (tracepoints) go into a POLLHUP/ POLLERR state and the mmap region associated with those events are unmapped (in perf_evlist__filter_pollfd()). But we go back and do a perf_evlist__mmap_read() which assumes that the mmaps are still valid and we hit the crash. If the mapping for an event is released, its refcnt is 0 (and ->base is NULL), so ensure we have non-zero refcount before accessing the map. Note that perf-record has a similar logic but unlike perf-trace, the record__mmap_read_all() checks the evlist->mmap[i].base before accessing the map. Signed-off-by: Sukadev Bhattiprolu Cc: Jiri Olsa Cc: Li Zhang Link: http://lkml.kernel.org/r/20150612060003.GA19913@us.ibm.com [ Fixed it up to use atomic_read() ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'tools/perf') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index dc1dc2c181ef..6b58a47a79ec 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -634,11 +634,18 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) { struct perf_mmap *md = &evlist->mmap[idx]; - u64 head = perf_mmap__read_head(md); + u64 head; u64 old = md->prev; unsigned char *data = md->base + page_size; union perf_event *event = NULL; + /* + * Check if event was unmapped due to a POLLHUP/POLLERR. + */ + if (!atomic_read(&md->refcnt)) + return NULL; + + head = perf_mmap__read_head(md); if (evlist->overwrite) { /* * If we're further behind than half the buffer, there's a chance -- cgit v1.2.1 From 2b56bcfb6f4bb0aa0813b6ee1dde8f5b23fce5d4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 17 Jun 2015 16:40:26 -0300 Subject: perf evlist: Add toggle_enable() method For an upcoming feature in 'perf top' we will have a hotkey to enable/disable events, so remember if the events in the list are enabled or disabled and allows toggling this state using a new method. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-64c4jvdl5feg2zhimxvokqka@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 9 +++++++++ tools/perf/util/evlist.h | 2 ++ 2 files changed, 11 insertions(+) (limited to 'tools/perf') diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 6b58a47a79ec..8366511b45f8 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -297,6 +297,8 @@ void perf_evlist__disable(struct perf_evlist *evlist) PERF_EVENT_IOC_DISABLE, 0); } } + + evlist->enabled = false; } void perf_evlist__enable(struct perf_evlist *evlist) @@ -316,6 +318,13 @@ void perf_evlist__enable(struct perf_evlist *evlist) PERF_EVENT_IOC_ENABLE, 0); } } + + evlist->enabled = true; +} + +void perf_evlist__toggle_enable(struct perf_evlist *evlist) +{ + (evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist); } int perf_evlist__disable_event(struct perf_evlist *evlist, diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 955bf31b7dd3..a8489b9d2812 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -41,6 +41,7 @@ struct perf_evlist { int nr_groups; int nr_mmaps; bool overwrite; + bool enabled; size_t mmap_len; int id_pos; int is_pos; @@ -139,6 +140,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist); void perf_evlist__disable(struct perf_evlist *evlist); void perf_evlist__enable(struct perf_evlist *evlist); +void perf_evlist__toggle_enable(struct perf_evlist *evlist); int perf_evlist__disable_event(struct perf_evlist *evlist, struct perf_evsel *evsel); -- cgit v1.2.1 From 5d484f99aed547e235f2229653c95392a1bc3692 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 17 Jun 2015 16:50:52 -0300 Subject: perf top: Allow disabling/enabling events dynamicly Now it is possible to press CTRL+z at anytime and that will disable the events being monitored, essentially turning 'top' into 'report', with pressing CTRL+z again making it enable the events again, returning to the 'top' behaviour, i.e. dynamic + decaying of older samples. One may want, for instance, play with: -d, --delay number of seconds to delay between refreshes and: -z, --zero zero history across updates Plus CTRL+z to see only the events since last zeroing, etc. Suggested-by: Ingo Molnar Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-zq7tnh5462blt2yda0bcxh5b@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 52 +++++++++++++++++++++++++++++------------- tools/perf/ui/browsers/hists.c | 2 ++ 2 files changed, 38 insertions(+), 16 deletions(-) (limited to 'tools/perf') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 6b987424d015..72d8a7ae5986 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -235,10 +235,13 @@ static void perf_top__show_details(struct perf_top *top) more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, 0, top->sym_pcnt_filter, top->print_entries, 4); - if (top->zero) - symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); - else - symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); + + if (top->evlist->enabled) { + if (top->zero) + symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); + else + symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); + } if (more != 0) printf("%d lines not displayed, maybe increase display entries [e]\n", more); out_unlock: @@ -276,11 +279,13 @@ static void perf_top__print_sym_table(struct perf_top *top) return; } - if (top->zero) { - hists__delete_entries(hists); - } else { - hists__decay_entries(hists, top->hide_user_symbols, - top->hide_kernel_symbols); + if (top->evlist->enabled) { + if (top->zero) { + hists__delete_entries(hists); + } else { + hists__decay_entries(hists, top->hide_user_symbols, + top->hide_kernel_symbols); + } } hists__collapse_resort(hists, NULL); @@ -545,11 +550,13 @@ static void perf_top__sort_new_samples(void *arg) hists = evsel__hists(t->sym_evsel); - if (t->zero) { - hists__delete_entries(hists); - } else { - hists__decay_entries(hists, t->hide_user_symbols, - t->hide_kernel_symbols); + if (t->evlist->enabled) { + if (t->zero) { + hists__delete_entries(hists); + } else { + hists__decay_entries(hists, t->hide_user_symbols, + t->hide_kernel_symbols); + } } hists__collapse_resort(hists, NULL); @@ -579,8 +586,21 @@ static void *display_thread_tui(void *arg) hists->uid_filter_str = top->record_opts.target.uid_str; } - perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, - &top->session->header.env); + while (true) { + int key = perf_evlist__tui_browse_hists(top->evlist, help, &hbt, + top->min_percent, + &top->session->header.env); + + if (key != CTRL('z')) + break; + + perf_evlist__toggle_enable(top->evlist); + /* + * No need to refresh, resort/decay histogram entries + * if we are not collecting samples: + */ + hbt.refresh = top->evlist->enabled ? top->delay_secs : 0; + } done = 1; return NULL; diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index e64893f2fd7f..8f7c4d49d327 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1736,6 +1736,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, "t Zoom into current Thread\n" "V Verbose (DSO names in callchains, etc)\n" "z Toggle zeroing of samples\n" + "CTRL+z Enable/Disable events\n" "/ Filter symbol by name"; if (browser == NULL) @@ -1900,6 +1901,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, /* Fall thru */ case 'q': case CTRL('c'): + case CTRL('z'): goto out_free_stack; default: continue; -- cgit v1.2.1