From: Adrian Hunter <adrian.hunter@intel.com>
To: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>,
jolsa@kernel.org, mingo@kernel.org, kan.liang@intel.com,
linux-kernel@vger.kernel.org
Subject: [PATCH] perf tools: Fix gaps propagating maps
Date: Fri, 4 Sep 2015 15:15:54 +0300 [thread overview]
Message-ID: <1441368954-25066-1-git-send-email-adrian.hunter@intel.com> (raw)
In-Reply-To: <55E943B7.6000408@intel.com>
A perf_evsel is a selected event containing the perf_event_attr
that is passed to perf_event_open(). A perf_evlist is a collection
of perf_evsel's. A perf_evlist also has lists of cpus and threads
(pids) on which to open the event. These lists are called 'maps'
and this patch is about how those 'maps' are propagated from the
perf_evlist to the perf_evsels.
Originally perf_evsels did not have their own thread 'maps', and
their cpu 'maps' were only used for checking. Then threads were
added by:
578e91ec04d0 ("perf evlist: Propagate thread maps through the evlist")
And then 'perf record' was changed to open events using the 'maps'
from perf_evsel not perf_evlist anymore, by:
d988d5ee6478 ("perf evlist: Open event on evsel cpus and threads")
That exposed situations where the 'maps' were not getting propagated
correctly, such as when perf_evsel are added to the perf_evlist later.
This patch ensures 'maps' get propagated in that case, and also if 'maps'
are subsequently changed or set to NULL by perf_evlist__set_maps()
and perf_evlist__create_syswide_maps().
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
tools/perf/util/evlist.c | 129 ++++++++++++++++++++++++++++++++---------------
tools/perf/util/evlist.h | 1 +
2 files changed, 88 insertions(+), 42 deletions(-)
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index d51a5200c8af..00128cf7655b 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -124,8 +124,49 @@ void perf_evlist__delete(struct perf_evlist *evlist)
free(evlist);
}
+static void __perf_evlist__propagate_maps(struct perf_evlist *evlist,
+ struct perf_evsel *evsel,
+ bool propagate)
+{
+ if (propagate) {
+ /*
+ * 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) &&
+ evsel->cpus != evlist->cpus) {
+ cpu_map__put(evsel->cpus);
+ evsel->cpus = cpu_map__get(evlist->cpus);
+ }
+
+ if (!evsel->threads)
+ evsel->threads = thread_map__get(evlist->threads);
+ } else {
+ if (evsel->cpus == evlist->cpus) {
+ cpu_map__put(evsel->cpus);
+ evsel->cpus = NULL;
+ }
+
+ if (evsel->threads == evlist->threads) {
+ thread_map__put(evsel->threads);
+ evsel->threads = NULL;
+ }
+ }
+}
+
+static void perf_evlist__propagate_maps(struct perf_evlist *evlist,
+ bool propagate)
+{
+ struct perf_evsel *evsel;
+
+ evlist__for_each(evlist, evsel)
+ __perf_evlist__propagate_maps(evlist, evsel, propagate);
+}
+
void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
{
+ __perf_evlist__propagate_maps(evlist, entry, true);
+
entry->evlist = evlist;
list_add_tail(&entry->node, &evlist->entries);
entry->idx = evlist->nr_entries;
@@ -140,6 +181,10 @@ void perf_evlist__splice_list_tail(struct perf_evlist *evlist,
int nr_entries)
{
bool set_id_pos = !evlist->nr_entries;
+ struct perf_evsel *evsel;
+
+ __evlist__for_each(list, evsel)
+ __perf_evlist__propagate_maps(evlist, evsel, true);
list_splice_tail(list, &evlist->entries);
evlist->nr_entries += nr_entries;
@@ -1103,34 +1148,11 @@ 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)
-{
- 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->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);
-
- 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)
{
+ if (evlist->threads || evlist->cpus)
+ return -1;
+
evlist->threads = thread_map__new_str(target->pid, target->tid,
target->uid);
@@ -1145,7 +1167,11 @@ 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);
+ evlist->has_user_cpus = !!target->cpu_list;
+
+ perf_evlist__propagate_maps(evlist, true);
+
+ return 0;
out_delete_threads:
thread_map__put(evlist->threads);
@@ -1157,17 +1183,32 @@ 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);
+ /*
+ * First 'un-propagate' the current maps which allows the propagation to
+ * work correctly even when changing the maps or setting them to NULL.
+ */
+ perf_evlist__propagate_maps(evlist, false);
- 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;
+ }
- if (evlist->threads)
+ if (threads != evlist->threads) {
thread_map__put(evlist->threads);
+ evlist->threads = threads;
+ }
- evlist->threads = threads;
+ perf_evlist__propagate_maps(evlist, true);
- return perf_evlist__propagate_maps(evlist, false);
+ return 0;
}
int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel)
@@ -1387,6 +1428,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;
/*
@@ -1398,20 +1441,22 @@ 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;
+ err = perf_evlist__set_maps(evlist, cpus, threads);
+ if (err)
+ goto out_put;
out:
return err;
-out_free_cpus:
- cpu_map__put(evlist->cpus);
- evlist->cpus = NULL;
+out_put:
+ cpu_map__put(cpus);
+ thread_map__put(threads);
goto out;
}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index b39a6198f4ac..2dd5715dfef6 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;
--
1.9.1
next prev parent reply other threads:[~2015-09-04 12:18 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-08-21 6:23 [PATCH 1/1] perf,tools: open event on evsel cpus and threads kan.liang
2015-08-21 13:54 ` Jiri Olsa
2015-08-31 20:31 ` Arnaldo Carvalho de Melo
2015-08-31 21:06 ` Liang, Kan
2015-08-31 21:14 ` Arnaldo Carvalho de Melo
2015-08-31 21:28 ` Liang, Kan
2015-08-31 21:34 ` Arnaldo Carvalho de Melo
2015-09-01 8:31 ` [tip:perf/urgent] perf evlist: Open " tip-bot for Kan Liang
2015-09-03 13:34 ` Adrian Hunter
2015-09-03 15:27 ` Arnaldo Carvalho de Melo
2015-09-03 16:23 ` Adrian Hunter
2015-09-03 16:41 ` Arnaldo Carvalho de Melo
2015-09-03 18:19 ` Jiri Olsa
2015-09-03 18:38 ` Adrian Hunter
2015-09-03 19:04 ` Jiri Olsa
2015-09-03 20:41 ` Arnaldo Carvalho de Melo
2015-09-04 7:05 ` Jiri Olsa
2015-09-04 7:09 ` Adrian Hunter
2015-09-04 12:15 ` Adrian Hunter [this message]
2015-09-04 13:28 ` [PATCH] perf tools: Fix gaps propagating maps Arnaldo Carvalho de Melo
2015-09-04 13:42 ` Adrian Hunter
2015-09-04 14:48 ` Arnaldo Carvalho de Melo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1441368954-25066-1-git-send-email-adrian.hunter@intel.com \
--to=adrian.hunter@intel.com \
--cc=acme@redhat.com \
--cc=jolsa@kernel.org \
--cc=jolsa@redhat.com \
--cc=kan.liang@intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome