perf_counters.cc
Go to the documentation of this file.
1 // Copyright 2021 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "perf_counters.h"
16 
17 #include <cstring>
18 #include <vector>
19 
20 #if defined HAVE_LIBPFM
21 #include "perfmon/pfmlib.h"
22 #include "perfmon/pfmlib_perf_event.h"
23 #endif
24 
25 namespace benchmark {
26 namespace internal {
27 
28 constexpr size_t PerfCounterValues::kMaxCounters;
29 
30 #if defined HAVE_LIBPFM
31 const bool PerfCounters::kSupported = true;
32 
33 bool PerfCounters::Initialize() { return pfm_initialize() == PFM_SUCCESS; }
34 
35 PerfCounters PerfCounters::Create(
36  const std::vector<std::string>& counter_names) {
37  if (counter_names.empty()) {
38  return NoCounters();
39  }
40  if (counter_names.size() > PerfCounterValues::kMaxCounters) {
42  << counter_names.size()
43  << " counters were requested. The minimum is 1, the maximum is "
45  return NoCounters();
46  }
47  std::vector<int> counter_ids(counter_names.size());
48 
49  const int mode = PFM_PLM3; // user mode only
50  for (size_t i = 0; i < counter_names.size(); ++i) {
51  const bool is_first = i == 0;
52  struct perf_event_attr attr{};
53  attr.size = sizeof(attr);
54  const int group_id = !is_first ? counter_ids[0] : -1;
55  const auto& name = counter_names[i];
56  if (name.empty()) {
57  GetErrorLogInstance() << "A counter name was the empty string\n";
58  return NoCounters();
59  }
60  pfm_perf_encode_arg_t arg{};
61  arg.attr = &attr;
62 
63  const int pfm_get =
64  pfm_get_os_event_encoding(name.c_str(), mode, PFM_OS_PERF_EVENT, &arg);
65  if (pfm_get != PFM_SUCCESS) {
66  GetErrorLogInstance() << "Unknown counter name: " << name << "\n";
67  return NoCounters();
68  }
69  attr.disabled = is_first;
70  // Note: the man page for perf_event_create suggests inerit = true and
71  // read_format = PERF_FORMAT_GROUP don't work together, but that's not the
72  // case.
73  attr.inherit = true;
74  attr.pinned = is_first;
75  attr.exclude_kernel = true;
76  attr.exclude_user = false;
77  attr.exclude_hv = true;
78  // Read all counters in one read.
79  attr.read_format = PERF_FORMAT_GROUP;
80 
81  int id = -1;
82  static constexpr size_t kNrOfSyscallRetries = 5;
83  // Retry syscall as it was interrupted often (b/64774091).
84  for (size_t num_retries = 0; num_retries < kNrOfSyscallRetries;
85  ++num_retries) {
86  id = perf_event_open(&attr, 0, -1, group_id, 0);
87  if (id >= 0 || errno != EINTR) {
88  break;
89  }
90  }
91  if (id < 0) {
93  << "Failed to get a file descriptor for " << name << "\n";
94  return NoCounters();
95  }
96 
97  counter_ids[i] = id;
98  }
99  if (ioctl(counter_ids[0], PERF_EVENT_IOC_ENABLE) != 0) {
100  GetErrorLogInstance() << "Failed to start counters\n";
101  return NoCounters();
102  }
103 
104  return PerfCounters(counter_names, std::move(counter_ids));
105 }
106 
108  if (counter_ids_.empty()) {
109  return;
110  }
111  ioctl(counter_ids_[0], PERF_EVENT_IOC_DISABLE);
112  for (int fd : counter_ids_) {
113  close(fd);
114  }
115 }
116 #else // defined HAVE_LIBPFM
117 const bool PerfCounters::kSupported = false;
118 
119 bool PerfCounters::Initialize() { return false; }
120 
122  const std::vector<std::string>& counter_names) {
123  if (!counter_names.empty()) {
124  GetErrorLogInstance() << "Performance counters not supported.";
125  }
126  return NoCounters();
127 }
128 
129 PerfCounters::~PerfCounters() = default;
130 #endif // defined HAVE_LIBPFM
131 } // namespace internal
132 } // namespace benchmark
benchmark::internal::PerfCounters::counter_ids_
std::vector< int > counter_ids_
Definition: perf_counters.h:119
benchmark::internal::GetErrorLogInstance
LogType & GetErrorLogInstance()
Definition: third_party/benchmark/src/log.h:54
benchmark
Definition: bm_alarm.cc:55
benchmark::internal::PerfCounters::Initialize
static bool Initialize()
Definition: perf_counters.cc:119
mode
const char int mode
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:135
setup.name
name
Definition: setup.py:542
benchmark::internal::PerfCounters::PerfCounters
PerfCounters()
Definition: perf_counters.h:117
benchmark::internal::PerfCounters::kSupported
static const bool kSupported
Definition: perf_counters.h:72
perf_counters.h
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
benchmark::internal::PerfCounters::Create
static PerfCounters Create(const std::vector< std::string > &counter_names)
Definition: perf_counters.cc:121
arg
Definition: cmdline.cc:40
close
#define close
Definition: test-fs.c:48
benchmark::internal::PerfCounters::~PerfCounters
~PerfCounters()
benchmark::internal::PerfCounterValues::kMaxCounters
static constexpr size_t kMaxCounters
Definition: perf_counters.h:50
benchmark::internal::PerfCounters::NoCounters
static PerfCounters NoCounters()
Definition: perf_counters.h:75
attr
OPENSSL_EXPORT X509_ATTRIBUTE * attr
Definition: x509.h:1666
benchmark::internal::PerfCounters
Definition: perf_counters.h:69
internal
Definition: benchmark/test/output_test_helper.cc:20
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
id
uint32_t id
Definition: flow_control_fuzzer.cc:70


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:42