From d01bd1ac920e98e2a64f6bb5adf907180e0aaac7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 16 May 2018 16:09:08 -0300 Subject: [PATCH 01/18] perf config: Call perf_config__init() lazily We check what perf_config__init() does at each perf_config() call, namely if the static perf_config instance was created, so instead of bailing out in that case, try to allocate it, bailing if it fails. Now to get the perf_config() call out of the start of perf's main() function, doing it also lazily. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Taeung Song Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-4bo45k6ivsmbxpfpdte4orsg@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/perf.c | 1 - tools/perf/util/config.c | 16 +++++++++------- tools/perf/util/config.h | 1 - 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 20a08cb32332..cd6ea55d4b0c 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -458,7 +458,6 @@ int main(int argc, const char **argv) srandom(time(NULL)); - perf_config__init(); err = perf_config(perf_default_config, NULL); if (err) return err; diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 84eb9393c7db..5ac157056cdf 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -707,6 +707,14 @@ struct perf_config_set *perf_config_set__new(void) return set; } +static int perf_config__init(void) +{ + if (config_set == NULL) + config_set = perf_config_set__new(); + + return config_set == NULL; +} + int perf_config(config_fn_t fn, void *data) { int ret = 0; @@ -714,7 +722,7 @@ int perf_config(config_fn_t fn, void *data) struct perf_config_section *section; struct perf_config_item *item; - if (config_set == NULL) + if (config_set == NULL && perf_config__init()) return -1; perf_config_set__for_each_entry(config_set, section, item) { @@ -735,12 +743,6 @@ int perf_config(config_fn_t fn, void *data) return ret; } -void perf_config__init(void) -{ - if (config_set == NULL) - config_set = perf_config_set__new(); -} - void perf_config__exit(void) { perf_config_set__delete(config_set); diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h index baf82bf227ac..bd0a5897c76a 100644 --- a/tools/perf/util/config.h +++ b/tools/perf/util/config.h @@ -38,7 +38,6 @@ struct perf_config_set *perf_config_set__new(void); void perf_config_set__delete(struct perf_config_set *set); int perf_config_set__collect(struct perf_config_set *set, const char *file_name, const char *var, const char *value); -void perf_config__init(void); void perf_config__exit(void); void perf_config__refresh(void); From 00a6270361c025bfaae1d70ef1b596d182e05e8a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 16 May 2018 16:20:12 -0300 Subject: [PATCH 02/18] tools lib api: The tracing_mnt variable doesn't need to be global Its only used in the file it is defined, so just make it static. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-p5x29u6mq2ml3mtnbg9844ad@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/tracing_path.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c index 7b7fd0b18551..4f8ec7d476b8 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -13,8 +13,7 @@ #include "tracing_path.h" - -char tracing_mnt[PATH_MAX] = "/sys/kernel/debug"; +static char tracing_mnt[PATH_MAX] = "/sys/kernel/debug"; char tracing_path[PATH_MAX] = "/sys/kernel/debug/tracing"; char tracing_events_path[PATH_MAX] = "/sys/kernel/debug/tracing/events"; @@ -129,7 +128,7 @@ int tracing_path__strerror_open_tp(int err, char *buf, size_t size, snprintf(buf, size, "Error:\tNo permissions to read %s/%s\n" "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", - tracing_events_path, filename, tracing_mnt); + tracing_events_path, filename, tracing_path_mount()); } break; default: From 17c257e867be1880eaf7c1b9dac286086d75d1ec Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 16 May 2018 16:27:14 -0300 Subject: [PATCH 03/18] tools lib api: Unexport 'tracing_path' variable One should use tracing_path_mount() instead, so more things get done lazily instead of at every 'perf' tool call startup. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-fci4yll35idd9yuslp67vqc2@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/tracing_path.c | 4 ++-- tools/lib/api/fs/tracing_path.h | 1 - tools/perf/perf.c | 5 +---- tools/perf/util/probe-file.c | 3 +-- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c index 4f8ec7d476b8..6f5fe942eff4 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -14,7 +14,7 @@ #include "tracing_path.h" static char tracing_mnt[PATH_MAX] = "/sys/kernel/debug"; -char tracing_path[PATH_MAX] = "/sys/kernel/debug/tracing"; +static char tracing_path[PATH_MAX] = "/sys/kernel/debug/tracing"; char tracing_events_path[PATH_MAX] = "/sys/kernel/debug/tracing/events"; @@ -75,7 +75,7 @@ char *get_tracing_file(const char *name) { char *file; - if (asprintf(&file, "%s/%s", tracing_path, name) < 0) + if (asprintf(&file, "%s/%s", tracing_path_mount(), name) < 0) return NULL; return file; diff --git a/tools/lib/api/fs/tracing_path.h b/tools/lib/api/fs/tracing_path.h index 0066f06cc381..1b65decedfc0 100644 --- a/tools/lib/api/fs/tracing_path.h +++ b/tools/lib/api/fs/tracing_path.h @@ -4,7 +4,6 @@ #include -extern char tracing_path[]; extern char tracing_events_path[]; void tracing_path_set(const char *mountpoint); diff --git a/tools/perf/perf.c b/tools/perf/perf.c index cd6ea55d4b0c..d5a0878de816 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -238,7 +238,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) (*argc)--; } else if (strstarts(cmd, CMD_DEBUGFS_DIR)) { tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR)); - fprintf(stderr, "dir: %s\n", tracing_path); + fprintf(stderr, "dir: %s\n", tracing_path_mount()); if (envchanged) *envchanged = 1; } else if (!strcmp(cmd, "--list-cmds")) { @@ -463,9 +463,6 @@ int main(int argc, const char **argv) return err; set_buildid_dir(NULL); - /* get debugfs/tracefs mount point from /proc/mounts */ - tracing_path_mount(); - /* * "perf-xxxx" is the same as "perf xxxx", but we obviously: * diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 4ae1123c6794..b76088fadf3d 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -84,8 +84,7 @@ int open_trace_file(const char *trace_file, bool readwrite) char buf[PATH_MAX]; int ret; - ret = e_snprintf(buf, PATH_MAX, "%s/%s", - tracing_path, trace_file); + ret = e_snprintf(buf, PATH_MAX, "%s/%s", tracing_path_mount(), trace_file); if (ret >= 0) { pr_debug("Opening %s write=%d\n", buf, readwrite); if (readwrite && !probe_event_dry_run) From 40c3c0c9ac2befd28df3844dc9efdbadee3af5c0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 16 May 2018 16:42:26 -0300 Subject: [PATCH 04/18] tools lib api fs tracing_path: Introduce get/put_events_file() helpers To make reading events files a tad more compact than with get_tracing_files("events/foo"). Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-do6xgtwpmfl8zjs1euxsd2du@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/tracing_path.c | 15 +++++++++++++++ tools/lib/api/fs/tracing_path.h | 5 +++++ tools/perf/util/trace-event-info.c | 11 +++++------ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c index 6f5fe942eff4..9cd282425929 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -86,6 +86,21 @@ void put_tracing_file(char *file) free(file); } +char *get_events_file(const char *name) +{ + char *file; + + if (asprintf(&file, "%s/events/%s", tracing_path_mount(), name) < 0) + return NULL; + + return file; +} + +void put_events_file(char *file) +{ + free(file); +} + int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name) { diff --git a/tools/lib/api/fs/tracing_path.h b/tools/lib/api/fs/tracing_path.h index 1b65decedfc0..3b32fb439f12 100644 --- a/tools/lib/api/fs/tracing_path.h +++ b/tools/lib/api/fs/tracing_path.h @@ -12,5 +12,10 @@ const char *tracing_path_mount(void); char *get_tracing_file(const char *name); void put_tracing_file(char *file); +char *get_events_file(const char *name); +void put_events_file(char *file); + +#define zput_events_file(ptr) ({ free(*ptr); *ptr = NULL; }) + int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name); #endif /* __API_FS_TRACING_PATH_H */ diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index d7f2113462fb..c85d0d1a65ed 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -103,11 +103,10 @@ static int record_file(const char *file, ssize_t hdr_sz) static int record_header_files(void) { - char *path; + char *path = get_events_file("header_page"); struct stat st; int err = -EIO; - path = get_tracing_file("events/header_page"); if (!path) { pr_debug("can't get tracing/events/header_page"); return -ENOMEM; @@ -128,9 +127,9 @@ static int record_header_files(void) goto out; } - put_tracing_file(path); + put_events_file(path); - path = get_tracing_file("events/header_event"); + path = get_events_file("header_event"); if (!path) { pr_debug("can't get tracing/events/header_event"); err = -ENOMEM; @@ -154,7 +153,7 @@ static int record_header_files(void) err = 0; out: - put_tracing_file(path); + put_events_file(path); return err; } @@ -243,7 +242,7 @@ static int record_ftrace_files(struct tracepoint_path *tps) char *path; int ret; - path = get_tracing_file("events/ftrace"); + path = get_events_file("ftrace"); if (!path) { pr_debug("can't get tracing/events/ftrace"); return -ENOMEM; From c02cab228e44aacf161642b63779971f8e39993b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 May 2018 14:22:37 -0300 Subject: [PATCH 05/18] perf tools: Reuse the path to the tracepoint /events/ directory When using for_each_event() we needlessly rebuild the whole path to the tracepoint directory, reuse the dir_path instead, saving some cycles and reducing the size of the next patch. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-54bcs15n0cp6gwcgpc4hptyc@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 2fc4ee8b86c1..f9d5bbd63484 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -156,13 +156,12 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { (strcmp(sys_dirent->d_name, ".")) && \ (strcmp(sys_dirent->d_name, ".."))) -static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) +static int tp_event_has_id(const char *dir_path, struct dirent *evt_dir) { char evt_path[MAXPATHLEN]; int fd; - snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, - sys_dir->d_name, evt_dir->d_name); + snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dir->d_name); fd = open(evt_path, O_RDONLY); if (fd < 0) return -EINVAL; @@ -171,12 +170,12 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) return 0; } -#define for_each_event(sys_dirent, evt_dir, evt_dirent) \ +#define for_each_event(dir_path, evt_dir, evt_dirent) \ while ((evt_dirent = readdir(evt_dir)) != NULL) \ if (evt_dirent->d_type == DT_DIR && \ (strcmp(evt_dirent->d_name, ".")) && \ (strcmp(evt_dirent->d_name, "..")) && \ - (!tp_event_has_id(sys_dirent, evt_dirent))) + (!tp_event_has_id(dir_path, evt_dirent))) #define MAX_EVENT_LENGTH 512 @@ -204,7 +203,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) if (!evt_dir) continue; - for_each_event(sys_dirent, evt_dir, evt_dirent) { + for_each_event(dir_path, evt_dir, evt_dirent) { scnprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, evt_dirent->d_name); @@ -2119,7 +2118,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, if (!evt_dir) continue; - for_each_event(sys_dirent, evt_dir, evt_dirent) { + for_each_event(dir_path, evt_dir, evt_dirent) { if (event_glob != NULL && !strglobmatch(evt_dirent->d_name, event_glob)) continue; @@ -2199,7 +2198,7 @@ int is_valid_tracepoint(const char *event_string) if (!evt_dir) continue; - for_each_event(sys_dirent, evt_dir, evt_dirent) { + for_each_event(dir_path, evt_dir, evt_dirent) { snprintf(evt_path, MAXPATHLEN, "%s:%s", sys_dirent->d_name, evt_dirent->d_name); if (!strcmp(evt_path, event_string)) { From 25a7d914274de38637c5199342eb90a297361386 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 May 2018 14:27:29 -0300 Subject: [PATCH 06/18] perf parse-events: Use get/put_events_file() Instead of accessing the trace_events_path variable directly, that may not have been properly initialized wrt detecting where tracefs is mounted. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-id7hzn1ydgkxbumeve5wapqz@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 7 +++-- tools/perf/util/parse-events.c | 50 ++++++++++++++++++++++----------- tools/perf/util/trace-event.c | 8 ++++-- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 6829dd416a99..6d57d7082637 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1328,7 +1328,7 @@ static int count_tracepoints(void) TEST_ASSERT_VAL("Can't open events dir", events_dir); while ((events_ent = readdir(events_dir))) { - char sys_path[PATH_MAX]; + char *sys_path; struct dirent *sys_ent; DIR *sys_dir; @@ -1339,8 +1339,8 @@ static int count_tracepoints(void) || !strcmp(events_ent->d_name, "header_page")) continue; - scnprintf(sys_path, PATH_MAX, "%s/%s", - tracing_events_path, events_ent->d_name); + sys_path = get_events_file(events_ent->d_name); + TEST_ASSERT_VAL("Can't get sys path", sys_path); sys_dir = opendir(sys_path); TEST_ASSERT_VAL("Can't open sys dir", sys_dir); @@ -1356,6 +1356,7 @@ static int count_tracepoints(void) } closedir(sys_dir); + put_events_file(sys_path); } closedir(events_dir); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index f9d5bbd63484..24668300b327 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -189,19 +189,19 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) int fd; u64 id; char evt_path[MAXPATHLEN]; - char dir_path[MAXPATHLEN]; + char *dir_path; sys_dir = opendir(tracing_events_path); if (!sys_dir) return NULL; for_each_subsystem(sys_dir, sys_dirent) { - - snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, - sys_dirent->d_name); + dir_path = get_events_file(sys_dirent->d_name); + if (!dir_path) + continue; evt_dir = opendir(dir_path); if (!evt_dir) - continue; + goto next; for_each_event(dir_path, evt_dir, evt_dirent) { @@ -217,6 +217,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) close(fd); id = atoll(id_buf); if (id == config) { + put_events_file(dir_path); closedir(evt_dir); closedir(sys_dir); path = zalloc(sizeof(*path)); @@ -241,6 +242,8 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) } } closedir(evt_dir); +next: + put_events_file(dir_path); } closedir(sys_dir); @@ -511,14 +514,19 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, struct parse_events_error *err, struct list_head *head_config) { - char evt_path[MAXPATHLEN]; + char *evt_path; struct dirent *evt_ent; DIR *evt_dir; int ret = 0, found = 0; - snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); + evt_path = get_events_file(sys_name); + if (!evt_path) { + tracepoint_error(err, errno, sys_name, evt_name); + return -1; + } evt_dir = opendir(evt_path); if (!evt_dir) { + put_events_file(evt_path); tracepoint_error(err, errno, sys_name, evt_name); return -1; } @@ -544,6 +552,7 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, ret = -1; } + put_events_file(evt_path); closedir(evt_dir); return ret; } @@ -2091,7 +2100,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, DIR *sys_dir, *evt_dir; struct dirent *sys_dirent, *evt_dirent; char evt_path[MAXPATHLEN]; - char dir_path[MAXPATHLEN]; + char *dir_path; char **evt_list = NULL; unsigned int evt_i = 0, evt_num = 0; bool evt_num_known = false; @@ -2112,11 +2121,12 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, !strglobmatch(sys_dirent->d_name, subsys_glob)) continue; - snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, - sys_dirent->d_name); + dir_path = get_events_file(sys_dirent->d_name); + if (!dir_path) + continue; evt_dir = opendir(dir_path); if (!evt_dir) - continue; + goto next; for_each_event(dir_path, evt_dir, evt_dirent) { if (event_glob != NULL && @@ -2132,11 +2142,15 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, sys_dirent->d_name, evt_dirent->d_name); evt_list[evt_i] = strdup(evt_path); - if (evt_list[evt_i] == NULL) + if (evt_list[evt_i] == NULL) { + put_events_file(dir_path); goto out_close_evt_dir; + } evt_i++; } closedir(evt_dir); +next: + put_events_file(dir_path); } closedir(sys_dir); @@ -2184,19 +2198,19 @@ int is_valid_tracepoint(const char *event_string) DIR *sys_dir, *evt_dir; struct dirent *sys_dirent, *evt_dirent; char evt_path[MAXPATHLEN]; - char dir_path[MAXPATHLEN]; + char *dir_path; sys_dir = opendir(tracing_events_path); if (!sys_dir) return 0; for_each_subsystem(sys_dir, sys_dirent) { - - snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, - sys_dirent->d_name); + dir_path = get_events_file(sys_dirent->d_name); + if (!dir_path) + continue; evt_dir = opendir(dir_path); if (!evt_dir) - continue; + goto next; for_each_event(dir_path, evt_dir, evt_dirent) { snprintf(evt_path, MAXPATHLEN, "%s:%s", @@ -2208,6 +2222,8 @@ int is_valid_tracepoint(const char *event_string) } } closedir(evt_dir); +next: + put_events_file(dir_path); } closedir(sys_dir); return 0; diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c index 16a776371d03..1aa368603268 100644 --- a/tools/perf/util/trace-event.c +++ b/tools/perf/util/trace-event.c @@ -75,6 +75,7 @@ void trace_event__cleanup(struct trace_event *t) static struct event_format* tp_format(const char *sys, const char *name) { + char *tp_dir = get_events_file(sys); struct pevent *pevent = tevent.pevent; struct event_format *event = NULL; char path[PATH_MAX]; @@ -82,8 +83,11 @@ tp_format(const char *sys, const char *name) char *data; int err; - scnprintf(path, PATH_MAX, "%s/%s/%s/format", - tracing_events_path, sys, name); + if (!tp_dir) + return ERR_PTR(-errno); + + scnprintf(path, PATH_MAX, "%s/%s/format", tp_dir, name); + put_events_file(tp_dir); err = filename__read_str(path, &data, &size); if (err) From 7014e0e3bf9b0d0b6221eb7d2f8a1f690423dd73 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 May 2018 14:42:39 -0300 Subject: [PATCH 07/18] tools lib api fs tracing_path: Introduce opendir() method That takes care of using the right call to get the tracing_path directory, the one that will end up calling tracing_path_set() to figure out where tracefs is mounted. One more step in doing just lazy reading of system structures to reduce the number of operations done unconditionaly at 'perf' start. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-42zzi0f274909bg9mxzl81bu@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/tracing_path.c | 13 +++++++++++++ tools/lib/api/fs/tracing_path.h | 3 +++ tools/perf/tests/parse-events.c | 2 +- tools/perf/util/parse-events.c | 8 ++++---- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c index 9cd282425929..9b451af0721c 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -101,6 +101,19 @@ void put_events_file(char *file) free(file); } +DIR *tracing_events__opendir(void) +{ + DIR *dir = NULL; + char *path = get_tracing_file("events"); + + if (path) { + dir = opendir(path); + put_events_file(path); + } + + return dir; +} + int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name) { diff --git a/tools/lib/api/fs/tracing_path.h b/tools/lib/api/fs/tracing_path.h index 3b32fb439f12..904d085b2ae7 100644 --- a/tools/lib/api/fs/tracing_path.h +++ b/tools/lib/api/fs/tracing_path.h @@ -3,9 +3,12 @@ #define __API_FS_TRACING_PATH_H #include +#include extern char tracing_events_path[]; +DIR *tracing_events__opendir(void); + void tracing_path_set(const char *mountpoint); const char *tracing_path_mount(void); diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 6d57d7082637..b9ebe15afb13 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1323,7 +1323,7 @@ static int count_tracepoints(void) DIR *events_dir; int cnt = 0; - events_dir = opendir(tracing_events_path); + events_dir = tracing_events__opendir(); TEST_ASSERT_VAL("Can't open events dir", events_dir); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 24668300b327..15eec49e71a1 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -191,7 +191,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) char evt_path[MAXPATHLEN]; char *dir_path; - sys_dir = opendir(tracing_events_path); + sys_dir = tracing_events__opendir(); if (!sys_dir) return NULL; @@ -578,7 +578,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, DIR *events_dir; int ret = 0; - events_dir = opendir(tracing_events_path); + events_dir = tracing_events__opendir(); if (!events_dir) { tracepoint_error(err, errno, sys_name, evt_name); return -1; @@ -2106,7 +2106,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, bool evt_num_known = false; restart: - sys_dir = opendir(tracing_events_path); + sys_dir = tracing_events__opendir(); if (!sys_dir) return; @@ -2200,7 +2200,7 @@ int is_valid_tracepoint(const char *event_string) char evt_path[MAXPATHLEN]; char *dir_path; - sys_dir = opendir(tracing_events_path); + sys_dir = tracing_events__opendir(); if (!sys_dir) return 0; From 789e465058352122023e4fa7de8dcf5c513e0b0b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 May 2018 14:51:23 -0300 Subject: [PATCH 08/18] tools lib api fs tracing_path: Make tracing_events_path private Not anymore accessed outside this library, keep it private. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-wg1m07flfrg1rm06jjzie8si@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/tracing_path.c | 3 +-- tools/lib/api/fs/tracing_path.h | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c index 9b451af0721c..120037496f77 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -15,8 +15,7 @@ static char tracing_mnt[PATH_MAX] = "/sys/kernel/debug"; static char tracing_path[PATH_MAX] = "/sys/kernel/debug/tracing"; -char tracing_events_path[PATH_MAX] = "/sys/kernel/debug/tracing/events"; - +static char tracing_events_path[PATH_MAX] = "/sys/kernel/debug/tracing/events"; static void __tracing_path_set(const char *tracing, const char *mountpoint) { diff --git a/tools/lib/api/fs/tracing_path.h b/tools/lib/api/fs/tracing_path.h index 904d085b2ae7..a19136b086dc 100644 --- a/tools/lib/api/fs/tracing_path.h +++ b/tools/lib/api/fs/tracing_path.h @@ -5,8 +5,6 @@ #include #include -extern char tracing_events_path[]; - DIR *tracing_events__opendir(void); void tracing_path_set(const char *mountpoint); From 6e1690c4c0b540930f08295b6a95c8660b257745 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 May 2018 15:12:36 -0300 Subject: [PATCH 09/18] tools include compiler-gcc: Add __pure attribute helper Adopt it from the kernel sources, will be used soon. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-oubheiqj8edo5rzewt11cbn0@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/compiler-gcc.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h index a3a4427441bf..70fe61295733 100644 --- a/tools/include/linux/compiler-gcc.h +++ b/tools/include/linux/compiler-gcc.h @@ -21,6 +21,9 @@ /* &a[0] degrades to a pointer: a different type from an array */ #define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) +#ifndef __pure +#define __pure __attribute__((pure)) +#endif #define noinline __attribute__((noinline)) #ifndef __packed #define __packed __attribute__((packed)) From 9ac94e31ca8c6311ec9eb68aea513e39ad809013 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 May 2018 15:03:05 -0300 Subject: [PATCH 10/18] perf tools: Read the cache line size lazily It is not read as commonly as 'page_size', so it makes sense to read it lazily, caching its value when it is first read. Less files open unconditionally at startup. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-35xhrq91u94uc1djtclek1ie@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/perf.c | 11 ----------- tools/perf/util/sort.c | 4 ++-- tools/perf/util/sort.h | 4 ++-- tools/perf/util/util.c | 21 ++++++++++++++++++++- tools/perf/util/util.h | 2 +- 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index d5a0878de816..cefd8f74630c 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -421,16 +421,6 @@ void pthread__unblock_sigwinch(void) pthread_sigmask(SIG_UNBLOCK, &set, NULL); } -#ifdef _SC_LEVEL1_DCACHE_LINESIZE -#define cache_line_size(cacheline_sizep) *cacheline_sizep = sysconf(_SC_LEVEL1_DCACHE_LINESIZE) -#else -static void cache_line_size(int *cacheline_sizep) -{ - if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep)) - pr_debug("cannot determine cache line size"); -} -#endif - int main(int argc, const char **argv) { int err; @@ -444,7 +434,6 @@ int main(int argc, const char **argv) /* The page_size is placed in util object. */ page_size = sysconf(_SC_PAGE_SIZE); - cache_line_size(&cacheline_size); if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0) sysctl_perf_event_max_stack = value; diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index e65903a695a6..4058ade352a5 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -2582,7 +2582,7 @@ int sort_dimension__add(struct perf_hpp_list *list, const char *tok, if (sort__mode != SORT_MODE__MEMORY) return -EINVAL; - if (sd->entry == &sort_mem_dcacheline && cacheline_size == 0) + if (sd->entry == &sort_mem_dcacheline && cacheline_size() == 0) return -EINVAL; if (sd->entry == &sort_mem_daddr_sym) @@ -2628,7 +2628,7 @@ static int setup_sort_list(struct perf_hpp_list *list, char *str, if (*tok) { ret = sort_dimension__add(list, tok, evlist, level); if (ret == -EINVAL) { - if (!cacheline_size && !strncasecmp(tok, "dcacheline", strlen(tok))) + if (!cacheline_size() && !strncasecmp(tok, "dcacheline", strlen(tok))) pr_err("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); else pr_err("Invalid --sort key: `%s'", tok); diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 035b62e2c60b..9e6896293bbd 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -186,13 +186,13 @@ static inline float hist_entry__get_percent_limit(struct hist_entry *he) static inline u64 cl_address(u64 address) { /* return the cacheline of the address */ - return (address & ~(cacheline_size - 1)); + return (address & ~(cacheline_size() - 1)); } static inline u64 cl_offset(u64 address) { /* return the cacheline of the address */ - return (address & (cacheline_size - 1)); + return (address & (cacheline_size() - 1)); } enum sort_mode { diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 1019bbc5dbd8..99ab52165680 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -38,7 +38,26 @@ void perf_set_multithreaded(void) } unsigned int page_size; -int cacheline_size; + +#ifdef _SC_LEVEL1_DCACHE_LINESIZE +#define cache_line_size(cacheline_sizep) *cacheline_sizep = sysconf(_SC_LEVEL1_DCACHE_LINESIZE) +#else +static void cache_line_size(int *cacheline_sizep) +{ + if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep)) + pr_debug("cannot determine cache line size"); +} +#endif + +int cacheline_size(void) +{ + static int size; + + if (!size) + cache_line_size(&size); + + return size; +} int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index c9626c206208..74d21dfe0d29 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -43,7 +43,7 @@ size_t hex_width(u64 v); int hex2u64(const char *ptr, u64 *val); extern unsigned int page_size; -extern int cacheline_size; +int __pure cacheline_size(void); int fetch_kernel_version(unsigned int *puint, char *str, size_t str_sz); From 029c75e5cf166f9c04744d81c798f54a44a8417c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 May 2018 16:31:32 -0300 Subject: [PATCH 11/18] perf tools: No need to unconditionally read the max_stack sysctls Let tools that need to have those variables with the sysctl current values use a function that will read them. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-1ljj3oeo5kpt2n1icfd9vowe@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- tools/perf/builtin-trace.c | 2 +- tools/perf/perf.c | 7 ------- tools/perf/util/evsel.c | 2 +- tools/perf/util/util.c | 13 +++++++++++++ tools/perf/util/util.h | 2 ++ 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 3c061c57afb6..7a349fcd3864 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1264,7 +1264,7 @@ int cmd_top(int argc, const char **argv) .proc_map_timeout = 500, .overwrite = 1, }, - .max_stack = sysctl_perf_event_max_stack, + .max_stack = sysctl__max_stack(), .sym_pcnt_filter = 5, .nr_threads_synthesize = UINT_MAX, }; diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index c7effcfc40ed..560aed7da36a 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -3162,7 +3162,7 @@ int cmd_trace(int argc, const char **argv) mmap_pages_user_set = false; if (trace.max_stack == UINT_MAX) { - trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack; + trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl__max_stack(); max_stack_user_set = false; } diff --git a/tools/perf/perf.c b/tools/perf/perf.c index cefd8f74630c..51c81509a315 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -426,7 +426,6 @@ int main(int argc, const char **argv) int err; const char *cmd; char sbuf[STRERR_BUFSIZE]; - int value; /* libsubcmd init */ exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT); @@ -435,12 +434,6 @@ int main(int argc, const char **argv) /* The page_size is placed in util object. */ page_size = sysconf(_SC_PAGE_SIZE); - if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0) - sysctl_perf_event_max_stack = value; - - if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0) - sysctl_perf_event_max_contexts_per_stack = value; - cmd = extract_argv0_path(argv[0]); if (!cmd) cmd = "perf-help"; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 4cd2cf93f726..150db5ed7400 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2862,7 +2862,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, return scnprintf(msg, size, "Not enough memory to setup event with callchain.\n" "Hint: Try tweaking /proc/sys/kernel/perf_event_max_stack\n" - "Hint: Current value: %d", sysctl_perf_event_max_stack); + "Hint: Current value: %d", sysctl__max_stack()); break; case ENODEV: if (target->cpu_list) diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 99ab52165680..eac5b858a371 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -62,6 +62,19 @@ int cacheline_size(void) int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK; +int sysctl__max_stack(void) +{ + int value; + + if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0) + sysctl_perf_event_max_stack = value; + + if (sysctl__read_int("kernel/perf_event_max_contexts_per_stack", &value) == 0) + sysctl_perf_event_max_contexts_per_stack = value; + + return sysctl_perf_event_max_stack; +} + bool test_attr__enabled; bool perf_host = true; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 74d21dfe0d29..dc58254a2b69 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -45,6 +45,8 @@ int hex2u64(const char *ptr, u64 *val); extern unsigned int page_size; int __pure cacheline_size(void); +int sysctl__max_stack(void); + int fetch_kernel_version(unsigned int *puint, char *str, size_t str_sz); #define KVER_VERSION(x) (((x) >> 16) & 0xff) From 19610184693c547b4c12738df4156589892c4018 Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Thu, 17 May 2018 12:03:25 +0530 Subject: [PATCH 12/18] perf script: Show virtual addresses instead of offsets When perf data is recorded with the call-graph option enabled, the callchain shown by perf script shows the binary offsets of the symbols as the ip. This is incorrect for kernel symbols as the ip values are always off by a fixed offset depending on the architecture. If the offsets from the start of the symbols are printed, they are also incorrect for both kernel and userspace symbols. Without the call-graph option, the callchain shows the virtual addresses of the symbols rather than their binary offsets. The offsets printed in this case are also correct. This fixes the inconsistency in perf script's output. This can be verified on a powerpc64le system running Fedora 27 as follows: # cat /proc/kallsyms | grep sys_write ... c0000000004025a0 T sys_write c0000000004025a0 T __se_sys_write ... # perf probe -a sys_write Before applying this patch: # perf record -e probe:sys_write -g ~/test # perf script -F ip,sym,symoff 4125b0 sys_write+0x8000000000008010 1b9e0 system_call+0x8000000000008058 118234 __GI___libc_write+0xffff0000f52c0024 92c74 _IO_file_write@@GLIBC_2.17+0xffff0000f52c0044 5afbfd8a [unknown] 91a60 new_do_write+0xffff0000f52c0090 94638 _IO_do_write@@GLIBC_2.17+0xffff0000f52c0038 94bbc _IO_file_overflow@@GLIBC_2.17+0xffff0000f52c014c 95a24 __overflow+0xffff0000f52c0064 84548 _IO_puts+0xffff0000f52c0218 440 main+0xffffffffe0000020 236a0 generic_start_main.isra.0+0xffff0000f52c0140 23898 __libc_start_main+0xffff0000f52c00b8 0 [unknown] ... # perf record -e probe:sys_write ~/test # perf script -F ip,sym,symoff c0000000004025b0 sys_write+0x10 ... After applying this patch: # perf record -e probe:sys_write -g ~/test # perf script -F ip,sym,symoff c0000000004025b0 sys_write+0x10 c00000000000b9e0 system_call+0x58 7fffb70d8234 __GI___libc_write+0x24 7fffb7052c74 _IO_file_write@@GLIBC_2.17+0x44 5afc1818 [unknown] 7fffb7051a60 new_do_write+0x90 7fffb7054638 _IO_do_write@@GLIBC_2.17+0x38 7fffb7054bbc _IO_file_overflow@@GLIBC_2.17+0x14c 7fffb7055a24 __overflow+0x64 7fffb7044548 _IO_puts+0x218 10000440 main+0x20 7fffb6fe36a0 generic_start_main.isra.0+0x140 7fffb6fe3898 __libc_start_main+0xb8 0 [unknown] ... # perf record -e probe:sys_write ~/test # perf script -F ip,sym,symoff c0000000004025b0 sys_write+0x10 ... Signed-off-by: Sandipan Das Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Naveen N. Rao Cc: Ravi Bangoria Link: http://lkml.kernel.org/r/20180517063326.6319-1-sandipan@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 72a351613d85..7c777cb32806 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1764,7 +1764,7 @@ static int add_callchain_ip(struct thread *thread, } srcline = callchain_srcline(al.map, al.sym, al.addr); - return callchain_cursor_append(cursor, al.addr, al.map, al.sym, + return callchain_cursor_append(cursor, ip, al.map, al.sym, branch, flags, nr_loop_iter, iter_cycles, branch_from, srcline); } From 7903a70867230d9edbd5e886cd8b8a2b248f418f Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Thu, 17 May 2018 12:03:26 +0530 Subject: [PATCH 13/18] perf script: Show symbol offsets by default Since the ip shown for a symbol is now always a virtual address, it becomes difficult to correlate this with objdump output and determine the exact instruction address. So, we always show the offset from the start of the symbol. This can be verified on a powerpc64le system running Fedora 27 as follows: # perf probe -a sys_write # perf record -e probe:sys_write -g ~/test Before applying this patch: # perf script test 9710 [013] 95614.332431: probe:sys_write: (c0000000004025b0) c0000000004025b0 sys_write (/lib/modules/4.17.0-rc4+/build/vmlinux) c00000000000b9e0 system_call (/lib/modules/4.17.0-rc4+/build/vmlinux) 7fffb70d8234 __GI___libc_write (/usr/lib64/libc-2.26.so) 7fffb7052c74 _IO_file_write@@GLIBC_2.17 (/usr/lib64/libc-2.26.so) 5afc1818 [unknown] ([unknown]) 7fffb7051a60 new_do_write (/usr/lib64/libc-2.26.so) 7fffb7054638 _IO_do_write@@GLIBC_2.17 (/usr/lib64/libc-2.26.so) 7fffb7054bbc _IO_file_overflow@@GLIBC_2.17 (/usr/lib64/libc-2.26.so) 7fffb7055a24 __overflow (/usr/lib64/libc-2.26.so) 7fffb7044548 _IO_puts (/usr/lib64/libc-2.26.so) 10000440 main (/home/sandipan/test) 7fffb6fe36a0 generic_start_main.isra.0 (/usr/lib64/libc-2.26.so) 7fffb6fe3898 __libc_start_main (/usr/lib64/libc-2.26.so) 0 [unknown] ([unknown]) ... After applying this patch: # perf script test 9710 [013] 95614.332431: probe:sys_write: (c0000000004025b0) c0000000004025b0 sys_write+0x10 (/lib/modules/4.17.0-rc4+/build/vmlinux) c00000000000b9e0 system_call+0x58 (/lib/modules/4.17.0-rc4+/build/vmlinux) 7fffb70d8234 __GI___libc_write+0x24 (/usr/lib64/libc-2.26.so) 7fffb7052c74 _IO_file_write@@GLIBC_2.17+0x44 (/usr/lib64/libc-2.26.so) 5afc1818 [unknown] ([unknown]) 7fffb7051a60 new_do_write+0x90 (/usr/lib64/libc-2.26.so) 7fffb7054638 _IO_do_write@@GLIBC_2.17+0x38 (/usr/lib64/libc-2.26.so) 7fffb7054bbc _IO_file_overflow@@GLIBC_2.17+0x14c (/usr/lib64/libc-2.26.so) 7fffb7055a24 __overflow+0x64 (/usr/lib64/libc-2.26.so) 7fffb7044548 _IO_puts+0x218 (/usr/lib64/libc-2.26.so) 10000440 main+0x20 (/home/sandipan/test) 7fffb6fe36a0 generic_start_main.isra.0+0x140 (/usr/lib64/libc-2.26.so) 7fffb6fe3898 __libc_start_main+0xb8 (/usr/lib64/libc-2.26.so) 0 [unknown] ([unknown]) ... Signed-off-by: Sandipan Das Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Naveen N. Rao Cc: Ravi Bangoria Link: http://lkml.kernel.org/r/20180517063326.6319-2-sandipan@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 26 ++++++++++--------- .../shell/record+probe_libc_inet_pton.sh | 12 ++++----- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index fa2c7a288750..cefc8813e91e 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -153,8 +153,8 @@ static struct { .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | - PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | - PERF_OUTPUT_PERIOD, + PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET | + PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD, .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, }, @@ -165,8 +165,9 @@ static struct { .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | - PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | - PERF_OUTPUT_PERIOD | PERF_OUTPUT_BPF_OUTPUT, + PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET | + PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD | + PERF_OUTPUT_BPF_OUTPUT, .invalid_fields = PERF_OUTPUT_TRACE, }, @@ -185,10 +186,10 @@ static struct { .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | - PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | - PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR | - PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT | - PERF_OUTPUT_PHYS_ADDR, + PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET | + PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD | + PERF_OUTPUT_ADDR | PERF_OUTPUT_DATA_SRC | + PERF_OUTPUT_WEIGHT | PERF_OUTPUT_PHYS_ADDR, .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, }, @@ -199,8 +200,8 @@ static struct { .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | - PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | - PERF_OUTPUT_PERIOD, + PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET | + PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD, .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, }, @@ -211,8 +212,8 @@ static struct { .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | - PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | - PERF_OUTPUT_SYNTH, + PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET | + PERF_OUTPUT_DSO | PERF_OUTPUT_SYNTH, .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, }, @@ -544,6 +545,7 @@ static int perf_session__check_output_opt(struct perf_session *session) if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) { output[j].fields |= PERF_OUTPUT_IP; output[j].fields |= PERF_OUTPUT_SYM; + output[j].fields |= PERF_OUTPUT_SYMOFFSET; output[j].fields |= PERF_OUTPUT_DSO; set_print_ip_opts(attr); goto out; diff --git a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh index ee86473643be..650b208f700f 100755 --- a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh +++ b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh @@ -16,18 +16,18 @@ nm -g $libc 2>/dev/null | fgrep -q inet_pton || exit 254 trace_libc_inet_pton_backtrace() { idx=0 expected[0]="ping[][0-9 \.:]+probe_libc:inet_pton: \([[:xdigit:]]+\)" - expected[1]=".*inet_pton[[:space:]]\($libc|inlined\)$" + expected[1]=".*inet_pton\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" case "$(uname -m)" in s390x) eventattr='call-graph=dwarf,max-stack=4' - expected[2]="gaih_inet.*[[:space:]]\($libc|inlined\)$" - expected[3]="(__GI_)?getaddrinfo[[:space:]]\($libc|inlined\)$" - expected[4]="main[[:space:]]\(.*/bin/ping.*\)$" + expected[2]="gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" + expected[3]="(__GI_)?getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc|inlined\)$" + expected[4]="main\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$" ;; *) eventattr='max-stack=3' - expected[2]="getaddrinfo[[:space:]]\($libc\)$" - expected[3]=".*\(.*/bin/ping.*\)$" + expected[2]="getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" + expected[3]=".*\+0x[[:xdigit:]]+[[:space:]]\(.*/bin/ping.*\)$" ;; esac From 48659ebf37e5d9d23bda6dbf032bdbe9708929f1 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 17 May 2018 22:58:37 +0800 Subject: [PATCH 14/18] perf annotate: Record the min/max cycles Currently perf has a feature to account cycles for LBRs For example, on skylake: perf record -b ... perf report or perf annotate And then browsing the annotate browser gives average cycle counts for program blocks. For some analysis it would be useful if we could know not only the average cycles but also the min and max cycles. This patch records the min and max cycles. Signed-off-by: Jin Yao Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1526569118-14217-2-git-send-email-yao.jin@linux.intel.com [ Switch from max/min to min/max ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 14 +++++++++++++- tools/perf/util/annotate.h | 4 ++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 5d74a30fe00f..4fcfefea3bc2 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -760,6 +760,15 @@ static int __symbol__account_cycles(struct annotation *notes, ch[offset].num_aggr++; ch[offset].cycles_aggr += cycles; + if (cycles > ch[offset].cycles_max) + ch[offset].cycles_max = cycles; + + if (ch[offset].cycles_min) { + if (cycles && cycles < ch[offset].cycles_min) + ch[offset].cycles_min = cycles; + } else + ch[offset].cycles_min = cycles; + if (!have_start && ch[offset].have_start) return 0; if (ch[offset].num) { @@ -953,8 +962,11 @@ void annotation__compute_ipc(struct annotation *notes, size_t size) if (ch->have_start) annotation__count_and_fill(notes, ch->start, offset, ch); al = notes->offsets[offset]; - if (al && ch->num_aggr) + if (al && ch->num_aggr) { al->cycles = ch->cycles_aggr / ch->num_aggr; + al->cycles_max = ch->cycles_max; + al->cycles_min = ch->cycles_min; + } notes->have_cycles = true; } } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index f28a9e43421d..d50363d56f73 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -105,6 +105,8 @@ struct annotation_line { int jump_sources; float ipc; u64 cycles; + u64 cycles_max; + u64 cycles_min; size_t privsize; char *path; u32 idx; @@ -186,6 +188,8 @@ struct cyc_hist { u64 start; u64 cycles; u64 cycles_aggr; + u64 cycles_max; + u64 cycles_min; u32 num; u32 num_aggr; u8 have_start; From 3e71fc0319775723adc08991ba7fbaeff1150347 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Thu, 17 May 2018 22:58:38 +0800 Subject: [PATCH 15/18] perf annotate: Create hotkey 'c' to show min/max cycles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the 'perf annotate' view, a new hotkey 'c' is created for showing the min/max cycles. For example, when press 'c', the annotate view is: Percent│ IPC Cycle(min/max) │ │ │ Disassembly of section .text: │ │ 000000000003aab0 : 8.22 │3.92 sub $0x18,%rsp │3.92 mov $0x1,%esi │3.92 xor %eax,%eax │3.92 cmpl $0x0,argp_program_version_hook@@G │3.92 1(2/1) ↓ je 20 │ lock cmpxchg %esi,__abort_msg@@GLIBC_P │ ↓ jne 29 │ ↓ jmp 43 │1.10 20: cmpxchg %esi,__abort_msg@@GLIBC_PRIVATE+ 8.93 │1.10 1(5/1) ↓ je 43 When press 'c' again, the annotate view is switched back: Percent│ IPC Cycle │ │ │ Disassembly of section .text: │ │ 000000000003aab0 : 8.22 │3.92 sub $0x18,%rsp │3.92 mov $0x1,%esi │3.92 xor %eax,%eax │3.92 cmpl $0x0,argp_program_version_hook@@GLIBC_2.2.5+0x │3.92 1 ↓ je 20 │ lock cmpxchg %esi,__abort_msg@@GLIBC_PRIVATE+0x8a0 │ ↓ jne 29 │ ↓ jmp 43 │1.10 20: cmpxchg %esi,__abort_msg@@GLIBC_PRIVATE+0x8a0 8.93 │1.10 1 ↓ je 43 Signed-off-by: Jin Yao Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1526569118-14217-3-git-send-email-yao.jin@linux.intel.com [ Rename all maxmin to minmax ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 8 +++++++ tools/perf/util/annotate.c | 37 ++++++++++++++++++++++++++----- tools/perf/util/annotate.h | 7 +++++- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 3781d74088a7..8be40fa903aa 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -695,6 +695,7 @@ static int annotate_browser__run(struct annotate_browser *browser, "O Bump offset level (jump targets -> +call -> all -> cycle thru)\n" "s Toggle source code view\n" "t Circulate percent, total period, samples view\n" + "c Show min/max cycle\n" "/ Search string\n" "k Toggle line numbers\n" "P Print to [symbol_name].annotation file.\n" @@ -791,6 +792,13 @@ static int annotate_browser__run(struct annotate_browser *browser, notes->options->show_total_period = true; annotation__update_column_widths(notes); continue; + case 'c': + if (notes->options->show_minmax_cycle) + notes->options->show_minmax_cycle = false; + else + notes->options->show_minmax_cycle = true; + annotation__update_column_widths(notes); + continue; case K_LEFT: case K_ESC: case 'q': diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 4fcfefea3bc2..6612c7f90af4 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2498,13 +2498,38 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati else obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC"); - if (al->cycles) - obj__printf(obj, "%*" PRIu64 " ", + if (!notes->options->show_minmax_cycle) { + if (al->cycles) + obj__printf(obj, "%*" PRIu64 " ", ANNOTATION__CYCLES_WIDTH - 1, al->cycles); - else if (!show_title) - obj__printf(obj, "%*s", ANNOTATION__CYCLES_WIDTH, " "); - else - obj__printf(obj, "%*s ", ANNOTATION__CYCLES_WIDTH - 1, "Cycle"); + else if (!show_title) + obj__printf(obj, "%*s", + ANNOTATION__CYCLES_WIDTH, " "); + else + obj__printf(obj, "%*s ", + ANNOTATION__CYCLES_WIDTH - 1, + "Cycle"); + } else { + if (al->cycles) { + char str[32]; + + scnprintf(str, sizeof(str), + "%" PRIu64 "(%" PRIu64 "/%" PRIu64 ")", + al->cycles, al->cycles_min, + al->cycles_max); + + obj__printf(obj, "%*s ", + ANNOTATION__MINMAX_CYCLES_WIDTH - 1, + str); + } else if (!show_title) + obj__printf(obj, "%*s", + ANNOTATION__MINMAX_CYCLES_WIDTH, + " "); + else + obj__printf(obj, "%*s ", + ANNOTATION__MINMAX_CYCLES_WIDTH - 1, + "Cycle(min/max)"); + } } obj__printf(obj, " "); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index d50363d56f73..5080b6dd98b8 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -61,6 +61,7 @@ bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); #define ANNOTATION__IPC_WIDTH 6 #define ANNOTATION__CYCLES_WIDTH 6 +#define ANNOTATION__MINMAX_CYCLES_WIDTH 19 struct annotation_options { bool hide_src_code, @@ -69,7 +70,8 @@ struct annotation_options { show_linenr, show_nr_jumps, show_nr_samples, - show_total_period; + show_total_period, + show_minmax_cycle; u8 offset_level; }; @@ -243,6 +245,9 @@ struct annotation { static inline int annotation__cycles_width(struct annotation *notes) { + if (notes->have_cycles && notes->options->show_minmax_cycle) + return ANNOTATION__IPC_WIDTH + ANNOTATION__MINMAX_CYCLES_WIDTH; + return notes->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0; } From cfc4033be77abcf5953bed2fd201100515fcb357 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 17 May 2018 17:22:22 -0300 Subject: [PATCH 16/18] perf bpf: Fixup include and examples install messages Before: INSTALL lib install include/bpf/*.h '/home/acme/lib/include/perf/bpf' INSTALL lib install examples/bpf/*.c '/home/acme/lib/examples/perf/bpf' After: INSTALL lib INSTALL include/bpf INSTALL lib INSTALL examples/bpf Reported-by: Ingo Molnar Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Fixes: dd8e4ead6e98 ("perf bpf: Add bpf.h to be used in eBPF proggies") Fixes: 8f12a2ff00e5 ("perf bpf: Add 'examples' directories") Link: https://lkml.kernel.org/n/tip-icljqe87e8pak8mu6mkki9d4@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index c63a3971d719..ecc9fc952655 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -770,9 +770,11 @@ endif ifndef NO_LIBBPF $(call QUIET_INSTALL, lib) \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf' + $(call QUIET_INSTALL, include/bpf) \ $(INSTALL) include/bpf/*.h '$(DESTDIR_SQ)$(perf_include_instdir_SQ)/bpf' $(call QUIET_INSTALL, lib) \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf' + $(call QUIET_INSTALL, examples/bpf) \ $(INSTALL) examples/bpf/*.c '$(DESTDIR_SQ)$(perf_examples_instdir_SQ)/bpf' endif $(call QUIET_INSTALL, perf-archive) \ From dbbd34a666ee117d0e39e71a47f38f02c4a5c698 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 17 May 2018 12:21:53 +0300 Subject: [PATCH 17/18] perf machine: Add machine__is() to identify machine arch Add a function to identify the machine architecture. Signed-off-by: Adrian Hunter Tested-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Andy Lutomirski Cc: Dave Hansen Cc: H. Peter Anvin Cc: Joerg Roedel Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: x86@kernel.org Link: http://lkml.kernel.org/r/1526548928-20790-6-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/env.c | 18 ++++++++++++++++++ tools/perf/util/env.h | 2 ++ tools/perf/util/machine.c | 9 +++++++++ tools/perf/util/machine.h | 2 ++ 4 files changed, 31 insertions(+) diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 4c842762e3f2..319fb0a0d05e 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -93,6 +93,24 @@ int perf_env__read_cpu_topology_map(struct perf_env *env) return 0; } +static int perf_env__read_arch(struct perf_env *env) +{ + struct utsname uts; + + if (env->arch) + return 0; + + if (!uname(&uts)) + env->arch = strdup(uts.machine); + + return env->arch ? 0 : -ENOMEM; +} + +const char *perf_env__raw_arch(struct perf_env *env) +{ + return env && !perf_env__read_arch(env) ? env->arch : "unknown"; +} + void cpu_cache_level__free(struct cpu_cache_level *cache) { free(cache->type); diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index c4ef2e523367..62e193948608 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -76,4 +76,6 @@ int perf_env__read_cpu_topology_map(struct perf_env *env); void cpu_cache_level__free(struct cpu_cache_level *cache); const char *perf_env__arch(struct perf_env *env); +const char *perf_env__raw_arch(struct perf_env *env); + #endif /* __PERF_ENV_H */ diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 7c777cb32806..107bae7676b1 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -2296,6 +2296,15 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, return 0; } +/* + * Compares the raw arch string. N.B. see instead perf_env__arch() if a + * normalized arch is needed. + */ +bool machine__is(struct machine *machine, const char *arch) +{ + return machine && !strcmp(perf_env__raw_arch(machine->env), arch); +} + int machine__get_kernel_start(struct machine *machine) { struct map *map = machine__kernel_map(machine); diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 388fb4741c54..b31d33b5aa2a 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -188,6 +188,8 @@ static inline bool machine__is_host(struct machine *machine) return machine ? machine->pid == HOST_KERNEL_ID : false; } +bool machine__is(struct machine *machine, const char *arch); + struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid); struct thread *machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid); From 19422a9f2a3be7f3a046285ffae4cbb571aa853a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 17 May 2018 12:21:54 +0300 Subject: [PATCH 18/18] perf tools: Fix kernel_start for PTI on x86 Opickn x86_64, PTI entry trampolines are less than the start of kernel text, but still above 2^63. So leave kernel_start = 1ULL << 63 for x86_64. Signed-off-by: Adrian Hunter Tested-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: Andy Lutomirski Cc: Dave Hansen Cc: H. Peter Anvin Cc: Joerg Roedel Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: x86@kernel.org Link: http://lkml.kernel.org/r/1526548928-20790-7-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 107bae7676b1..e011a7160380 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -2321,7 +2321,12 @@ int machine__get_kernel_start(struct machine *machine) machine->kernel_start = 1ULL << 63; if (map) { err = map__load(map); - if (!err) + /* + * On x86_64, PTI entry trampolines are less than the + * start of kernel text, but still above 2^63. So leave + * kernel_start = 1ULL << 63 for x86_64. + */ + if (!err && !machine__is(machine, "x86_64")) machine->kernel_start = map->start; } return err;