[docs] Add LICENSE.txt to the root of the mono-repo
[llvm-project.git] / third-party / benchmark / test / perf_counters_gtest.cc
blob3eac62463bc5b3057d4a30027f4da5e5b3166fbb
1 #include <thread>
3 #include "../src/perf_counters.h"
4 #include "gtest/gtest.h"
6 #ifndef GTEST_SKIP
7 struct MsgHandler {
8 void operator=(std::ostream&) {}
9 };
10 #define GTEST_SKIP() return MsgHandler() = std::cout
11 #endif
13 using benchmark::internal::PerfCounters;
14 using benchmark::internal::PerfCounterValues;
16 namespace {
17 const char kGenericPerfEvent1[] = "CYCLES";
18 const char kGenericPerfEvent2[] = "BRANCHES";
19 const char kGenericPerfEvent3[] = "INSTRUCTIONS";
21 TEST(PerfCountersTest, Init) {
22 EXPECT_EQ(PerfCounters::Initialize(), PerfCounters::kSupported);
25 TEST(PerfCountersTest, OneCounter) {
26 if (!PerfCounters::kSupported) {
27 GTEST_SKIP() << "Performance counters not supported.\n";
29 EXPECT_TRUE(PerfCounters::Initialize());
30 EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1}).IsValid());
33 TEST(PerfCountersTest, NegativeTest) {
34 if (!PerfCounters::kSupported) {
35 EXPECT_FALSE(PerfCounters::Initialize());
36 return;
38 EXPECT_TRUE(PerfCounters::Initialize());
39 EXPECT_FALSE(PerfCounters::Create({}).IsValid());
40 EXPECT_FALSE(PerfCounters::Create({""}).IsValid());
41 EXPECT_FALSE(PerfCounters::Create({"not a counter name"}).IsValid());
43 EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2,
44 kGenericPerfEvent3})
45 .IsValid());
47 EXPECT_FALSE(
48 PerfCounters::Create({kGenericPerfEvent2, "", kGenericPerfEvent1})
49 .IsValid());
50 EXPECT_FALSE(PerfCounters::Create({kGenericPerfEvent3, "not a counter name",
51 kGenericPerfEvent1})
52 .IsValid());
54 EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2,
55 kGenericPerfEvent3})
56 .IsValid());
58 EXPECT_FALSE(
59 PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2,
60 kGenericPerfEvent3, "MISPREDICTED_BRANCH_RETIRED"})
61 .IsValid());
64 TEST(PerfCountersTest, Read1Counter) {
65 if (!PerfCounters::kSupported) {
66 GTEST_SKIP() << "Test skipped because libpfm is not supported.\n";
68 EXPECT_TRUE(PerfCounters::Initialize());
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]);
80 TEST(PerfCountersTest, Read2Counters) {
81 if (!PerfCounters::kSupported) {
82 GTEST_SKIP() << "Test skipped because libpfm is not supported.\n";
84 EXPECT_TRUE(PerfCounters::Initialize());
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);
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;
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); };
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);
124 TEST(PerfCountersTest, MultiThreaded) {
125 if (!PerfCounters::kSupported) {
126 GTEST_SKIP() << "Test skipped because libpfm is not supported.";
128 EXPECT_TRUE(PerfCounters::Initialize());
129 PerfCounterValues values1(2);
130 PerfCounterValues values2(2);
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])};
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])};
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]);
145 } // namespace