2626namespace benchmark {
2727namespace internal {
2828
29- constexpr size_t PerfCounterValues::kMaxCounters ;
30-
3129#if defined HAVE_LIBPFM
30+
31+ class SinglePMURegistry {
32+ public:
33+ ~SinglePMURegistry () = default ;
34+ SinglePMURegistry (SinglePMURegistry&&) = default ;
35+ SinglePMURegistry (const SinglePMURegistry&) = delete ;
36+ SinglePMURegistry& operator =(SinglePMURegistry&&) noexcept ;
37+ SinglePMURegistry& operator =(const SinglePMURegistry&) = delete ;
38+
39+ SinglePMURegistry (pfm_pmu_t pmu_id)
40+ : pmu_id_(pmu_id), available_counters_(0 ), available_fixed_counters_(0 ) {
41+ {
42+ pfm_pmu_info_t pmu_info{};
43+ const auto pfm_pmu = pfm_get_pmu_info (pmu_id, &pmu_info);
44+
45+ if (pfm_pmu != PFM_SUCCESS) {
46+ GetErrorLogInstance () << " Unknown pmu: " << pmu_id << " \n " ;
47+ return ;
48+ }
49+
50+ name_ = pmu_info.name ;
51+ desc_ = pmu_info.desc ;
52+ available_counters_ = pmu_info.num_cntrs ;
53+ available_fixed_counters_ = pmu_info.num_fixed_cntrs ;
54+
55+ BM_VLOG (1 ) << " PMU: " << pmu_id << " " << name_ << " " << desc_ << " \n " ;
56+ BM_VLOG (1 ) << " counters: " << available_counters_ << " fixed: " << available_fixed_counters_ << " \n " ;
57+ }
58+ }
59+
60+ const char * name () const { return name_; }
61+
62+ bool AddCounter (int event_id) {
63+ pfm_event_info_t info{};
64+ const auto pfm_event_info =
65+ pfm_get_event_info (event_id, PFM_OS_PERF_EVENT, &info);
66+
67+ if (pfm_event_info != PFM_SUCCESS) {
68+ GetErrorLogInstance () << " Unknown event id: " << event_id << " \n " ;
69+ return false ;
70+ }
71+
72+ assert (info.pmu == pmu_id_);
73+
74+ if (counter_ids_.find (event_id) != counter_ids_.end ()) return true ;
75+
76+ if (counter_ids_.size () >= available_counters_ - 1 ) {
77+ GetErrorLogInstance () << " Maximal number of counters for PMU " << name_
78+ << " (" << available_counters_ << " ) reached.\n " ;
79+ return false ;
80+ }
81+
82+ counter_ids_.emplace (event_id, info.code );
83+
84+ BM_VLOG (2 ) << " Registered counter: " << event_id << " (" << info.name << " - " << info.desc
85+ << " ) in pmu " << name_ << " (" << counter_ids_.size () << " /" << available_counters_ << " \n " ;
86+
87+ return true ;
88+ }
89+
90+ private:
91+ pfm_pmu_t pmu_id_;
92+ const char * name_;
93+ const char * desc_;
94+ std::unordered_map<int , uint64_t > counter_ids_;
95+ std::unordered_map<int , uint64_t > fixed_counter_ids_;
96+ uint64_t available_counters_;
97+ uint64_t available_fixed_counters_;
98+ };
99+
100+ class PMURegistry {
101+ public:
102+ ~PMURegistry () = default ;
103+ PMURegistry (PMURegistry&&) = default ;
104+ PMURegistry (const PMURegistry&) = delete ;
105+ PMURegistry& operator =(PMURegistry&&) noexcept ;
106+ PMURegistry& operator =(const PMURegistry&) = delete ;
107+ PMURegistry () {}
108+
109+ bool EnlistCounter (const std::basic_string<char >& name, struct perf_event_attr &attr_base) {
110+ attr_base.size = sizeof (attr_base);
111+ pfm_perf_encode_arg_t encoding{};
112+ encoding.attr = &attr_base;
113+
114+ const auto pfm_get = pfm_get_os_event_encoding (
115+ name.c_str (), PFM_PLM3, PFM_OS_PERF_EVENT, &encoding);
116+ if (pfm_get != PFM_SUCCESS) {
117+ GetErrorLogInstance () << " Unknown counter name: " << name << " \n " ;
118+ return false ;
119+ }
120+
121+ pfm_event_info_t info{};
122+ const auto pfm_info =
123+ pfm_get_event_info (encoding.idx , PFM_OS_PERF_EVENT, &info);
124+ if (pfm_info != PFM_SUCCESS) {
125+ GetErrorLogInstance ()
126+ << " Unknown counter idx: " << encoding.idx << " (" << name << " )\n " ;
127+ return false ;
128+ }
129+
130+ // Spin-up a new per-PMU sub-registry if needed
131+ if (pmu_registry_.find (info.pmu ) == pmu_registry_.end ()) {
132+ pmu_registry_.emplace (info.pmu , SinglePMURegistry (info.pmu ));
133+ }
134+
135+ auto & single_pmu = pmu_registry_.find (info.pmu )->second ;
136+
137+ return single_pmu.AddCounter (info.idx );
138+ }
139+
140+ private:
141+ std::unordered_map<pfm_pmu_t , SinglePMURegistry> pmu_registry_;
142+ };
143+
32144const bool PerfCounters::kSupported = true ;
33145
34146bool PerfCounters::Initialize () { return pfm_initialize () == PFM_SUCCESS; }
@@ -38,35 +150,28 @@ PerfCounters PerfCounters::Create(
38150 if (counter_names.empty ()) {
39151 return NoCounters ();
40152 }
41- if (counter_names.size () > PerfCounterValues::kMaxCounters ) {
42- GetErrorLogInstance ()
43- << counter_names.size ()
44- << " counters were requested. The minimum is 1, the maximum is "
45- << PerfCounterValues::kMaxCounters << " \n " ;
46- return NoCounters ();
47- }
153+
48154 std::vector<int > counter_ids (counter_names.size ());
155+ PMURegistry registry{};
49156
50- const int mode = PFM_PLM3; // user mode only
51157 for (size_t i = 0 ; i < counter_names.size (); ++i) {
52- const bool is_first = i == 0 ;
53- struct perf_event_attr attr {};
54- attr.size = sizeof (attr);
55- const int group_id = !is_first ? counter_ids[0 ] : -1 ;
56158 const auto & name = counter_names[i];
57159 if (name.empty ()) {
58160 GetErrorLogInstance () << " A counter name was the empty string\n " ;
59161 return NoCounters ();
60162 }
61- pfm_perf_encode_arg_t arg{};
62- arg.attr = &attr;
63163
64- const int pfm_get =
65- pfm_get_os_event_encoding (name.c_str (), mode, PFM_OS_PERF_EVENT, &arg);
66- if (pfm_get != PFM_SUCCESS) {
67- GetErrorLogInstance () << " Unknown counter name: " << name << " \n " ;
164+ struct perf_event_attr attr {};
165+ auto ok = registry.EnlistCounter (name, attr);
166+
167+ if (!ok) {
168+ GetErrorLogInstance () << " Failed to register counter: " << name << " \n " ;
68169 return NoCounters ();
69170 }
171+
172+ const bool is_first = i == 0 ;
173+ const int group_id = !is_first ? counter_ids[0 ] : -1 ;
174+
70175 attr.disabled = is_first;
71176 // Note: the man page for perf_event_create suggests inerit = true and
72177 // read_format = PERF_FORMAT_GROUP don't work together, but that's not the
0 commit comments