perf_counters_gtest.cc
Go to the documentation of this file.
1 #include <thread>
2 
3 #include "../src/perf_counters.h"
4 #include "gtest/gtest.h"
5 
6 #ifndef GTEST_SKIP
7 struct MsgHandler {
8  void operator=(std::ostream&){}
9 };
10 #define GTEST_SKIP() return MsgHandler() = std::cout
11 #endif
12 
15 
16 namespace {
17 const char kGenericPerfEvent1[] = "CYCLES";
18 const char kGenericPerfEvent2[] = "BRANCHES";
19 const char kGenericPerfEvent3[] = "INSTRUCTIONS";
20 
21 TEST(PerfCountersTest, Init) {
22  EXPECT_EQ(PerfCounters::Initialize(), PerfCounters::kSupported);
23 }
24 
25 TEST(PerfCountersTest, OneCounter) {
26  if (!PerfCounters::kSupported) {
27  GTEST_SKIP() << "Performance counters not supported.\n";
28  }
30  EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1}).IsValid());
31 }
32 
33 TEST(PerfCountersTest, NegativeTest) {
34  if (!PerfCounters::kSupported) {
36  return;
37  }
39  EXPECT_FALSE(PerfCounters::Create({}).IsValid());
40  EXPECT_FALSE(PerfCounters::Create({""}).IsValid());
41  EXPECT_FALSE(PerfCounters::Create({"not a counter name"}).IsValid());
42  {
43  EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2,
44  kGenericPerfEvent3})
45  .IsValid());
46  }
48  PerfCounters::Create({kGenericPerfEvent2, "", kGenericPerfEvent1})
49  .IsValid());
50  EXPECT_FALSE(PerfCounters::Create({kGenericPerfEvent3, "not a counter name",
51  kGenericPerfEvent1})
52  .IsValid());
53  {
54  EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2,
55  kGenericPerfEvent3})
56  .IsValid());
57  }
59  PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2,
60  kGenericPerfEvent3, "MISPREDICTED_BRANCH_RETIRED"})
61  .IsValid());
62 }
63 
64 TEST(PerfCountersTest, Read1Counter) {
65  if (!PerfCounters::kSupported) {
66  GTEST_SKIP() << "Test skipped because libpfm is not supported.\n";
67  }
69  auto counters = PerfCounters::Create({kGenericPerfEvent1});
70  EXPECT_TRUE(counters.IsValid());
71  PerfCounterValues values1(1);
72  EXPECT_TRUE(counters.Snapshot(&values1));
73  EXPECT_GT(values1[0], 0);
74  PerfCounterValues values2(1);
75  EXPECT_TRUE(counters.Snapshot(&values2));
76  EXPECT_GT(values2[0], 0);
77  EXPECT_GT(values2[0], values1[0]);
78 }
79 
80 TEST(PerfCountersTest, Read2Counters) {
81  if (!PerfCounters::kSupported) {
82  GTEST_SKIP() << "Test skipped because libpfm is not supported.\n";
83  }
85  auto counters =
86  PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2});
87  EXPECT_TRUE(counters.IsValid());
88  PerfCounterValues values1(2);
89  EXPECT_TRUE(counters.Snapshot(&values1));
90  EXPECT_GT(values1[0], 0);
91  EXPECT_GT(values1[1], 0);
92  PerfCounterValues values2(2);
93  EXPECT_TRUE(counters.Snapshot(&values2));
94  EXPECT_GT(values2[0], 0);
95  EXPECT_GT(values2[1], 0);
96 }
97 
98 size_t do_work() {
99  size_t res = 0;
100  for (size_t i = 0; i < 100000000; ++i) res += i * i;
101  return res;
102 }
103 
104 void measure(size_t threadcount, PerfCounterValues* values1,
105  PerfCounterValues* values2) {
106  BM_CHECK_NE(values1, nullptr);
107  BM_CHECK_NE(values2, nullptr);
108  std::vector<std::thread> threads(threadcount);
109  auto work = [&]() { BM_CHECK(do_work() > 1000); };
110 
111  // We need to first set up the counters, then start the threads, so the
112  // threads would inherit the counters. But later, we need to first destroy the
113  // thread pool (so all the work finishes), then measure the counters. So the
114  // scopes overlap, and we need to explicitly control the scope of the
115  // threadpool.
116  auto counters =
117  PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent3});
118  for (auto& t : threads) t = std::thread(work);
119  counters.Snapshot(values1);
120  for (auto& t : threads) t.join();
121  counters.Snapshot(values2);
122 }
123 
124 TEST(PerfCountersTest, MultiThreaded) {
125  if (!PerfCounters::kSupported) {
126  GTEST_SKIP() << "Test skipped because libpfm is not supported.";
127  }
129  PerfCounterValues values1(2);
130  PerfCounterValues values2(2);
131 
132  measure(2, &values1, &values2);
133  std::vector<double> D1{static_cast<double>(values2[0] - values1[0]),
134  static_cast<double>(values2[1] - values1[1])};
135 
136  measure(4, &values1, &values2);
137  std::vector<double> D2{static_cast<double>(values2[0] - values1[0]),
138  static_cast<double>(values2[1] - values1[1])};
139 
140  // Some extra work will happen on the main thread - like joining the threads
141  // - so the ratio won't be quite 2.0, but very close.
142  EXPECT_GE(D2[0], 1.9 * D1[0]);
143  EXPECT_GE(D2[1], 1.9 * D1[1]);
144 }
145 } // namespace
EXPECT_FALSE
#define EXPECT_FALSE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1970
BM_CHECK
#define BM_CHECK(b)
Definition: benchmark/src/check.h:58
EXPECT_GT
#define EXPECT_GT(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2036
google::protobuf::python::cmessage::Init
static int Init(CMessage *self, PyObject *args, PyObject *kwargs)
Definition: bloaty/third_party/protobuf/python/google/protobuf/pyext/message.cc:1287
GTEST_SKIP
#define GTEST_SKIP()
Definition: perf_counters_gtest.cc:10
threads
static uv_thread_t * threads
Definition: threadpool.c:38
EXPECT_EQ
#define EXPECT_EQ(a, b)
Definition: iomgr/time_averaged_stats_test.cc:27
TEST
#define TEST(name, init_size,...)
Definition: arena_test.cc:75
MsgHandler::operator=
void operator=(std::ostream &)
Definition: perf_counters_gtest.cc:8
BM_CHECK_NE
#define BM_CHECK_NE(a, b)
Definition: benchmark/src/check.h:69
do_work
static void do_work(void *arg)
Definition: test-thread.c:111
MsgHandler
Definition: perf_counters_gtest.cc:7
benchmark::Initialize
void Initialize(int *argc, char **argv)
Definition: benchmark/src/benchmark.cc:602
EXPECT_GE
#define EXPECT_GE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2034
benchmark::internal::PerfCounters
Definition: perf_counters.h:69
benchmark::internal::PerfCounterValues
Definition: perf_counters.h:42
EXPECT_TRUE
#define EXPECT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1967
thread
static uv_thread_t thread
Definition: test-async-null-cb.c:29
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230


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