26
26
namespace benchmark {
27
27
namespace internal {
28
28
29
- constexpr size_t PerfCounterValues::kMaxCounters ;
30
-
31
29
#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
+
32
144
const bool PerfCounters::kSupported = true ;
33
145
34
146
bool PerfCounters::Initialize () { return pfm_initialize () == PFM_SUCCESS; }
@@ -38,35 +150,28 @@ PerfCounters PerfCounters::Create(
38
150
if (counter_names.empty ()) {
39
151
return NoCounters ();
40
152
}
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
+
48
154
std::vector<int > counter_ids (counter_names.size ());
155
+ PMURegistry registry{};
49
156
50
- const int mode = PFM_PLM3; // user mode only
51
157
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 ;
56
158
const auto & name = counter_names[i];
57
159
if (name.empty ()) {
58
160
GetErrorLogInstance () << " A counter name was the empty string\n " ;
59
161
return NoCounters ();
60
162
}
61
- pfm_perf_encode_arg_t arg{};
62
- arg.attr = &attr;
63
163
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 " ;
68
169
return NoCounters ();
69
170
}
171
+
172
+ const bool is_first = i == 0 ;
173
+ const int group_id = !is_first ? counter_ids[0 ] : -1 ;
174
+
70
175
attr.disabled = is_first;
71
176
// Note: the man page for perf_event_create suggests inerit = true and
72
177
// read_format = PERF_FORMAT_GROUP don't work together, but that's not the
0 commit comments