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