3 #include "../src/perf_counters.h"
4 #include "gtest/gtest.h"
8 void operator=(std::ostream
&) {}
10 #define GTEST_SKIP() return MsgHandler() = std::cout
13 using benchmark::internal::PerfCounters
;
14 using benchmark::internal::PerfCounterValues
;
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());
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
,
48 PerfCounters::Create({kGenericPerfEvent2
, "", kGenericPerfEvent1
})
50 EXPECT_FALSE(PerfCounters::Create({kGenericPerfEvent3
, "not a counter name",
54 EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1
, kGenericPerfEvent2
,
59 PerfCounters::Create({kGenericPerfEvent1
, kGenericPerfEvent2
,
60 kGenericPerfEvent3
, "MISPREDICTED_BRANCH_RETIRED"})
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());
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);
100 for (size_t i
= 0; i
< 100000000; ++i
) res
+= i
* i
;
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
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]);