diff --git a/src/perf_counters.cc b/src/perf_counters.cc index d466e27e8..eb12676b1 100644 --- a/src/perf_counters.cc +++ b/src/perf_counters.cc @@ -86,6 +86,12 @@ PerfCounters PerfCounters::Create( Initialize(); } + // Initially try to create a single group which holds all PMUs since that + // has lower overhead. Group multiplexing doesn't work on all platforms so if + // that fails try again without using groups. + bool group_pmus = true; +retry_without_groups: + // Valid counters will populate these arrays but we start empty std::vector valid_names; std::vector counter_ids; @@ -96,11 +102,6 @@ PerfCounters PerfCounters::Create( counter_ids.reserve(counter_names.size()); const int kCounterMode = PFM_PLM3; // user mode only - - // Group leads will be assigned on demand. The idea is that once we cannot - // create a counter descriptor, the reason is that this group has maxed out - // so we set the group_id again to -1 and retry - giving the algorithm a - // chance to create a new group leader to hold the next set of counters. int group_id = -1; // Loop through all performance counters @@ -150,7 +151,7 @@ PerfCounters PerfCounters::Create( // case. attr.disabled = is_first; attr.inherit = true; - attr.pinned = is_first; + attr.pinned = group_pmus; attr.exclude_kernel = true; attr.exclude_user = false; attr.exclude_hv = true; @@ -171,10 +172,14 @@ PerfCounters PerfCounters::Create( } if (id < 0) { // If the file descriptor is negative we might have reached a limit - // in the current group. Set the group_id to -1 and retry - if (group_id >= 0) { - // Create a new group - group_id = -1; + // in the current group. Let's try again without groups. + if (group_id >= 0 && group_pmus) { + // Close all performance counters + for (int close_id : counter_ids) { + ::close(close_id); + } + group_pmus = false; + goto retry_without_groups; } else { // At this point we have already retried to set a new group id and // failed. We then give up. @@ -197,7 +202,9 @@ PerfCounters PerfCounters::Create( if (group_id < 0) { // This is a leader, store and assign it to the current file descriptor leader_ids.push_back(id); - group_id = id; + if (group_pmus) { + group_id = id; + } } // This is a valid counter, add it to our descriptor's list counter_ids.push_back(id); @@ -214,9 +221,9 @@ PerfCounters PerfCounters::Create( // This should never happen but if it does, we give up on the // entire batch as recovery would be a mess. GetErrorLogInstance() << "***WARNING*** Failed to start counters. " - "Claring out all counters.\n"; + "Clearing out all counters.\n"; - // Close all peformance counters + // Close all performance counters for (int id : counter_ids) { ::close(id); } @@ -254,7 +261,7 @@ bool PerfCounters::IsCounterSupported(const std::string&) { return false; } PerfCounters PerfCounters::Create( const std::vector& counter_names) { if (!counter_names.empty()) { - GetErrorLogInstance() << "Performance counters not supported.\n"; + GetErrorLogInstance() << "Performance counters not supported."; } return NoCounters(); } @@ -280,3 +287,4 @@ PerfCounters& PerfCounters::operator=(PerfCounters&& other) noexcept { } } // namespace internal } // namespace benchmark + diff --git a/src/perf_counters.h b/src/perf_counters.h index bf5eb6bc3..350fe2d3d 100644 --- a/src/perf_counters.h +++ b/src/perf_counters.h @@ -71,7 +71,7 @@ class BENCHMARK_EXPORT PerfCounterValues { } // This reading is complex and as the goal of this class is to - // abstract away the intrincacies of the reading process, this is + // abstract away the intricacies of the reading process, this is // a better place for it size_t Read(const std::vector& leaders);