From bd315aab8a3ab1bc7074774b89a5d8ec7c1ff7ab Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Mon, 14 Sep 2015 10:23:55 +0000 Subject: [PATCH 01/15] perf top: Fix segfault pressing -> with no hist entries 'perf top' segfaults with following operation: # perf top -e page-faults -p 11400 # 11400 never generates page-fault Then on the resulting empty interface, press right key: # ./perf top -e page-faults -p 11400 perf: Segmentation fault -------- backtrace -------- ./perf[0x535428] /lib64/libc.so.6(+0x3545f)[0x7f0dd360745f] ./perf[0x531d46] ./perf(perf_evlist__tui_browse_hists+0x96)[0x5340d6] ./perf[0x44ba2f] /lib64/libpthread.so.0(+0x81d0)[0x7f0dd49dc1d0] /lib64/libc.so.6(clone+0x6c)[0x7f0dd36b90dc] The bug resides in perf_evsel__hists_browse() that, in the above circumstance browser->selection can be NULL, but code after skip_annotation doesn't consider it. This patch fix it by checking browser->selection before fetching browser->selection->map. Signed-off-by: Wang Nan Tested-by: Arnaldo Carvalho de Melo Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1442226235-117265-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index cf86f2d3a5e7..c04c60d4863c 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1968,7 +1968,8 @@ skip_annotation: &options[nr_options], dso); nr_options += add_map_opt(browser, &actions[nr_options], &options[nr_options], - browser->selection->map); + browser->selection ? + browser->selection->map : NULL); /* perf script support */ if (browser->he_selection) { @@ -1976,6 +1977,15 @@ skip_annotation: &actions[nr_options], &options[nr_options], thread, NULL); + /* + * Note that browser->selection != NULL + * when browser->he_selection is not NULL, + * so we don't need to check browser->selection + * before fetching browser->selection->sym like what + * we do before fetching browser->selection->map. + * + * See hist_browser__show_entry. + */ nr_options += add_script_opt(browser, &actions[nr_options], &options[nr_options], From a69b09e2342a9c144b0291b9aeb849ab7d5843bf Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:58:49 +0300 Subject: [PATCH 02/15] perf evlist: Simplify propagate_maps() logic If evsel->cpus is to be reassigned then the current value must be "put", which works even if it is NULL. Simplify the current logic by moving the "put" next to the assignment. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index d51a5200c8af..95e07ea3904c 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1113,11 +1113,10 @@ static int perf_evlist__propagate_maps(struct perf_evlist *evlist, * We already have cpus for evsel (via PMU sysfs) so * keep it, if there's no target cpu list defined. */ - if (evsel->cpus && has_user_cpus) + if (!evsel->cpus || has_user_cpus) { cpu_map__put(evsel->cpus); - - if (!evsel->cpus || has_user_cpus) evsel->cpus = cpu_map__get(evlist->cpus); + } evsel->threads = thread_map__get(evlist->threads); From 725e06b2e2754fbff61521fa76fee51cee5bcb5f Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:58:50 +0300 Subject: [PATCH 03/15] perf evlist: Simplify set_maps() logic Don't need to check for NULL when "putting" evlist->maps and evlist->threads because the "put" functions already do that. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 95e07ea3904c..9cb9296cc4f8 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1156,14 +1156,10 @@ int perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, struct thread_map *threads) { - if (evlist->cpus) - cpu_map__put(evlist->cpus); - + cpu_map__put(evlist->cpus); evlist->cpus = cpus; - if (evlist->threads) - thread_map__put(evlist->threads); - + thread_map__put(evlist->threads); evlist->threads = threads; return perf_evlist__propagate_maps(evlist, false); From d5bc056e73841d4bc941474a342ef9b6a207ac84 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:58:51 +0300 Subject: [PATCH 04/15] perf evlist: Remove redundant validation from propagate_maps() The validation checks that the values that were just assigned, got assigned i.e. the error can't ever happen. Subsequent patches will call this code in places where errors are not being returned. Changing those code paths to return this non-existent error is counter-productive, so just remove it. That in turn results in perf_evlist__set_maps not needing to return an error, but callers aren't checking it either, so remove that too. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 21 ++++++++------------- tools/perf/util/evlist.h | 5 ++--- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 9cb9296cc4f8..785bfd392039 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1103,8 +1103,8 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false); } -static int perf_evlist__propagate_maps(struct perf_evlist *evlist, - bool has_user_cpus) +static void perf_evlist__propagate_maps(struct perf_evlist *evlist, + bool has_user_cpus) { struct perf_evsel *evsel; @@ -1119,13 +1119,7 @@ static int perf_evlist__propagate_maps(struct perf_evlist *evlist, } evsel->threads = thread_map__get(evlist->threads); - - if ((evlist->cpus && !evsel->cpus) || - (evlist->threads && !evsel->threads)) - return -ENOMEM; } - - return 0; } int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) @@ -1144,7 +1138,9 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) if (evlist->cpus == NULL) goto out_delete_threads; - return perf_evlist__propagate_maps(evlist, !!target->cpu_list); + perf_evlist__propagate_maps(evlist, !!target->cpu_list); + + return 0; out_delete_threads: thread_map__put(evlist->threads); @@ -1152,9 +1148,8 @@ out_delete_threads: return -1; } -int perf_evlist__set_maps(struct perf_evlist *evlist, - struct cpu_map *cpus, - struct thread_map *threads) +void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, + struct thread_map *threads) { cpu_map__put(evlist->cpus); evlist->cpus = cpus; @@ -1162,7 +1157,7 @@ int perf_evlist__set_maps(struct perf_evlist *evlist, thread_map__put(evlist->threads); evlist->threads = threads; - return perf_evlist__propagate_maps(evlist, false); + perf_evlist__propagate_maps(evlist, false); } int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index b39a6198f4ac..da2fa9172bd6 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -155,9 +155,8 @@ int perf_evlist__enable_event_idx(struct perf_evlist *evlist, void perf_evlist__set_selected(struct perf_evlist *evlist, struct perf_evsel *evsel); -int perf_evlist__set_maps(struct perf_evlist *evlist, - struct cpu_map *cpus, - struct thread_map *threads); +void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, + struct thread_map *threads); int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target); int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel); From ec9a77a7e3346a05b1287597982d0dd09dd1c3bd Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:58:52 +0300 Subject: [PATCH 05/15] perf evlist: Add has_user_cpus member Subsequent patches will need to call perf_evlist__propagate_maps without reference to a "target". Add evlist->has_user_cpus to record whether the user has specified which cpus to target (and therefore whether that list of cpus should override the default settings for a selected event i.e. the cpu maps should be propagated) Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 11 ++++++----- tools/perf/util/evlist.h | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 785bfd392039..3a4445f26a2c 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1103,8 +1103,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false); } -static void perf_evlist__propagate_maps(struct perf_evlist *evlist, - bool has_user_cpus) +static void perf_evlist__propagate_maps(struct perf_evlist *evlist) { struct perf_evsel *evsel; @@ -1113,7 +1112,7 @@ static void perf_evlist__propagate_maps(struct perf_evlist *evlist, * We already have cpus for evsel (via PMU sysfs) so * keep it, if there's no target cpu list defined. */ - if (!evsel->cpus || has_user_cpus) { + if (!evsel->cpus || evlist->has_user_cpus) { cpu_map__put(evsel->cpus); evsel->cpus = cpu_map__get(evlist->cpus); } @@ -1138,7 +1137,9 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) if (evlist->cpus == NULL) goto out_delete_threads; - perf_evlist__propagate_maps(evlist, !!target->cpu_list); + evlist->has_user_cpus = !!target->cpu_list; + + perf_evlist__propagate_maps(evlist); return 0; @@ -1157,7 +1158,7 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, thread_map__put(evlist->threads); evlist->threads = threads; - perf_evlist__propagate_maps(evlist, false); + perf_evlist__propagate_maps(evlist); } int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index da2fa9172bd6..cfc4df68a9db 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -42,6 +42,7 @@ struct perf_evlist { int nr_mmaps; bool overwrite; bool enabled; + bool has_user_cpus; size_t mmap_len; int id_pos; int is_pos; From f114d6eff76d20b521d8716e969e71b1f56f82b5 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:58:53 +0300 Subject: [PATCH 06/15] perf evlist: Fix splice_list_tail() not setting evlist Commit d49e46950772 ("perf evsel: Add a backpointer to the evlist a evsel is in") updated perf_evlist__add() but not perf_evlist__splice_list_tail(). This illustrates that it is better if perf_evlist__splice_list_tail() calls perf_evlist__add() instead of duplicating the logic, so do that. This will also simplify a subsequent fix for propagating maps. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-6-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 15 +++++++-------- tools/perf/util/evlist.h | 3 +-- tools/perf/util/parse-events.c | 3 +-- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 3a4445f26a2c..961560b2046b 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -136,15 +136,14 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) } void perf_evlist__splice_list_tail(struct perf_evlist *evlist, - struct list_head *list, - int nr_entries) + struct list_head *list) { - bool set_id_pos = !evlist->nr_entries; + struct perf_evsel *evsel, *temp; - list_splice_tail(list, &evlist->entries); - evlist->nr_entries += nr_entries; - if (set_id_pos) - perf_evlist__set_id_pos(evlist); + __evlist__for_each_safe(list, temp, evsel) { + list_del_init(&evsel->node); + perf_evlist__add(evlist, evsel); + } } void __perf_evlist__set_leader(struct list_head *list) @@ -210,7 +209,7 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist, list_add_tail(&evsel->node, &head); } - perf_evlist__splice_list_tail(evlist, &head, nr_attrs); + perf_evlist__splice_list_tail(evlist, &head); return 0; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index cfc4df68a9db..115d8b53c601 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -179,8 +179,7 @@ bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist); bool perf_evlist__valid_read_format(struct perf_evlist *evlist); void perf_evlist__splice_list_tail(struct perf_evlist *evlist, - struct list_head *list, - int nr_entries); + struct list_head *list); static inline struct perf_evsel *perf_evlist__first(struct perf_evlist *evlist) { diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d826e6f515db..7e8ae21906e2 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1140,10 +1140,9 @@ int parse_events(struct perf_evlist *evlist, const char *str, ret = parse_events__scanner(str, &data, PE_START_EVENTS); perf_pmu__parse_cleanup(); if (!ret) { - int entries = data.idx - evlist->nr_entries; struct perf_evsel *last; - perf_evlist__splice_list_tail(evlist, &data.list, entries); + perf_evlist__splice_list_tail(evlist, &data.list); evlist->nr_groups += data.nr_groups; last = perf_evlist__last(evlist); last->cmdline_group_boundary = true; From b278c364b35ae940b05f6a9edf8061fc886cd09e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:58:54 +0300 Subject: [PATCH 07/15] perf evlist: Fix missing thread_map__put in propagate_maps() perf_evlist__propagate_maps() incorrectly assumes evsel->threads is NULL before reassigning it, but it won't be NULL when perf_evlist__set_maps() is used to set different (or NULL) maps. Thus thread_map__put must be used, which works even if evsel->threads is NULL. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-7-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 961560b2046b..79056c6ae507 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1116,6 +1116,7 @@ static void perf_evlist__propagate_maps(struct perf_evlist *evlist) evsel->cpus = cpu_map__get(evlist->cpus); } + thread_map__put(evsel->threads); evsel->threads = thread_map__get(evlist->threads); } } From fce4d296b405b03fba033a55017348bf55b10db6 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:58:55 +0300 Subject: [PATCH 08/15] perf evsel: Add own_cpus member perf_evlist__propagate_maps() cannot easily tell if an evsel has its own cpu map. To make that simpler, keep a copy of the PMU cpu map and adjust the propagation logic accordingly. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-8-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 5 ++++- tools/perf/util/evsel.c | 1 + tools/perf/util/evsel.h | 1 + tools/perf/util/parse-events.c | 4 ++-- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 79056c6ae507..5bd3b49452c6 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1111,9 +1111,12 @@ static void perf_evlist__propagate_maps(struct perf_evlist *evlist) * We already have cpus for evsel (via PMU sysfs) so * keep it, if there's no target cpu list defined. */ - if (!evsel->cpus || evlist->has_user_cpus) { + if (!evsel->own_cpus || evlist->has_user_cpus) { cpu_map__put(evsel->cpus); evsel->cpus = cpu_map__get(evlist->cpus); + } else if (evsel->cpus != evsel->own_cpus) { + cpu_map__put(evsel->cpus); + evsel->cpus = cpu_map__get(evsel->own_cpus); } thread_map__put(evsel->threads); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index c53f79123b37..5410483d5219 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1033,6 +1033,7 @@ void perf_evsel__exit(struct perf_evsel *evsel) perf_evsel__free_config_terms(evsel); close_cgroup(evsel->cgrp); cpu_map__put(evsel->cpus); + cpu_map__put(evsel->own_cpus); thread_map__put(evsel->threads); zfree(&evsel->group_name); zfree(&evsel->name); diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 298e6bbca200..ef8925f7211a 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -98,6 +98,7 @@ struct perf_evsel { struct cgroup_sel *cgrp; void *handler; struct cpu_map *cpus; + struct cpu_map *own_cpus; struct thread_map *threads; unsigned int sample_size; int id_pos; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 7e8ae21906e2..21ed6ee63da9 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -287,8 +287,8 @@ __add_event(struct list_head *list, int *idx, if (!evsel) return NULL; - if (cpus) - evsel->cpus = cpu_map__get(cpus); + evsel->cpus = cpu_map__get(cpus); + evsel->own_cpus = cpu_map__get(cpus); if (name) evsel->name = strdup(name); From 934e0f2053ce299893ca48a411bf7fdc8ac6254f Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:58:56 +0300 Subject: [PATCH 09/15] perf evlist: Make set_maps() more resilient Make perf_evlist__set_maps() more resilient by allowing for the possibility that one or another of the maps isn't being changed and therefore should not be "put". Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-9-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 5bd3b49452c6..78ff52ee8788 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1155,11 +1155,22 @@ out_delete_threads: void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, struct thread_map *threads) { - cpu_map__put(evlist->cpus); - evlist->cpus = cpus; + /* + * Allow for the possibility that one or another of the maps isn't being + * changed i.e. don't put it. Note we are assuming the maps that are + * being applied are brand new and evlist is taking ownership of the + * original reference count of 1. If that is not the case it is up to + * the caller to increase the reference count. + */ + if (cpus != evlist->cpus) { + cpu_map__put(evlist->cpus); + evlist->cpus = cpus; + } - thread_map__put(evlist->threads); - evlist->threads = threads; + if (threads != evlist->threads) { + thread_map__put(evlist->threads); + evlist->threads = threads; + } perf_evlist__propagate_maps(evlist); } From 74bfd2b25de354feb4484c553dce4fe8d9c3b60b Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:58:57 +0300 Subject: [PATCH 10/15] perf evlist: Make create_maps() use set_maps() Since there is a function to set maps, perf_evlist__create_maps() should use it. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-10-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 78ff52ee8788..c17f3558a37a 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1126,29 +1126,30 @@ static void perf_evlist__propagate_maps(struct perf_evlist *evlist) int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) { - evlist->threads = thread_map__new_str(target->pid, target->tid, - target->uid); + struct cpu_map *cpus; + struct thread_map *threads; - if (evlist->threads == NULL) + threads = thread_map__new_str(target->pid, target->tid, target->uid); + + if (!threads) return -1; if (target__uses_dummy_map(target)) - evlist->cpus = cpu_map__dummy_new(); + cpus = cpu_map__dummy_new(); else - evlist->cpus = cpu_map__new(target->cpu_list); + cpus = cpu_map__new(target->cpu_list); - if (evlist->cpus == NULL) + if (!cpus) goto out_delete_threads; evlist->has_user_cpus = !!target->cpu_list; - perf_evlist__propagate_maps(evlist); + perf_evlist__set_maps(evlist, cpus, threads); return 0; out_delete_threads: - thread_map__put(evlist->threads); - evlist->threads = NULL; + thread_map__put(threads); return -1; } From adc0c3e87b0e1baeccabe09b6dba738f17d0e91d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:58:58 +0300 Subject: [PATCH 11/15] perf evlist: Factor out a function to propagate maps for a single evsel Subsequent fixes will need a function that just propagates maps for a single evsel so factor it out. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-11-git-send-email-adrian.hunter@intel.com [ Moved them to before perf_evlist__add() to avoid having to move it in the next patch ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 49 ++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index c17f3558a37a..4e840bfc19ef 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -124,6 +124,33 @@ void perf_evlist__delete(struct perf_evlist *evlist) free(evlist); } +static void __perf_evlist__propagate_maps(struct perf_evlist *evlist, + struct perf_evsel *evsel) +{ + /* + * We already have cpus for evsel (via PMU sysfs) so + * keep it, if there's no target cpu list defined. + */ + if (!evsel->own_cpus || evlist->has_user_cpus) { + cpu_map__put(evsel->cpus); + evsel->cpus = cpu_map__get(evlist->cpus); + } else if (evsel->cpus != evsel->own_cpus) { + cpu_map__put(evsel->cpus); + evsel->cpus = cpu_map__get(evsel->own_cpus); + } + + thread_map__put(evsel->threads); + evsel->threads = thread_map__get(evlist->threads); +} + +static void perf_evlist__propagate_maps(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + evlist__for_each(evlist, evsel) + __perf_evlist__propagate_maps(evlist, evsel); +} + void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) { entry->evlist = evlist; @@ -1102,28 +1129,6 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false); } -static void perf_evlist__propagate_maps(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel; - - evlist__for_each(evlist, evsel) { - /* - * We already have cpus for evsel (via PMU sysfs) so - * keep it, if there's no target cpu list defined. - */ - if (!evsel->own_cpus || evlist->has_user_cpus) { - cpu_map__put(evsel->cpus); - evsel->cpus = cpu_map__get(evlist->cpus); - } else if (evsel->cpus != evsel->own_cpus) { - cpu_map__put(evsel->cpus); - evsel->cpus = cpu_map__get(evsel->own_cpus); - } - - thread_map__put(evsel->threads); - evsel->threads = thread_map__get(evlist->threads); - } -} - int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) { struct cpu_map *cpus; From 44c42d71c659527c81bf169808959c9339116d85 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:58:59 +0300 Subject: [PATCH 12/15] perf evlist: Fix add() not propagating maps If evsels are added after maps are created, then they won't have any maps propagated to them. Fix that. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-12-git-send-email-adrian.hunter@intel.com [ Moved the moving of propagate_maps() to the patch before, so that this one does _just_ the one lile fix calling in add()] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 4e840bfc19ef..99267ab0d24a 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -160,6 +160,8 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) if (!evlist->nr_entries++) perf_evlist__set_id_pos(evlist); + + __perf_evlist__propagate_maps(evlist, entry); } void perf_evlist__splice_list_tail(struct perf_evlist *evlist, From 8c0498b6891d7ca5c379c6283de7fc7fe8eebe5c Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:59:00 +0300 Subject: [PATCH 13/15] perf evlist: Fix create_syswide_maps() not propagating maps Fix it by making it call perf_evlist__set_maps() instead of setting the maps itself. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-13-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 99267ab0d24a..c8fc8a258f42 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1400,6 +1400,8 @@ void perf_evlist__close(struct perf_evlist *evlist) static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist) { + struct cpu_map *cpus; + struct thread_map *threads; int err = -ENOMEM; /* @@ -1411,20 +1413,19 @@ static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist) * error, and we may not want to do that fallback to a * default cpu identity map :-\ */ - evlist->cpus = cpu_map__new(NULL); - if (evlist->cpus == NULL) + cpus = cpu_map__new(NULL); + if (!cpus) goto out; - evlist->threads = thread_map__new_dummy(); - if (evlist->threads == NULL) - goto out_free_cpus; + threads = thread_map__new_dummy(); + if (!threads) + goto out_put; - err = 0; + perf_evlist__set_maps(evlist, cpus, threads); out: return err; -out_free_cpus: - cpu_map__put(evlist->cpus); - evlist->cpus = NULL; +out_put: + cpu_map__put(cpus); goto out; } From 2998272275fc31fc3d478ef9c95e7eaef67dafa3 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:59:01 +0300 Subject: [PATCH 14/15] perf tests: Fix task exit test setting maps The test titled "Test number of exit event of a simple workload" was setting cpu/thread maps directly. Make it use the proper function perf_evlist__set_maps() especially now that it also propagates the maps. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-14-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/task-exit.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index 3a8fedef83bc..add16385f13e 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c @@ -43,6 +43,8 @@ int test__task_exit(void) }; const char *argv[] = { "true", NULL }; char sbuf[STRERR_BUFSIZE]; + struct cpu_map *cpus; + struct thread_map *threads; signal(SIGCHLD, sig_handler); @@ -58,14 +60,19 @@ int test__task_exit(void) * perf_evlist__prepare_workload we'll fill in the only thread * we're monitoring, the one forked there. */ - evlist->cpus = cpu_map__dummy_new(); - evlist->threads = thread_map__new_by_tid(-1); - if (!evlist->cpus || !evlist->threads) { + cpus = cpu_map__dummy_new(); + threads = thread_map__new_by_tid(-1); + if (!cpus || !threads) { err = -ENOMEM; pr_debug("Not enough memory to create thread/cpu maps\n"); - goto out_delete_evlist; + goto out_free_maps; } + perf_evlist__set_maps(evlist, cpus, threads); + + cpus = NULL; + threads = NULL; + err = perf_evlist__prepare_workload(evlist, &target, argv, false, workload_exec_failed_signal); if (err < 0) { @@ -114,6 +121,9 @@ retry: err = -1; } +out_free_maps: + cpu_map__put(cpus); + thread_map__put(threads); out_delete_evlist: perf_evlist__delete(evlist); return err; From c5e6bd2ed3e81df443e4ae11e95ed71ff77bf9e5 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Sep 2015 10:59:02 +0300 Subject: [PATCH 15/15] perf tests: Fix software clock events test setting maps The test titled "Test software clock events have valid period values" was setting cpu/thread maps directly. Make it use the proper function perf_evlist__set_maps() especially now that it also propagates the maps. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Kan Liang Link: http://lkml.kernel.org/r/1441699142-18905-15-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/sw-clock.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c index 1aa21c90731b..5b83f56a3b6f 100644 --- a/tools/perf/tests/sw-clock.c +++ b/tools/perf/tests/sw-clock.c @@ -34,6 +34,8 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) .disabled = 1, .freq = 1, }; + struct cpu_map *cpus; + struct thread_map *threads; attr.sample_freq = 500; @@ -50,14 +52,19 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) } perf_evlist__add(evlist, evsel); - evlist->cpus = cpu_map__dummy_new(); - evlist->threads = thread_map__new_by_tid(getpid()); - if (!evlist->cpus || !evlist->threads) { + cpus = cpu_map__dummy_new(); + threads = thread_map__new_by_tid(getpid()); + if (!cpus || !threads) { err = -ENOMEM; pr_debug("Not enough memory to create thread/cpu maps\n"); - goto out_delete_evlist; + goto out_free_maps; } + perf_evlist__set_maps(evlist, cpus, threads); + + cpus = NULL; + threads = NULL; + if (perf_evlist__open(evlist)) { const char *knob = "/proc/sys/kernel/perf_event_max_sample_rate"; @@ -107,6 +114,9 @@ next_event: err = -1; } +out_free_maps: + cpu_map__put(cpus); + thread_map__put(threads); out_delete_evlist: perf_evlist__delete(evlist); return err;