Commit 0a892c1c9472 ("perf record: Add dummy event during system wide
synthesis") reveals an issue with Intel PT system wide tracing.
Specifically that Intel PT already adds a dummy tracking event, and it is
not the first event.  Adding another dummy tracking event causes duplicated
sideband events.  Fix by checking for an existing dummy tracking event
first.

Example showing duplicated switch events:

 Before:

   # perf record -a -e intel_pt//u uname
   Linux
   [ perf record: Woken up 1 times to write data ]
   [ perf record: Captured and wrote 0.895 MB perf.data ]
   # perf script --no-itrace --show-switch-events | head
            swapper     0 [007]  6390.516222: PERF_RECORD_SWITCH_CPU_WIDE OUT 
preempt  next pid/tid:    11/11
            swapper     0 [007]  6390.516222: PERF_RECORD_SWITCH_CPU_WIDE OUT 
preempt  next pid/tid:    11/11
          rcu_sched    11 [007]  6390.516223: PERF_RECORD_SWITCH_CPU_WIDE IN    
       prev pid/tid:     0/0
          rcu_sched    11 [007]  6390.516224: PERF_RECORD_SWITCH_CPU_WIDE IN    
       prev pid/tid:     0/0
          rcu_sched    11 [007]  6390.516227: PERF_RECORD_SWITCH_CPU_WIDE OUT   
       next pid/tid:     0/0
          rcu_sched    11 [007]  6390.516227: PERF_RECORD_SWITCH_CPU_WIDE OUT   
       next pid/tid:     0/0
            swapper     0 [007]  6390.516228: PERF_RECORD_SWITCH_CPU_WIDE IN    
       prev pid/tid:    11/11
            swapper     0 [007]  6390.516228: PERF_RECORD_SWITCH_CPU_WIDE IN    
       prev pid/tid:    11/11
            swapper     0 [002]  6390.516415: PERF_RECORD_SWITCH_CPU_WIDE OUT 
preempt  next pid/tid:  5556/5559
            swapper     0 [002]  6390.516416: PERF_RECORD_SWITCH_CPU_WIDE OUT 
preempt  next pid/tid:  5556/5559

 After:

   # perf record -a -e intel_pt//u uname
   Linux
   [ perf record: Woken up 1 times to write data ]
   [ perf record: Captured and wrote 0.868 MB perf.data ]
   #  perf script --no-itrace --show-switch-events | head
            swapper     0 [005]  6450.567013: PERF_RECORD_SWITCH_CPU_WIDE OUT 
preempt  next pid/tid:  7179/7181
               perf  7181 [005]  6450.567014: PERF_RECORD_SWITCH_CPU_WIDE IN    
       prev pid/tid:     0/0
               perf  7181 [005]  6450.567028: PERF_RECORD_SWITCH_CPU_WIDE OUT   
       next pid/tid:     0/0
            swapper     0 [005]  6450.567029: PERF_RECORD_SWITCH_CPU_WIDE IN    
       prev pid/tid:  7179/7181
            swapper     0 [005]  6450.571699: PERF_RECORD_SWITCH_CPU_WIDE OUT 
preempt  next pid/tid:    11/11
          rcu_sched    11 [005]  6450.571700: PERF_RECORD_SWITCH_CPU_WIDE IN    
       prev pid/tid:     0/0
          rcu_sched    11 [005]  6450.571702: PERF_RECORD_SWITCH_CPU_WIDE OUT   
       next pid/tid:     0/0
            swapper     0 [005]  6450.571703: PERF_RECORD_SWITCH_CPU_WIDE IN    
       prev pid/tid:    11/11
            swapper     0 [005]  6450.579703: PERF_RECORD_SWITCH_CPU_WIDE OUT 
preempt  next pid/tid:    11/11
          rcu_sched    11 [005]  6450.579704: PERF_RECORD_SWITCH_CPU_WIDE IN    
       prev pid/tid:     0/0

Signed-off-by: Adrian Hunter <[email protected]>
---
 tools/perf/builtin-record.c | 18 +++++++++---------
 tools/perf/util/evlist.c    | 12 ++++++++++++
 tools/perf/util/evlist.h    |  1 +
 tools/perf/util/evsel.c     |  8 +-------
 tools/perf/util/evsel.h     |  6 ++++++
 5 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index e108d90ae2ed..a37e7910e9e9 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -852,20 +852,20 @@ static int record__open(struct record *rec)
         * event synthesis.
         */
        if (opts->initial_delay || target__has_cpu(&opts->target)) {
-               if (perf_evlist__add_dummy(evlist))
-                       return -ENOMEM;
+               pos = perf_evlist__get_tracking_event(evlist);
+               if (!evsel__is_dummy_event(pos)) {
+                       /* Set up dummy event. */
+                       if (perf_evlist__add_dummy(evlist))
+                               return -ENOMEM;
+                       pos = evlist__last(evlist);
+                       perf_evlist__set_tracking_event(evlist, pos);
+               }
 
-               /* Disable tracking of mmaps on lead event. */
-               pos = evlist__first(evlist);
-               pos->tracking = 0;
-               /* Set up dummy event. */
-               pos = evlist__last(evlist);
-               pos->tracking = 1;
                /*
                 * Enable the dummy event when the process is forked for
                 * initial_delay, immediately for system wide.
                 */
-               if (opts->initial_delay)
+               if (opts->initial_delay && !pos->immediate)
                        pos->core.attr.enable_on_exec = 1;
                else
                        pos->immediate = 1;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 173b4f0e0e6e..ab48be4cf258 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1566,6 +1566,18 @@ void perf_evlist__to_front(struct evlist *evlist,
        list_splice(&move, &evlist->core.entries);
 }
 
+struct evsel *perf_evlist__get_tracking_event(struct evlist *evlist)
+{
+       struct evsel *evsel;
+
+       evlist__for_each_entry(evlist, evsel) {
+               if (evsel->tracking)
+                       return evsel;
+       }
+
+       return evlist__first(evlist);
+}
+
 void perf_evlist__set_tracking_event(struct evlist *evlist,
                                     struct evsel *tracking_evsel)
 {
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index b6f325dfb4d2..a8081dfc19cf 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -335,6 +335,7 @@ void perf_evlist__to_front(struct evlist *evlist,
        evlist__cpu_iter_start(evlist);                 \
        perf_cpu_map__for_each_cpu (cpu, index, (evlist)->core.all_cpus)
 
+struct evsel *perf_evlist__get_tracking_event(struct evlist *evlist);
 void perf_evlist__set_tracking_event(struct evlist *evlist,
                                     struct evsel *tracking_evsel);
 
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 96e5171dce41..a68ac3632ae6 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -898,12 +898,6 @@ static void evsel__apply_config_terms(struct evsel *evsel,
        }
 }
 
-static bool is_dummy_event(struct evsel *evsel)
-{
-       return (evsel->core.attr.type == PERF_TYPE_SOFTWARE) &&
-              (evsel->core.attr.config == PERF_COUNT_SW_DUMMY);
-}
-
 struct evsel_config_term *__evsel__get_config_term(struct evsel *evsel, enum 
evsel_term_type type)
 {
        struct evsel_config_term *term, *found_term = NULL;
@@ -1161,7 +1155,7 @@ void evsel__config(struct evsel *evsel, struct 
record_opts *opts,
         * The software event will trigger -EOPNOTSUPP error out,
         * if BRANCH_STACK bit is set.
         */
-       if (is_dummy_event(evsel))
+       if (evsel__is_dummy_event(evsel))
                evsel__reset_sample_bit(evsel, BRANCH_STACK);
 }
 
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 0f963c2a88a5..35e3f6d66085 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -399,6 +399,12 @@ static inline bool evsel__has_br_stack(const struct evsel 
*evsel)
               evsel->synth_sample_type & PERF_SAMPLE_BRANCH_STACK;
 }
 
+static inline bool evsel__is_dummy_event(struct evsel *evsel)
+{
+       return (evsel->core.attr.type == PERF_TYPE_SOFTWARE) &&
+              (evsel->core.attr.config == PERF_COUNT_SW_DUMMY);
+}
+
 struct perf_env *evsel__env(struct evsel *evsel);
 
 int evsel__store_ids(struct evsel *evsel, struct evlist *evlist);
-- 
2.17.1

Reply via email to