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