perf/core improvements and fixes
Arnaldo Carvalho de Melo
maintainerHi Ingo,
Please consider pulling,
- Arnaldo
The following changes since commit 2c95afc1e83d93fac3be6923465e1753c2c53b0a:
perf/x86/intel, watchdog: Switch NMI watchdog to ref cycles on x86 (2016-06-14 11:16:59 +0200)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo-20160615
for you to fetch changes up to 2fd457a34525ea3bc609e377b46af759af8a7934:
perf probe: Add --cache option to cache the probe definitions (2016-06-15 14:34:42 -0300)
----------------------------------------------------------------
perf/core improvements and fixes:
User visible:
- Add --ldlat option to 'perf mem' to specify load latency for loads event (e.g. cpu/mem-loads/ ) (Jiri Olsa)
Build fixes:
- Fix libunwind related compile error for static cross build (He Kuang)
Infrastructure:
- UI refactorings to support headers with multiple lines, non-evsel hists browsers, toggle showing callchains, etc (Jiri Olsa)
- More prep work for caching probe definitions, paving the way
for supporting SDT (Statically Defined Traces) userspace probes (Masami Hiramatsu)
- Handle NULL at perf_config_set__delete() (Taeung Song)
----------------------------------------------------------------
He Kuang (1):
perf unwind: Fix compile error for static cross build
Jiri Olsa (10):
perf mem: Add --ldlat option
perf tools: Fix Data Object sort entry width index perf tui: Separate hierarchy and standard headers output perf stdio: Separate headers output
perf stdio: Separate hierarchy headers output
perf stdio: Separate standard headers output
perf stdio: Do not pass hists in hist_entry__fprintf perf stdio: Add use_callchain parameter to hists__fprintf perf hists: Replace perf_evsel arg perf_hpp_fmt's header callback perf hists: Replace perf_evsel arg perf_hpp_fmt's width callback
Masami Hiramatsu (7):
perf tools: Fix rm_rf() to handle non-regular files correctly perf probe: Fix to add NULL check for strndup
perf buildid: Rename and export build_id_cache__cachedir() perf probe: Add perf_probe_event__copy()
perf probe: Uncomment and export synthesize_perf_probe_point() perf probe: Introduce perf_cache interfaces
perf probe: Add --cache option to cache the probe definitions
Taeung Song (1):
perf config: Handle NULL at perf_config_set__delete()
tools/perf/Documentation/perf-mem.txt | 3 + tools/perf/Documentation/perf-probe.txt | 4 + tools/perf/builtin-diff.c | 7 +- tools/perf/builtin-mem.c | 1 + tools/perf/builtin-probe.c | 1 + tools/perf/builtin-report.c | 3 +- tools/perf/builtin-top.c | 2 +- tools/perf/config/Makefile | 3 + tools/perf/ui/browsers/hists.c | 39 ++-- tools/perf/ui/gtk/hists.c | 2 +- tools/perf/ui/hist.c | 11 +- tools/perf/ui/stdio/hist.c | 133 +++++++------ tools/perf/util/build-id.c | 12 +- tools/perf/util/build-id.h | 2 + tools/perf/util/config.c | 3 + tools/perf/util/hist.c | 2 +- tools/perf/util/hist.h | 7 +- tools/perf/util/mem-events.c | 17 +- tools/perf/util/mem-events.h | 1 + tools/perf/util/probe-event.c | 128 ++++++++++-- tools/perf/util/probe-event.h | 5 + tools/perf/util/probe-file.c | 331 ++++++++++++++++++++++++++++++++ tools/perf/util/probe-file.h | 20 ++ tools/perf/util/sort.c | 14 +- tools/perf/util/util.c | 13 +- 25 files changed, 640 insertions(+), 124 deletions(-)
Arnaldo Carvalho de Melo
maintainerPATCH 1/19 perf config: Handle NULL at perf_config_set__delete()
From: Taeung Song <[email protected]>
perf_config_set__delete() purge and free the config set that contains all config key-value pairs. But if the config set (i.e. 'set' variable at the function) is NULL, this is wrong so handle it.
--- tools/perf/util/config.c | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/util/config.c +3 -0
@@ -742,6 +742,9 @@ static void perf_config_set__purge(struct perf_config_set *set)void perf_config_set__delete (struct perf_config_set *set) { +if (set ==NULL ) +return ; +perf_config_set__purge (set);free (set); }
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 2/19 perf tools: Fix rm_rf() to handle non-regular files correctly
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Fix rm_rf() to handle non-regular files correctly. This fix includes two changes;
- Fix to use lstat(3) instead of stat(3) since if the target file is a symbolic link, rm_rf() should unlink the symbolic link itself, not the file which pointed by the symlink.
- Fix to unlink non-regular files (except for directory), including symlink.
Even though the first one fixes to stat symlink itself, without second fix, it still failed because the symlink is not a regular file.
--- tools/perf/util/util.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
tools/perf/util/util.c +5 -8
@@ -97,20 +97,17 @@ int rm_rf(char *path)scnprintf (namebuf,sizeof (namebuf),"%s/%s" , path, d->d_name); - ret =stat (namebuf, &statbuf); +/* We have to check symbolic link itself */ + ret =lstat (namebuf, &statbuf);if (ret <0 ) {pr_debug ("stat failed: %s\n" , namebuf);break ; } -if (S_ISREG (statbuf.st_mode)) - ret =unlink (namebuf); -else if (S_ISDIR (statbuf.st_mode)) +if (S_ISDIR (statbuf.st_mode)) ret =rm_rf (namebuf); -else { -pr_debug ("unknown file: %s\n" , namebuf); - ret =-1 ; - } +else + ret =unlink (namebuf); }closedir (dir);
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 3/19 perf probe: Fix to add NULL check for strndup
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Fix to add a NULL check for strndup when parsing probe trace command.
--- tools/perf/util/probe-event.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/perf/util/probe-event.c +4 -0
@@ -1603,6 +1603,10 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev) p =strchr (argv[1 ],':' );if (p) { tp->module =strndup (argv[1 ], p - argv[1 ]); +if (!tp->module) { + ret = -ENOMEM ; + goto out; + } p++; }else p = argv[1 ];
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 4/19 perf buildid: Rename and export build_id_cache__cachedir()
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Rename and export build_id_cache__cachedir() for retrieving use of the path of cache directory for given build_id.
--- tools/perf/util/build-id.c | 12 +++++------- tools/perf/util/build-id.h | 2 ++ 2 files changed, 7 insertions(+), 7 deletions(-)
tools/perf/util/build-id.c +5 -7
@@ -387,9 +387,8 @@ void disable_buildid_cache(void) no_buildid_cache = true; } -static char *build_id_cache__dirname_from_path (const char *name, -bool is_kallsyms,bool is_vdso, -const char *sbuild_id) +char *build_id_cache__cachedir (const char *sbuild_id,const char *name, +bool is_kallsyms,bool is_vdso) {char *realname = (char *)name, *filename;bool slash = is_kallsyms || is_vdso;
@@ -417,8 +416,7 @@ int build_id_cache__list_build_ids(const char *pathname,char *dir_name;int ret =0 ; - dir_name =build_id_cache__dirname_from_path (pathname, false, false, -NULL ); + dir_name =build_id_cache__cachedir (NULL , pathname, false, false);if (!dir_name)return -ENOMEM ;
@@ -444,8 +442,8 @@ int build_id_cache__add_s(const char *sbuild_id, const char *name, goto out_free; } - dir_name =build_id_cache__dirname_from_path (name, is_kallsyms, - is_vdso, sbuild_id); + dir_name =build_id_cache__cachedir (sbuild_id, name, + is_kallsyms, is_vdso);if (!dir_name) goto out_free;
tools/perf/util/build-id.h +2 -0
@@ -30,6 +30,8 @@ bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);int perf_session__write_buildid_table (struct perf_session *session,int fd);int perf_session__cache_build_ids (struct perf_session *session); +char *build_id_cache__cachedir (const char *sbuild_id,const char *name, +bool is_kallsyms,bool is_vdso);int build_id_cache__list_build_ids (const char *pathname,struct strlist **result);bool build_id_cache__cached (const char *sbuild_id);
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 5/19 perf probe: Add perf_probe_event__copy()
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Add perf_probe_event__copy() to copy perf_probe_event data structure and sub data structures under given source perf_probe_event.
--- tools/perf/util/probe-event.c | 76 +++++++++++++++++++++++++++++++++++++++++-- tools/perf/util/probe-event.h | 3 ++ 2 files changed, 76 insertions(+), 3 deletions(-)
tools/perf/util/probe-event.c +73 -3
@@ -2030,6 +2030,79 @@ void clear_perf_probe_event(struct perf_probe_event *pev)memset (pev,0 ,sizeof (*pev)); } +#define strdup_or_goto (str, label) \ +({ char *__p = NULL; if (str && !(__p = strdup(str))) goto label; __p; }) + +static int perf_probe_point__copy (struct perf_probe_point *dst, +struct perf_probe_point *src) +{ + dst->file =strdup_or_goto (src->file, out_err); + dst->function =strdup_or_goto (src->function, out_err); + dst->lazy_line =strdup_or_goto (src->lazy_line, out_err); + dst->line = src->line; + dst->retprobe = src->retprobe; + dst->offset = src->offset; +return 0 ; + +out_err: +clear_perf_probe_point (dst); +return -ENOMEM ; +} + +static int perf_probe_arg__copy (struct perf_probe_arg *dst, +struct perf_probe_arg *src) +{ +struct perf_probe_arg_field *field, **ppfield; + + dst->name =strdup_or_goto (src->name, out_err); + dst->var =strdup_or_goto (src->var, out_err); + dst->type =strdup_or_goto (src->type, out_err); + + field = src->field; + ppfield = &(dst->field); +while (field) { + *ppfield =zalloc (sizeof (*field)); +if (!*ppfield) + goto out_err; + (*ppfield)->name =strdup_or_goto (field->name, out_err); + (*ppfield)->index = field->index; + (*ppfield)->ref = field->ref; + field = field->next; + ppfield = &((*ppfield)->next); + } +return 0 ; +out_err: +return -ENOMEM ; +} + +int perf_probe_event__copy (struct perf_probe_event *dst, +struct perf_probe_event *src) +{ +int i; + + dst->event =strdup_or_goto (src->event, out_err); + dst->group =strdup_or_goto (src->group, out_err); + dst->target =strdup_or_goto (src->target, out_err); + dst->uprobes = src->uprobes; + +if (perf_probe_point__copy (&dst->point, &src->point) <0 ) + goto out_err; + + dst->args =zalloc (sizeof (struct perf_probe_arg ) * src->nargs); +if (!dst->args) + goto out_err; + dst->nargs = src->nargs; + +for (i =0 ; i < src->nargs; i++) +if (perf_probe_arg__copy (&dst->args[i], &src->args[i]) <0 ) + goto out_err; +return 0 ; + +out_err: +clear_perf_probe_event (dst); +return -ENOMEM ; +} +void clear_probe_trace_event (struct probe_trace_event *tev) {struct probe_trace_arg_ref *ref, *next;
@@ -2505,9 +2578,6 @@ static int find_probe_functions(struct map *map, char *name,return found; } -#define strdup_or_goto (str, label) \ - ({ char *__p = strdup(str); if (!__p) goto label; __p; }) - void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, struct probe_trace_event *tev __maybe_unused, struct map *map __maybe_unused,
tools/perf/util/probe-event.h +3 -0
@@ -122,6 +122,9 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev);char *synthesize_probe_trace_command (struct probe_trace_event *tev);char *synthesize_perf_probe_arg (struct perf_probe_arg *pa); +int perf_probe_event__copy (struct perf_probe_event *dst, +struct perf_probe_event *src); +/* Check the perf_probe_event needs debuginfo */ bool perf_probe_event_need_dwarf (struct perf_probe_event *pev);
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 6/19 perf probe: Uncomment and export synthesize_perf_probe_point()
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Uncomment and export synthesize_perf_probe_point() which had once introduced but has been disabled for a long time. This renews the code and re-enable it.
--- tools/perf/util/probe-event.c | 39 ++++++++++++++++++++++----------------- tools/perf/util/probe-event.h | 1 + 2 files changed, 23 insertions(+), 17 deletions(-)
tools/perf/util/probe-event.c +22 -17
@@ -67,7 +67,6 @@ int e_snprintf(char *str, size_t size, const char *format, ...)return ret; } -static char *synthesize_perf_probe_point (struct perf_probe_point *pp);static struct machine *host_machine;/* Initialize symbol maps and path of vmlinux/modules */
@@ -1716,7 +1715,7 @@ out: }/* Compose only probe point (not argument) */ -static char *synthesize_perf_probe_point (struct perf_probe_point *pp) +char *synthesize_perf_probe_point (struct perf_probe_point *pp) {struct strbuf buf;char *tmp, *ret =NULL ;
@@ -1755,30 +1754,36 @@ out:return ret; } -#if 0 char *synthesize_perf_probe_command (struct perf_probe_event *pev) { -char *buf; -int i, len, ret; +struct strbuf buf; +char *tmp, *ret =NULL ; +int i; - buf =synthesize_perf_probe_point (&pev->point); -if (!buf) +if (strbuf_init (&buf,64 ))return NULL ; +if (pev->event) +if (strbuf_addf (&buf,"%s:%s=" , pev->group ?:PERFPROBE_GROUP , + pev->event) <0 ) + goto out; + + tmp =synthesize_perf_probe_point (&pev->point); +if (!tmp ||strbuf_addstr (&buf, tmp) <0 ) + goto out; +free (tmp); - len =strlen (buf);for (i =0 ; i < pev->nargs; i++) { - ret =e_snprintf (&buf[len],MAX_CMDLEN - len," %s" , - pev->args[i].name); -if (ret <=0 ) { -free (buf); -return NULL ; - } - len += ret; + tmp =synthesize_perf_probe_arg (pev->args + i); +if (!tmp ||strbuf_addf (&buf," %s" , tmp) <0 ) + goto out; +free (tmp); } -return buf; + ret =strbuf_detach (&buf,NULL ); +out: +strbuf_release (&buf); +return ret; } -#endif static int __synthesize_probe_trace_arg_ref (struct probe_trace_arg_ref *ref,struct strbuf *buf,int depth)
tools/perf/util/probe-event.h +1 -0
@@ -121,6 +121,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev);char *synthesize_perf_probe_command (struct perf_probe_event *pev);char *synthesize_probe_trace_command (struct probe_trace_event *tev);char *synthesize_perf_probe_arg (struct perf_probe_arg *pa); +char *synthesize_perf_probe_point (struct perf_probe_point *pp);int perf_probe_event__copy (struct perf_probe_event *dst,struct perf_probe_event *src);
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 7/19 perf unwind: Fix compile error for static cross build
In reply to Arnaldo Carvalho de MeloFrom: He Kuang <[email protected]>
Build failure for static cross-compiling on aarch64, with libunwind-x86 provided:
$ file ./libunwind_for_x86_on_aarch64/lib/libunwind-x86.so.8.0.1
libunwind-x86.so.8.0.1: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, not stripped
$ make LDFLAGS=-static LIBUNWIND_DIR=./libunwind_for_x86_on_aarch64 ARCH=aarch64 CROSS_COMPILE=aarch64-buildroot-linux-gnu-
~/libperf.a(libperf-in.o): In function `find_proc_info':
:(.text+0xae4ac): undefined reference to _Ux86_dwarf_search_unwind_table' ~/libperf.a(libperf-in.o): In function _unwind__prepare_access':
:(.text+0xaedd0): undefined reference to _Ux86_create_addr_space' :(.text+0xaee24): undefined reference to _Ux86_set_caching_policy' ~/libperf.a(libperf-in.o): In function `_unwind__flush_access':
:(.text+0xaee98): undefined reference to _Ux86_flush_cache' ~/libperf.a(libperf-in.o): In function _unwind__finish_access':
:(.text+0xaef08): undefined reference to _Ux86_destroy_addr_space' ~/libperf.a(libperf-in.o): In function get_entries':
:(.text+0xaf148): undefined reference to _Ux86_init_remote' :(.text+0xaf184): undefined reference to _Ux86_get_reg' :(.text+0xaf1a4): undefined reference to `_Ux86_step'
collect2: error: ld returned 1 exit status
Makefile.perf:350: recipe for target '~/perf' failed
make[1]: *** [~/perf] Error 1
Makefile:68: recipe for target 'all' failed
make: *** [all] Error 2
This is because the remote libunwind library detected is not appended to EXTLIBS variable, which will be included between 'start-group' and 'end-group' when linking.
The existing variable LIBUNWIND_LIBS is assigned to libs for local unwind, this patch introduces a new variable EXTLIBS_LIBUNWIND for storing remote libunwind libraries instead.
--- tools/perf/config/Makefile | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/config/Makefile +3 -0
@@ -365,6 +365,7 @@ ifndef NO_LIBUNWIND $(call detected,CONFIG_LIBUNWIND_X86) CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT LDFLAGS += -lunwind-x86 + EXTLIBS_LIBUNWIND += -lunwind-x86 have_libunwind = 1 endif
@@ -372,6 +373,7 @@ ifndef NO_LIBUNWIND $(call detected,CONFIG_LIBUNWIND_AARCH64) CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT LDFLAGS += -lunwind-aarch64 + EXTLIBS_LIBUNWIND += -lunwind-aarch64 have_libunwind = 1 $(call feature_check,libunwind-debug-frame-aarch64) ifneq ($(feature-libunwind-debug-frame-aarch64), 1)
@@ -449,6 +451,7 @@ ifndef NO_LIBUNWIND CFLAGS += -DHAVE_LIBUNWIND_SUPPORT CFLAGS += $(LIBUNWIND_CFLAGS) LDFLAGS += $(LIBUNWIND_LDFLAGS) + EXTLIBS += $(EXTLIBS_LIBUNWIND) endif ifndef NO_LIBAUDIT
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 8/19 perf mem: Add --ldlat option
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Adding --ldlat option to specify desired latency for loads event.
Specify 50 as loads event latency:
$ perf mem record -e ldlat-loads -v --ldlat 50 true calling: record -W -d -e cpu/mem-loads,ldlat=50/P true
--- tools/perf/Documentation/perf-mem.txt | 3 +++ tools/perf/builtin-mem.c | 1 + tools/perf/util/mem-events.c | 17 ++++++++++++++++- tools/perf/util/mem-events.h | 1 + 4 files changed, 21 insertions(+), 1 deletion(-)
tools/perf/Documentation/perf-mem.txt +3 -0
@@ -56,6 +56,9 @@ OPTIONS --all-user:: Configure all used events to run in user space. +--ldload:: + Specify desired latency for loads event. + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-report[1]
tools/perf/builtin-mem.c +1 -0
@@ -67,6 +67,7 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)OPT_CALLBACK ('e' ,"event" , &mem,"event" ,"event selector. use 'perf mem record -e list' to list available events" , parse_record_events), +OPT_UINTEGER (0 ,"ldlat" , &perf_mem_events__loads_ldlat,"mem-loads latency" ),OPT_INCR ('v' ,"verbose" , &verbose,"be more verbose (show counter open errors, etc)" ), OPT_BOOLEAN('U', "--all-user", &all_user, "collect only user level data"),
tools/perf/util/mem-events.c +16 -1
@@ -10,18 +10,33 @@#include "debug.h" #include "symbol.h" +unsigned int perf_mem_events__loads_ldlat =30 ; +#define E (t, n, s) { .tag = t, .name = n, .sysfs_name = s }struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX ] = { -E ("ldlat-loads" ,"cpu/mem-loads,ldlat=30/P" ,"mem-loads" ), +E ("ldlat-loads" ,"cpu/mem-loads,ldlat=%u/P" ,"mem-loads" ),E ("ldlat-stores" ,"cpu/mem-stores/P" ,"mem-stores" ), };#undef E#undef E +static char mem_loads_name[100 ]; +static bool mem_loads_name__init; +char *perf_mem_events__name (int i) { +if (i ==PERF_MEM_EVENTS__LOAD ) { +if (!mem_loads_name__init) { + mem_loads_name__init = true; +scnprintf (mem_loads_name,sizeof (mem_loads_name), + perf_mem_events[i].name, + perf_mem_events__loads_ldlat); + } +return mem_loads_name; + } +return (char *)perf_mem_events[i].name; }
tools/perf/util/mem-events.h +1 -0
@@ -18,6 +18,7 @@ enum { };extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX ]; +extern unsigned int perf_mem_events__loads_ldlat;int perf_mem_events__parse (const char *str);int perf_mem_events__init (void );
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 9/19 perf tools: Fix Data Object sort entry width index
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Putting correct HISTC_MEM_DADDR_DSO index to Data Object sort entry.
--- tools/perf/util/sort.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/util/sort.c +1 -1
@@ -1218,7 +1218,7 @@ struct sort_entry sort_mem_daddr_dso = { .se_header = "Data Object", .se_cmp = sort__dso_daddr_cmp, .se_snprintf = hist_entry__dso_daddr_snprintf, - .se_width_idx = HISTC_MEM_DADDR_SYMBOL, + .se_width_idx = HISTC_MEM_DADDR_DSO, };struct sort_entry sort_mem_locked = {
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 10/19 perf tui: Separate hierarchy and standard headers output
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
It will be useful for future changes that enhance headers with multiple lines and span columns, which don't affect hierarchy headers.
--- tools/perf/ui/browsers/hists.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-)
tools/perf/ui/browsers/hists.c +24 -7
@@ -1622,21 +1622,38 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browsreturn ret; } -static void hist_browser__show_headers (struct hist_browser *browser) +static void hists_browser__hierarchy_headers (struct hist_browser *browser) {char headers[1024 ]; -if (symbol_conf.report_hierarchy) -hists_browser__scnprintf_hierarchy_headers (browser, headers, -sizeof (headers)); -else -hists_browser__scnprintf_headers (browser, headers, -sizeof (headers)); +hists_browser__scnprintf_hierarchy_headers (browser, headers, +sizeof (headers)); +ui_browser__gotorc (&browser->b,0 ,0 );ui_browser__set_color (&browser->b,HE_COLORSET_ROOT );ui_browser__write_nstring (&browser->b, headers, browser->b.width +1 ); } +static void hists_browser__headers (struct hist_browser *browser) +{ +char headers[1024 ]; + +hists_browser__scnprintf_headers (browser, headers, +sizeof (headers)); + +ui_browser__gotorc (&browser->b,0 ,0 ); +ui_browser__set_color (&browser->b,HE_COLORSET_ROOT ); +ui_browser__write_nstring (&browser->b, headers, browser->b.width +1 ); +} + +static void hist_browser__show_headers (struct hist_browser *browser) +{ +if (symbol_conf.report_hierarchy) +hists_browser__hierarchy_headers (browser); +else +hists_browser__headers (browser); +} +static void ui_browser__hists_init_top (struct ui_browser *browser) {if (browser->top ==NULL ) {
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 11/19 perf stdio: Separate headers output
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Introducing hists__fprintf_headers function to separate the code that displays headers.
--- tools/perf/ui/stdio/hist.c | 59 +++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 29 deletions(-)
tools/perf/ui/stdio/hist.c +30 -29
@@ -622,36 +622,18 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,return 2 ; } -size_t hists__fprintf (struct hists *hists,bool show_header,int max_rows, -int max_cols,float min_pcnt,FILE *fp) +static int hists__fprintf_headers (struct hists *hists,FILE *fp) {struct perf_hpp_fmt *fmt;struct perf_hpp_list_node *fmt_node; -struct rb_node *nd; -size_t ret =0 ;unsigned int width;const char *sep = symbol_conf.field_sep; -int nr_rows =0 ;char bf[96 ];struct perf_hpp dummy_hpp = { .buf = bf, .size =sizeof (bf), };bool first = true; -size_t linesz; -char *line =NULL ; -unsigned indent; - -init_rem_hits (); - -hists__for_each_format (hists, fmt) -perf_hpp__reset_width (fmt, hists); - -if (symbol_conf.col_width_list_str) -perf_hpp__set_user_width (symbol_conf.col_width_list_str); - -if (!show_header) - goto print_entries;fprintf (fp,"# " );
@@ -660,8 +642,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,perf_hpp_list__for_each_format (&fmt_node->hpp, fmt)perf_hpp__reset_width (fmt, hists); } - nr_rows +=print_hierarchy_header (hists, &dummy_hpp, sep, fp); - goto print_entries; +return print_hierarchy_header (hists, &dummy_hpp, sep, fp); }hists__for_each_format (hists, fmt) {
@@ -678,11 +659,9 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, }fprintf (fp,"\n" ); -if (max_rows && ++nr_rows >= max_rows) - goto out;if (sep) - goto print_entries; +return 1 ; first = true;
@@ -705,14 +684,36 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, }fprintf (fp,"\n" ); -if (max_rows && ++nr_rows >= max_rows) - goto out; -fprintf (fp,"#\n" ); -if (max_rows && ++nr_rows >= max_rows) +return 3 ; +} + +size_t hists__fprintf (struct hists *hists,bool show_header,int max_rows, +int max_cols,float min_pcnt,FILE *fp) +{ +struct perf_hpp_fmt *fmt; +struct rb_node *nd; +size_t ret =0 ; +const char *sep = symbol_conf.field_sep; +int nr_rows =0 ; +size_t linesz; +char *line =NULL ; +unsigned indent; + +init_rem_hits (); + +hists__for_each_format (hists, fmt) +perf_hpp__reset_width (fmt, hists); + +if (symbol_conf.col_width_list_str) +perf_hpp__set_user_width (symbol_conf.col_width_list_str); + +if (show_header) + nr_rows +=hists__fprintf_headers (hists, fp); + +if (max_rows && nr_rows >= max_rows) goto out; -print_entries: linesz =hists__sort_list_width (hists) +3 +1 ; linesz +=perf_hpp__color_overhead (); line =malloc (linesz);
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 12/19 perf stdio: Separate hierarchy headers output
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Introducing hists__fprintf_hierarchy_headers function to separate hierarchy headers display code.
--- tools/perf/ui/stdio/hist.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-)
tools/perf/ui/stdio/hist.c +18 -8
@@ -622,10 +622,25 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,return 2 ; } +static int +hists__fprintf_hierarchy_headers (struct hists *hists, +struct perf_hpp *hpp, +FILE *fp) +{ +struct perf_hpp_list_node *fmt_node; +struct perf_hpp_fmt *fmt; + +list_for_each_entry (fmt_node, &hists->hpp_formats, list) { +perf_hpp_list__for_each_format (&fmt_node->hpp, fmt) +perf_hpp__reset_width (fmt, hists); + } + +return print_hierarchy_header (hists, hpp, symbol_conf.field_sep, fp); +} +static int hists__fprintf_headers (struct hists *hists,FILE *fp) {struct perf_hpp_fmt *fmt; -struct perf_hpp_list_node *fmt_node;unsigned int width;const char *sep = symbol_conf.field_sep;char bf[96 ];
@@ -637,13 +652,8 @@ static int hists__fprintf_headers(struct hists *hists, FILE *fp)fprintf (fp,"# " ); -if (symbol_conf.report_hierarchy) { -list_for_each_entry (fmt_node, &hists->hpp_formats, list) { -perf_hpp_list__for_each_format (&fmt_node->hpp, fmt) -perf_hpp__reset_width (fmt, hists); - } -return print_hierarchy_header (hists, &dummy_hpp, sep, fp); - } +if (symbol_conf.report_hierarchy) +return hists__fprintf_hierarchy_headers (hists, &dummy_hpp, fp);hists__for_each_format (hists, fmt) {if (perf_hpp__should_skip (fmt, hists))
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 13/19 perf stdio: Separate standard headers output
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Introducing hists__fprintf_standard_headers function to separate standard headers display code.
--- tools/perf/ui/stdio/hist.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-)
tools/perf/ui/stdio/hist.c +24 -14
@@ -638,23 +638,16 @@ hists__fprintf_hierarchy_headers(struct hists *hists,return print_hierarchy_header (hists, hpp, symbol_conf.field_sep, fp); } -static int hists__fprintf_headers (struct hists *hists,FILE *fp) +static int +hists__fprintf_standard_headers (struct hists *hists, +struct perf_hpp *hpp, +FILE *fp) {struct perf_hpp_fmt *fmt;unsigned int width;const char *sep = symbol_conf.field_sep; -char bf[96 ]; -struct perf_hpp dummy_hpp = { - .buf = bf, - .size =sizeof (bf), - };bool first = true; -fprintf (fp,"# " ); - -if (symbol_conf.report_hierarchy) -return hists__fprintf_hierarchy_headers (hists, &dummy_hpp, fp); -hists__for_each_format (hists, fmt) {if (perf_hpp__should_skip (fmt, hists))continue ;
@@ -664,8 +657,8 @@ static int hists__fprintf_headers(struct hists *hists, FILE *fp)else first = false; - fmt->header (fmt, &dummy_hpp,hists_to_evsel (hists)); -fprintf (fp,"%s" , bf); + fmt->header (fmt, hpp,hists_to_evsel (hists)); +fprintf (fp,"%s" , hpp->buf); }fprintf (fp,"\n" );
@@ -688,7 +681,7 @@ static int hists__fprintf_headers(struct hists *hists, FILE *fp)else first = false; - width = fmt->width (fmt, &dummy_hpp,hists_to_evsel (hists)); + width = fmt->width (fmt, hpp,hists_to_evsel (hists));for (i =0 ; i < width; i++)fprintf (fp,"." ); }
@@ -698,6 +691,23 @@ static int hists__fprintf_headers(struct hists *hists, FILE *fp)return 3 ; } +static int hists__fprintf_headers (struct hists *hists,FILE *fp) +{ +char bf[96 ]; +struct perf_hpp dummy_hpp = { + .buf = bf, + .size =sizeof (bf), + }; + +fprintf (fp,"# " ); + +if (symbol_conf.report_hierarchy) +return hists__fprintf_hierarchy_headers (hists, &dummy_hpp, fp); +else +return hists__fprintf_standard_headers (hists, &dummy_hpp, fp); + +} +size_t hists__fprintf (struct hists *hists,bool show_header,int max_rows,int max_cols,float min_pcnt,FILE *fp) {
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 14/19 perf stdio: Do not pass hists in hist_entry__fprintf
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
There's no need, we have the hists pointer in struct hist_entry.
--- tools/perf/ui/stdio/hist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/perf/ui/stdio/hist.c +2 -2
@@ -492,7 +492,6 @@ out: }static int hist_entry__fprintf (struct hist_entry *he,size_t size, -struct hists *hists,char *bf,size_t bfsz,FILE *fp) {int ret;
@@ -500,6 +499,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, .buf = bf, .size = size, }; +struct hists *hists = he->hists;u64 total_period = hists->stats.total_period;if (size ==0 || size > bfsz)
@@ -755,7 +755,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,if (percent < min_pcnt)continue ; - ret +=hist_entry__fprintf (h, max_cols, hists, line, linesz, fp); + ret +=hist_entry__fprintf (h, max_cols, line, linesz, fp);if (max_rows && ++nr_rows >= max_rows)break ;
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 15/19 perf stdio: Add use_callchain parameter to hists__fprintf
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
It will be convenient in following patches to display hists entries without callchains even if they are defined.
--- tools/perf/builtin-diff.c | 3 ++- tools/perf/builtin-report.c | 3 ++- tools/perf/builtin-top.c | 2 +- tools/perf/ui/stdio/hist.c | 10 ++++++---- tools/perf/util/hist.h | 3 ++- 5 files changed, 13 insertions(+), 8 deletions(-)
tools/perf/builtin-diff.c +2 -1
@@ -666,7 +666,8 @@ static void hists__process(struct hists *hists)hists__precompute (hists);hists__output_resort (hists,NULL ); -hists__fprintf (hists, true,0 ,0 ,0 , stdout); +hists__fprintf (hists, true,0 ,0 ,0 , stdout, + symbol_conf.use_callchain); }static void data__fprintf (void )
tools/perf/builtin-report.c +2 -1
@@ -370,7 +370,8 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,continue ;hists__fprintf_nr_sample_events (hists, rep, evname, stdout); -hists__fprintf (hists, true,0 ,0 , rep->min_percent, stdout); +hists__fprintf (hists, true,0 ,0 , rep->min_percent, stdout, + symbol_conf.use_callchain);fprintf (stdout,"\n\n" ); }
tools/perf/builtin-top.c +1 -1
@@ -295,7 +295,7 @@ static void perf_top__print_sym_table(struct perf_top *top)hists__output_recalc_col_len (hists, top->print_entries - printed);putchar ('\n' );hists__fprintf (hists, false, top->print_entries - printed, win_width, - top->min_percent, stdout); + top->min_percent, stdout, symbol_conf.use_callchain); }static void prompt_integer (int *target,const char *msg)
tools/perf/ui/stdio/hist.c +6 -4
@@ -492,7 +492,8 @@ out: }static int hist_entry__fprintf (struct hist_entry *he,size_t size, -char *bf,size_t bfsz,FILE *fp) +char *bf,size_t bfsz,FILE *fp, +bool use_callchain) {int ret;struct perf_hpp hpp = {
@@ -512,7 +513,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, ret =fprintf (fp,"%s\n" , bf); -if (symbol_conf.use_callchain) +if (use_callchain) ret +=hist_entry_callchain__fprintf (he, total_period,0 , fp);return ret;
@@ -709,7 +710,8 @@ static int hists__fprintf_headers(struct hists *hists, FILE *fp) }size_t hists__fprintf (struct hists *hists,bool show_header,int max_rows, -int max_cols,float min_pcnt,FILE *fp) +int max_cols,float min_pcnt,FILE *fp, +bool use_callchain) {struct perf_hpp_fmt *fmt;struct rb_node *nd;
@@ -755,7 +757,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,if (percent < min_pcnt)continue ; - ret +=hist_entry__fprintf (h, max_cols, line, linesz, fp); + ret +=hist_entry__fprintf (h, max_cols, line, linesz, fp, use_callchain);if (max_rows && ++nr_rows >= max_rows)break ;
tools/perf/util/hist.h +2 -1
@@ -159,7 +159,8 @@ void events_stats__inc(struct events_stats *stats, u32 type);size_t events_stats__fprintf (struct events_stats *stats,FILE *fp);size_t hists__fprintf (struct hists *hists,bool show_header,int max_rows, -int max_cols,float min_pcnt,FILE *fp); +int max_cols,float min_pcnt,FILE *fp, +bool use_callchain);size_t perf_evlist__fprintf_nr_events (struct perf_evlist *evlist,FILE *fp);void hists__filter_by_dso (struct hists *hists);
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 16/19 perf hists: Replace perf_evsel arg perf_hpp_fmt's header callback
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Replacing perf_evsel arg perf_hpp_fmt's header callback with hists object.
None of the actual callbacks actually use evsel object, also this will be helpful in future for non evsel related hist browsers.
--- tools/perf/builtin-diff.c | 2 +- tools/perf/ui/browsers/hists.c | 6 +++--- tools/perf/ui/gtk/hists.c | 2 +- tools/perf/ui/hist.c | 4 ++-- tools/perf/ui/stdio/hist.c | 6 +++--- tools/perf/util/hist.h | 2 +- tools/perf/util/sort.c | 6 +++--- 7 files changed, 14 insertions(+), 14 deletions(-)
tools/perf/builtin-diff.c +1 -1
@@ -1045,7 +1045,7 @@ static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp, }static int hpp__header (struct perf_hpp_fmt *fmt,struct perf_hpp *hpp, -struct perf_evsel *evsel__maybe_unused ) +struct hists *hists__maybe_unused ) {struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt);
tools/perf/ui/browsers/hists.c +3 -3
@@ -1531,7 +1531,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *if (perf_hpp__should_skip (fmt, hists) || column++ < browser->b.horiz_scroll)continue ; - ret = fmt->header (fmt, &dummy_hpp,hists_to_evsel (hists)); + ret = fmt->header (fmt, &dummy_hpp, hists);if (advance_hpp_check (&dummy_hpp, ret))break ;
@@ -1568,7 +1568,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browsif (column++ < browser->b.horiz_scroll)continue ; - ret = fmt->header (fmt, &dummy_hpp,hists_to_evsel (hists)); + ret = fmt->header (fmt, &dummy_hpp, hists);if (advance_hpp_check (&dummy_hpp, ret))break ;
@@ -1605,7 +1605,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows } first_col = false; - ret = fmt->header (fmt, &dummy_hpp,hists_to_evsel (hists)); + ret = fmt->header (fmt, &dummy_hpp, hists); dummy_hpp.buf[ret] ='\0' ; start =trim (dummy_hpp.buf);
tools/perf/ui/gtk/hists.c +1 -1
@@ -549,7 +549,7 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,strcat (buf,"+" ); first_col = false; - fmt->header (fmt, &hpp,hists_to_evsel (hists)); + fmt->header (fmt, &hpp, hists);strcat (buf,ltrim (rtrim (hpp.buf))); } }
tools/perf/ui/hist.c +2 -2
@@ -229,9 +229,9 @@ static int hpp__width_fn(struct perf_hpp_fmt *fmt, }static int hpp__header_fn (struct perf_hpp_fmt *fmt,struct perf_hpp *hpp, -struct perf_evsel *evsel) +struct hists *hists) { -int len =hpp__width_fn (fmt, hpp, evsel); +int len =hpp__width_fn (fmt, hpp,hists_to_evsel (hists));return scnprintf (hpp->buf, hpp->size,"%*s" , len, fmt->name); }
tools/perf/ui/stdio/hist.c +3 -3
@@ -549,7 +549,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, struct perf_hpp_list_node, list);perf_hpp_list__for_each_format (&fmt_node->hpp, fmt) { - fmt->header (fmt, hpp,hists_to_evsel (hists)); + fmt->header (fmt, hpp, hists);fprintf (fp,"%s%s" , hpp->buf, sep ?:" " ); }
@@ -569,7 +569,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, header_width +=fprintf (fp,"+" ); first_col = false; - fmt->header (fmt, hpp,hists_to_evsel (hists)); + fmt->header (fmt, hpp, hists); header_width +=fprintf (fp,"%s" ,trim (hpp->buf)); }
@@ -658,7 +658,7 @@ hists__fprintf_standard_headers(struct hists *hists,else first = false; - fmt->header (fmt, hpp,hists_to_evsel (hists)); + fmt->header (fmt, hpp, hists);fprintf (fp,"%s" , hpp->buf); }
tools/perf/util/hist.h +1 -1
@@ -215,7 +215,7 @@ struct perf_hpp {struct perf_hpp_fmt {const char *name;int (*header)(struct perf_hpp_fmt *fmt,struct perf_hpp *hpp, -struct perf_evsel *evsel); +struct hists *hists);int (*width)(struct perf_hpp_fmt *fmt,struct perf_hpp *hpp,struct perf_evsel *evsel); int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
tools/perf/util/sort.c +3 -3
@@ -1488,7 +1488,7 @@ void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) }static int __sort__hpp_header (struct perf_hpp_fmt *fmt,struct perf_hpp *hpp, -struct perf_evsel *evsel) +struct hists *hists) {struct hpp_sort_entry *hse;size_t len = fmt->user_len;
@@ -1496,7 +1496,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, hse = container_of(fmt, struct hpp_sort_entry, hpp);if (!len) - len =hists__col_len (evsel__hists (evsel), hse->se->se_width_idx); + len =hists__col_len (hists, hse->se->se_width_idx);return scnprintf (hpp->buf, hpp->size,"%-*.*s" , len, len, fmt->name); }
@@ -1793,7 +1793,7 @@ static void update_dynamic_len(struct hpp_dynamic_entry *hde, }static int __sort__hde_header (struct perf_hpp_fmt *fmt,struct perf_hpp *hpp, -struct perf_evsel *evsel__maybe_unused ) +struct hists *hists__maybe_unused ) {struct hpp_dynamic_entry *hde;size_t len = fmt->user_len;
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 17/19 perf hists: Replace perf_evsel arg perf_hpp_fmt's width callback
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Replacing perf_evsel arg perf_hpp_fmt's width callback with hists object.
This will be helpful in future for non evsel related hist browsers.
--- tools/perf/builtin-diff.c | 2 +- tools/perf/ui/browsers/hists.c | 2 +- tools/perf/ui/hist.c | 9 +++++---- tools/perf/ui/stdio/hist.c | 6 +++--- tools/perf/util/hist.c | 2 +- tools/perf/util/hist.h | 2 +- tools/perf/util/sort.c | 6 +++--- 7 files changed, 15 insertions(+), 14 deletions(-)
tools/perf/builtin-diff.c +1 -1
@@ -1056,7 +1056,7 @@ static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,static int hpp__width (struct perf_hpp_fmt *fmt,struct perf_hpp *hpp__maybe_unused , -struct perf_evsel *evsel__maybe_unused ) +struct hists *hists__maybe_unused ) {struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt);
tools/perf/ui/browsers/hists.c +1 -1
@@ -1470,7 +1470,7 @@ static int hist_browser__show_no_entry(struct hist_browser *browser, column++ < browser->b.horiz_scroll)continue ; - ret = fmt->width (fmt,NULL ,hists_to_evsel (browser->hists)); + ret = fmt->width (fmt,NULL , browser->hists);if (first) {/* for folded sign */
tools/perf/ui/hist.c +5 -4
@@ -215,9 +215,10 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,static int hpp__width_fn (struct perf_hpp_fmt *fmt,struct perf_hpp *hpp__maybe_unused , -struct perf_evsel *evsel) +struct hists *hists) {int len = fmt->user_len ?: fmt->len; +struct perf_evsel *evsel =hists_to_evsel (hists);if (symbol_conf.event_group) len =max (len, evsel->nr_members * fmt->len);
@@ -231,7 +232,7 @@ static int hpp__width_fn(struct perf_hpp_fmt *fmt,static int hpp__header_fn (struct perf_hpp_fmt *fmt,struct perf_hpp *hpp,struct hists *hists) { -int len =hpp__width_fn (fmt, hpp,hists_to_evsel (hists)); +int len =hpp__width_fn (fmt, hpp, hists);return scnprintf (hpp->buf, hpp->size,"%*s" , len, fmt->name); }
@@ -632,7 +633,7 @@ unsigned int hists__sort_list_width(struct hists *hists)else ret +=2 ; - ret += fmt->width (fmt, &dummy_hpp,hists_to_evsel (hists)); + ret += fmt->width (fmt, &dummy_hpp, hists); }if (verbose &&hists__has (hists, sym))/* Addr + origin */
@@ -657,7 +658,7 @@ unsigned int hists__overhead_width(struct hists *hists)else ret +=2 ; - ret += fmt->width (fmt, &dummy_hpp,hists_to_evsel (hists)); + ret += fmt->width (fmt, &dummy_hpp, hists); }return ret;
tools/perf/ui/stdio/hist.c +3 -3
@@ -590,7 +590,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,fprintf (fp,"%s" , sep ?:".." ); first_col = false; - width = fmt->width (fmt, hpp,hists_to_evsel (hists)); + width = fmt->width (fmt, hpp, hists);fprintf (fp,"%.*s" , width, dots); }
@@ -607,7 +607,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, width++;/* for '+' sign between column header */ first_col = false; - width += fmt->width (fmt, hpp,hists_to_evsel (hists)); + width += fmt->width (fmt, hpp, hists); }if (width > header_width)
@@ -682,7 +682,7 @@ hists__fprintf_standard_headers(struct hists *hists,else first = false; - width = fmt->width (fmt, hpp,hists_to_evsel (hists)); + width = fmt->width (fmt, hpp, hists);for (i =0 ; i < width; i++)fprintf (fp,"." ); }
tools/perf/util/hist.c +1 -1
@@ -1081,7 +1081,7 @@ int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp, struct perf_hpp_fmt *fmt, int printed) {if (!list_is_last (&fmt->list, &he->hists->hpp_list->fields)) { -const int width = fmt->width (fmt, hpp,hists_to_evsel (he->hists)); +const int width = fmt->width (fmt, hpp, he->hists);if (printed < width) {advance_hpp (hpp, printed); printed =scnprintf (hpp->buf, hpp->size,"%-*s" , width - printed," " );
tools/perf/util/hist.h +1 -1
@@ -217,7 +217,7 @@ struct perf_hpp_fmt {int (*header)(struct perf_hpp_fmt *fmt,struct perf_hpp *hpp,struct hists *hists);int (*width)(struct perf_hpp_fmt *fmt,struct perf_hpp *hpp, -struct perf_evsel *evsel); +struct hists *hists);int (*color)(struct perf_hpp_fmt *fmt,struct perf_hpp *hpp,struct hist_entry *he); int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
tools/perf/util/sort.c +3 -3
@@ -1503,7 +1503,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,static int __sort__hpp_width (struct perf_hpp_fmt *fmt,struct perf_hpp *hpp__maybe_unused , -struct perf_evsel *evsel) +struct hists *hists) {struct hpp_sort_entry *hse;size_t len = fmt->user_len;
@@ -1511,7 +1511,7 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt, hse = container_of(fmt, struct hpp_sort_entry, hpp);if (!len) - len =hists__col_len (evsel__hists (evsel), hse->se->se_width_idx); + len =hists__col_len (hists, hse->se->se_width_idx);return len; }
@@ -1808,7 +1808,7 @@ static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,static int __sort__hde_width (struct perf_hpp_fmt *fmt,struct perf_hpp *hpp__maybe_unused , -struct perf_evsel *evsel__maybe_unused ) +struct hists *hists__maybe_unused ) {struct hpp_dynamic_entry *hde;size_t len = fmt->user_len;
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 18/19 perf probe: Introduce perf_cache interfaces
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Introduce perf_cache object and interfaces to create, add entries, commit, and delete the object.
perf_cache represents a file for the cached "perf probe" definitions on one binary file or vmlinux which has its own build id. The probe cache file is located under the build-id cache directory of the target binary, as below;
<perf-debug-dir>/.build-id/<BU>/<ILDID>/probe
--- tools/perf/util/probe-file.c | 331 +++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/probe-file.h | 20 +++ 2 files changed, 351 insertions(+)
tools/perf/util/probe-file.c +331 -0
@@ -14,6 +14,7 @@* GNU General Public License for more details. * */ +#include <sys/uio.h> #include "util.h" #include "event.h" #include "strlist.h"
@@ -324,3 +325,333 @@ int probe_file__del_events(int fd, struct strfilter *filter)return ret; } + +/* Caller must ensure to remove this entry from list */ +static void probe_cache_entry__delete (struct probe_cache_entry *entry) +{ +if (entry) { +BUG_ON (!list_empty (&entry->node)); + +strlist__delete (entry->tevlist); +clear_perf_probe_event (&entry->pev); +zfree (&entry->spev); +free (entry); + } +} + +static struct probe_cache_entry * +probe_cache_entry__new (struct perf_probe_event *pev) +{ +struct probe_cache_entry *entry =zalloc (sizeof (*entry)); + +if (entry) { +INIT_LIST_HEAD (&entry->node); + entry->tevlist =strlist__new (NULL ,NULL ); +if (!entry->tevlist) +zfree (&entry); +else if (pev) { + entry->spev =synthesize_perf_probe_command (pev); +if (!entry->spev || +perf_probe_event__copy (&entry->pev, pev) <0 ) { +probe_cache_entry__delete (entry); +return NULL ; + } + } + } + +return entry; +} + +/* For the kernel probe caches, pass target = NULL */ +static int probe_cache__open (struct probe_cache *pcache,const char *target) +{ +char cpath[PATH_MAX ]; +char sbuildid[SBUILD_ID_SIZE ]; +char *dir_name; +bool is_kallsyms = !target; +int ret, fd; + +if (target) + ret =filename__sprintf_build_id (target, sbuildid); +else { + target =DSO__NAME_KALLSYMS ; + ret =sysfs__sprintf_build_id ("/" , sbuildid); + } +if (ret <0 ) { +pr_debug ("Failed to get build-id from %s.\n" , target); +return ret; + } + +/* If we have no buildid cache, make it */ +if (!build_id_cache__cached (sbuildid)) { + ret =build_id_cache__add_s (sbuildid, target, + is_kallsyms,NULL ); +if (ret <0 ) { +pr_debug ("Failed to add build-id cache: %s\n" , target); +return ret; + } + } + + dir_name =build_id_cache__cachedir (sbuildid, target, is_kallsyms, + false); +if (!dir_name) +return -ENOMEM ; + +snprintf (cpath,PATH_MAX ,"%s/probes" , dir_name); + fd =open (cpath,O_CREAT |O_RDWR ,0644 ); +if (fd <0 ) +pr_debug ("Failed to open cache(%d): %s\n" , fd, cpath); +free (dir_name); + pcache->fd = fd; + +return fd; +} + +static int probe_cache__load (struct probe_cache *pcache) +{ +struct probe_cache_entry *entry =NULL ; +char buf[MAX_CMDLEN ], *p; +int ret =0 ; +FILE *fp; + + fp =fdopen (dup (pcache->fd),"r" ); +if (!fp) +return -EINVAL ; + +while (!feof (fp)) { +if (!fgets (buf,MAX_CMDLEN , fp)) +break ; + p =strchr (buf,'\n' ); +if (p) + *p ='\0' ; +if (buf[0 ] =='#' ) {/* #perf_probe_event */ + entry =probe_cache_entry__new (NULL ); +if (!entry) { + ret = -ENOMEM ; + goto out; + } + entry->spev =strdup (buf +1 ); +if (entry->spev) + ret =parse_perf_probe_command (buf +1 , + &entry->pev); +else + ret = -ENOMEM ; +if (ret <0 ) { +probe_cache_entry__delete (entry); + goto out; + } +list_add_tail (&entry->node, &pcache->entries); + }else {/* trace_probe_event */ +if (!entry) { + ret = -EINVAL ; + goto out; + } +strlist__add (entry->tevlist, buf); + } + } +out: +fclose (fp); +return ret; +} + +static struct probe_cache *probe_cache__alloc (void ) +{ +struct probe_cache *pcache =zalloc (sizeof (*pcache)); + +if (pcache) { +INIT_LIST_HEAD (&pcache->entries); + pcache->fd = -EINVAL ; + } +return pcache; +} + +void probe_cache__purge (struct probe_cache *pcache) +{ +struct probe_cache_entry *entry, *n; + +list_for_each_entry_safe (entry, n, &pcache->entries, node) { +list_del_init (&entry->node); +probe_cache_entry__delete (entry); + } +} + +void probe_cache__delete (struct probe_cache *pcache) +{ +if (!pcache) +return ; + +probe_cache__purge (pcache); +if (pcache->fd >0 ) +close (pcache->fd); +free (pcache); +} + +struct probe_cache *probe_cache__new (const char *target) +{ +struct probe_cache *pcache =probe_cache__alloc (); +int ret; + +if (!pcache) +return NULL ; + + ret =probe_cache__open (pcache, target); +if (ret <0 ) { +pr_debug ("Cache open error: %d\n" , ret); + goto out_err; + } + + ret =probe_cache__load (pcache); +if (ret <0 ) { +pr_debug ("Cache read error: %d\n" , ret); + goto out_err; + } + +return pcache; + +out_err: +probe_cache__delete (pcache); +return NULL ; +} + +static bool streql (const char *a,const char *b) +{ +if (a == b) +return true; + +if (!a || !b) +return false; + +return !strcmp (a, b); +} + +static struct probe_cache_entry * +probe_cache__find (struct probe_cache *pcache,struct perf_probe_event *pev) +{ +struct probe_cache_entry *entry =NULL ; +char *cmd =synthesize_perf_probe_command (pev); + +if (!cmd) +return NULL ; + +list_for_each_entry (entry, &pcache->entries, node) { +/* Hit if same event name or same command-string */ +if ((pev->event && + (streql (entry->pev.group, pev->group) && +streql (entry->pev.event, pev->event))) || + (!strcmp (entry->spev, cmd))) + goto found; + } + entry =NULL ; + +found: +free (cmd); +return entry; +} + +int probe_cache__add_entry (struct probe_cache *pcache, +struct perf_probe_event *pev, +struct probe_trace_event *tevs,int ntevs) +{ +struct probe_cache_entry *entry =NULL ; +char *command; +int i, ret =0 ; + +if (!pcache || !pev || !tevs || ntevs <=0 ) { + ret = -EINVAL ; + goto out_err; + } + +/* Remove old cache entry */ + entry =probe_cache__find (pcache, pev); +if (entry) { +list_del_init (&entry->node); +probe_cache_entry__delete (entry); + } + + ret = -ENOMEM ; + entry =probe_cache_entry__new (pev); +if (!entry) + goto out_err; + +for (i =0 ; i < ntevs; i++) { +if (!tevs[i].point.symbol) +continue ; + + command =synthesize_probe_trace_command (&tevs[i]); +if (!command) + goto out_err; +strlist__add (entry->tevlist, command); +free (command); + } +list_add_tail (&entry->node, &pcache->entries); +pr_debug ("Added probe cache: %d\n" , ntevs); +return 0 ; + +out_err: +pr_debug ("Failed to add probe caches\n" ); +probe_cache_entry__delete (entry); +return ret; +} + +static int probe_cache_entry__write (struct probe_cache_entry *entry,int fd) +{ +struct str_node *snode; +struct stat st; +struct iovec iov[3 ]; +int ret; +/* Save stat for rollback */ + ret =fstat (fd, &st); +if (ret <0 ) +return ret; + +pr_debug ("Writing cache: #%s\n" , entry->spev); + iov[0 ].iov_base = (void *)"#" ; iov[0 ].iov_len =1 ; + iov[1 ].iov_base = entry->spev; iov[1 ].iov_len =strlen (entry->spev); + iov[2 ].iov_base = (void *)"\n" ; iov[2 ].iov_len =1 ; + ret =writev (fd, iov,3 ); +if (ret < (int )iov[1 ].iov_len +2 ) + goto rollback; + +strlist__for_each (snode, entry->tevlist) { + iov[0 ].iov_base = (void *)snode->s; + iov[0 ].iov_len =strlen (snode->s); + iov[1 ].iov_base = (void *)"\n" ; iov[1 ].iov_len =1 ; + ret =writev (fd, iov,2 ); +if (ret < (int )iov[0 ].iov_len +1 ) + goto rollback; + } +return 0 ; + +rollback: +/* Rollback to avoid cache file corruption */ +if (ret >0 ) + ret =-1 ; +if (ftruncate (fd, st.st_size) <0 ) + ret =-2 ; + +return ret; +} + +int probe_cache__commit (struct probe_cache *pcache) +{ +struct probe_cache_entry *entry; +int ret =0 ; + +/* TBD: if we do not update existing entries, skip it */ + ret =lseek (pcache->fd,0 ,SEEK_SET ); +if (ret <0 ) + goto out; + + ret =ftruncate (pcache->fd,0 ); +if (ret <0 ) + goto out; + +list_for_each_entry (entry, &pcache->entries, node) { + ret =probe_cache_entry__write (entry, pcache->fd); +pr_debug ("Cache committed: %d\n" , ret); +if (ret <0 ) +break ; + } +out: +return ret; +}
tools/perf/util/probe-file.h +20 -0
@@ -5,6 +5,19 @@#include "strfilter.h" #include "probe-event.h" +/* Cache of probe definitions */ +struct probe_cache_entry { +struct list_head node; +struct perf_probe_event pev; +char *spev; +struct strlist *tevlist; +}; + +struct probe_cache { +int fd; +struct list_head entries; +}; +#define PF_FL_UPROBE 1#define PF_FL_RW 2
@@ -18,5 +31,12 @@ int probe_file__get_events(int fd, struct strfilter *filter, struct strlist *plist);int probe_file__del_strlist (int fd,struct strlist *namelist); +struct probe_cache *probe_cache__new (const char *target); +int probe_cache__add_entry (struct probe_cache *pcache, +struct perf_probe_event *pev, +struct probe_trace_event *tevs,int ntevs); +int probe_cache__commit (struct probe_cache *pcache); +void probe_cache__purge (struct probe_cache *pcache); +void probe_cache__delete (struct probe_cache *pcache);#endif
Signature · 1 line
2.5.5
Arnaldo Carvalho de Melo
maintainerPATCH 19/19 perf probe: Add --cache option to cache the probe definitions
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Add --cache option to cache the probe definitions. This just saves the result of the dwarf analysis to probe cache.
--- tools/perf/Documentation/perf-probe.txt | 4 ++++ tools/perf/builtin-probe.c | 1 + tools/perf/util/probe-event.c | 9 +++++++++ tools/perf/util/probe-event.h | 1 + 4 files changed, 15 insertions(+)
tools/perf/Documentation/perf-probe.txt +4 -0
@@ -109,6 +109,10 @@ OPTIONS Dry run. With this option, --add and --del doesn't execute actual adding and removal operations. +--cache:: + Cache the probes (with --add option). Any events which successfully added + are also stored in the cache file. + --max-probes=NUM:: Set the maximum number of probe points for an event. Default is 128.
tools/perf/builtin-probe.c +1 -0
@@ -512,6 +512,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) "Enable symbol demangling"),OPT_BOOLEAN (0 ,"demangle-kernel" , &symbol_conf.demangle_kernel,"Enable kernel symbol demangling" ), +OPT_BOOLEAN (0 ,"cache" , &probe_conf.cache,"Manipulate probe cache" ), OPT_END() };int ret;
tools/perf/util/probe-event.c +9 -0
@@ -2514,6 +2514,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, {int i, fd, ret;struct probe_trace_event *tev =NULL ; +struct probe_cache *cache =NULL ;struct strlist *namelist; fd =probe_file__open (PF_FL_RW | (pev->uprobes ?PF_FL_UPROBE :0 ));
@@ -2555,6 +2556,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, }if (ret == -EINVAL && pev->uprobes)warn_uprobe_event_compat (tev); +if (ret ==0 && probe_conf.cache) { + cache =probe_cache__new (pev->target); +if (!cache || +probe_cache__add_entry (cache, pev, tevs, ntevs) <0 || +probe_cache__commit (cache) <0 ) +pr_warning ("Failed to add event to probe cache\n" ); +probe_cache__delete (cache); + }strlist__delete (namelist); close_out:
tools/perf/util/probe-event.h +1 -0
@@ -12,6 +12,7 @@ struct probe_conf {bool show_location_range;bool force_add;bool no_inlines; +bool cache;int max_probes; };extern struct probe_conf probe_conf;
Signature · 1 line
2.5.5
On Wed, Jun 15, 2016 at 03:13:09PM -0300, Arnaldo Carvalho de Melo wrote:
SNIP
Quoted 4 lines
----------------------------------------------------------------
He Kuang (1):
perf unwind: Fix compile error for static cross build
Quoted 11 lines
Jiri Olsa (10):
perf mem: Add --ldlat option
perf tools: Fix Data Object sort entry width index perf tui: Separate hierarchy and standard headers output perf stdio: Separate headers output
perf stdio: Separate hierarchy headers output
perf stdio: Separate standard headers output
perf stdio: Do not pass hists inhist_entry__fprintfperf stdio: Adduse_callchainparameter tohists__fprintfperf hists: Replaceperf_evselarg perf_hpp_fmt's header callback perf hists: Replaceperf_evselarg perf_hpp_fmt's width callback
hi,
any reason for skipping this one?:
perf tools: Rename __hists__add_entry to hists__add_entry
thanks,
jirka
Arnaldo Carvalho de Melo
maintainerEm Thu, Jun 16, 2016 at 08:29:47AM +0200, Jiri Olsa escreveu:
Quoted 19 lines · Arnaldo Carvalho de Melo
SNIP
Quoted 4 lines
----------------------------------------------------------------
He Kuang (1):
perf unwind: Fix compile error for static cross buildQuoted 11 lines
Jiri Olsa (10):
perf mem: Add --ldlat option
perf tools: Fix Data Object sort entry width index perf tui: Separate hierarchy and standard headers output perf stdio: Separate headers output
perf stdio: Separate hierarchy headers output
perf stdio: Separate standard headers output
perf stdio: Do not pass hists inhist_entry__fprintfperf stdio: Adduse_callchainparameter tohists__fprintfperf hists: Replaceperf_evselarg perf_hpp_fmt's header callback perf hists: Replaceperf_evselarg perf_hpp_fmt's width callback
Quoted 3 lines
hi,
any reason for skipping this one?:
perf tools: Rename__hists__add_entrytohists__add_entry
nope, will apply.
- Arnaldo
Quoted 88 lines · Arnaldo Carvalho de Melo
Hi Ingo,
Please consider pulling,
- Arnaldo
The following changes since commit
2c95afc1e83d93fac3be6923465e1753c2c53b0a:perf/x86/intel, watchdog: Switch NMI watchdog to ref cycles on x86 (2016-06-14 11:16:59 +0200)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.gittags/perf-core-for-mingo-20160615for you to fetch changes up to
2fd457a34525ea3bc609e377b46af759af8a7934:perf probe: Add --cache option to cache the probe definitions (2016-06-15 14:34:42 -0300)
----------------------------------------------------------------
perf/core improvements and fixes:User visible:
- Add --ldlat option to 'perf mem' to specify load latency for loads event (e.g. cpu/mem-loads/ ) (Jiri Olsa)
Build fixes:
- Fix libunwind related compile error for static cross build (He Kuang)
Infrastructure:
- UI refactorings to support headers with multiple lines, non-evsel hists browsers, toggle showing callchains, etc (Jiri Olsa)
- More prep work for caching probe definitions, paving the way
for supporting SDT (Statically Defined Traces) userspace probes (Masami Hiramatsu)- Handle NULL at
perf_config_set__delete()(Taeung Song)Signed-off-by Arnaldo Carvalho de Melo <[email protected]>----------------------------------------------------------------
He Kuang (1):
perf unwind: Fix compile error for static cross buildJiri Olsa (10):
perf mem: Add --ldlat option
perf tools: Fix Data Object sort entry width index perf tui: Separate hierarchy and standard headers output perf stdio: Separate headers output
perf stdio: Separate hierarchy headers output
perf stdio: Separate standard headers output
perf stdio: Do not pass hists inhist_entry__fprintfperf stdio: Adduse_callchainparameter tohists__fprintfperf hists: Replaceperf_evselarg perf_hpp_fmt's header callback perf hists: Replaceperf_evselarg perf_hpp_fmt's width callbackMasami Hiramatsu (7):
perf tools: Fixrm_rf()to handle non-regular files correctly perf probe: Fix to add NULL check for strndup
perf buildid: Rename and exportbuild_id_cache__cachedir()perf probe: Addperf_probe_event__copy()
perf probe: Uncomment and exportsynthesize_perf_probe_point()perf probe: Introduceperf_cacheinterfaces
perf probe: Add --cache option to cache the probe definitionsTaeung Song (1):
perf config: Handle NULL atperf_config_set__delete()tools/perf/Documentation/perf-mem.txt | 3 + tools/perf/Documentation/perf-probe.txt | 4 + tools/perf/builtin-diff.c | 7 +- tools/perf/builtin-mem.c | 1 + tools/perf/builtin-probe.c | 1 + tools/perf/builtin-report.c | 3 +- tools/perf/builtin-top.c | 2 +- tools/perf/config/Makefile | 3 + tools/perf/ui/browsers/hists.c | 39 ++-- tools/perf/ui/gtk/hists.c | 2 +- tools/perf/ui/hist.c | 11 +- tools/perf/ui/stdio/hist.c | 133 +++++++------ tools/perf/util/build-id.c | 12 +- tools/perf/util/build-id.h | 2 + tools/perf/util/config.c | 3 + tools/perf/util/hist.c | 2 +- tools/perf/util/hist.h | 7 +- tools/perf/util/mem-events.c | 17 +-
Quoted 8 lines
tools/perf/util/mem-events.h | 1 + tools/perf/util/probe-event.c | 128 ++++++++++-- tools/perf/util/probe-event.h | 5 + tools/perf/util/probe-file.c | 331 ++++++++++++++++++++++++++++++++ tools/perf/util/probe-file.h | 20 ++ tools/perf/util/sort.c | 14 +- tools/perf/util/util.c | 13 +- 25 files changed, 640 insertions(+), 124 deletions(-)
Pulled, thanks a lot Arnaldo!
Ingo