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