Skip to content

Commit

Permalink
Allow for collection of more PMUs than are physically available.
Browse files Browse the repository at this point in the history
Normally we can only collect as many PMUs as we have physical PMU
counters because they are managed as a single pinned group and extra
requested PMUs will not be collected. With this patch we instead collect
each PMU as a separate group once this limit is hit using PMU
multiplexing.
  • Loading branch information
Jamison Collins committed Jan 12, 2024
1 parent ea71a14 commit 2d609d4
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 15 deletions.
36 changes: 22 additions & 14 deletions src/perf_counters.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string> valid_names;
std::vector<int> counter_ids;
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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.
Expand All @@ -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);
Expand All @@ -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);
}
Expand Down Expand Up @@ -254,7 +261,7 @@ bool PerfCounters::IsCounterSupported(const std::string&) { return false; }
PerfCounters PerfCounters::Create(
const std::vector<std::string>& counter_names) {
if (!counter_names.empty()) {
GetErrorLogInstance() << "Performance counters not supported.\n";
GetErrorLogInstance() << "Performance counters not supported.";
}
return NoCounters();
}
Expand All @@ -280,3 +287,4 @@ PerfCounters& PerfCounters::operator=(PerfCounters&& other) noexcept {
}
} // namespace internal
} // namespace benchmark

2 changes: 1 addition & 1 deletion src/perf_counters.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>& leaders);

Expand Down

0 comments on commit 2d609d4

Please # to comment.