perf_counters_gtest.cc 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #include <thread>
  2. #include "../src/perf_counters.h"
  3. #include "gtest/gtest.h"
  4. #ifndef GTEST_SKIP
  5. struct MsgHandler {
  6. void operator=(std::ostream&){}
  7. };
  8. #define GTEST_SKIP() return MsgHandler() = std::cout
  9. #endif
  10. using benchmark::internal::PerfCounters;
  11. using benchmark::internal::PerfCounterValues;
  12. namespace {
  13. const char kGenericPerfEvent1[] = "CYCLES";
  14. const char kGenericPerfEvent2[] = "BRANCHES";
  15. const char kGenericPerfEvent3[] = "INSTRUCTIONS";
  16. TEST(PerfCountersTest, Init) {
  17. EXPECT_EQ(PerfCounters::Initialize(), PerfCounters::kSupported);
  18. }
  19. TEST(PerfCountersTest, OneCounter) {
  20. if (!PerfCounters::kSupported) {
  21. GTEST_SKIP() << "Performance counters not supported.\n";
  22. }
  23. EXPECT_TRUE(PerfCounters::Initialize());
  24. EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1}).IsValid());
  25. }
  26. TEST(PerfCountersTest, NegativeTest) {
  27. if (!PerfCounters::kSupported) {
  28. EXPECT_FALSE(PerfCounters::Initialize());
  29. return;
  30. }
  31. EXPECT_TRUE(PerfCounters::Initialize());
  32. EXPECT_FALSE(PerfCounters::Create({}).IsValid());
  33. EXPECT_FALSE(PerfCounters::Create({""}).IsValid());
  34. EXPECT_FALSE(PerfCounters::Create({"not a counter name"}).IsValid());
  35. {
  36. EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2,
  37. kGenericPerfEvent3})
  38. .IsValid());
  39. }
  40. EXPECT_FALSE(
  41. PerfCounters::Create({kGenericPerfEvent2, "", kGenericPerfEvent1})
  42. .IsValid());
  43. EXPECT_FALSE(PerfCounters::Create({kGenericPerfEvent3, "not a counter name",
  44. kGenericPerfEvent1})
  45. .IsValid());
  46. {
  47. EXPECT_TRUE(PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2,
  48. kGenericPerfEvent3})
  49. .IsValid());
  50. }
  51. EXPECT_FALSE(
  52. PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2,
  53. kGenericPerfEvent3, "MISPREDICTED_BRANCH_RETIRED"})
  54. .IsValid());
  55. }
  56. TEST(PerfCountersTest, Read1Counter) {
  57. if (!PerfCounters::kSupported) {
  58. GTEST_SKIP() << "Test skipped because libpfm is not supported.\n";
  59. }
  60. EXPECT_TRUE(PerfCounters::Initialize());
  61. auto counters = PerfCounters::Create({kGenericPerfEvent1});
  62. EXPECT_TRUE(counters.IsValid());
  63. PerfCounterValues values1(1);
  64. EXPECT_TRUE(counters.Snapshot(&values1));
  65. EXPECT_GT(values1[0], 0);
  66. PerfCounterValues values2(1);
  67. EXPECT_TRUE(counters.Snapshot(&values2));
  68. EXPECT_GT(values2[0], 0);
  69. EXPECT_GT(values2[0], values1[0]);
  70. }
  71. TEST(PerfCountersTest, Read2Counters) {
  72. if (!PerfCounters::kSupported) {
  73. GTEST_SKIP() << "Test skipped because libpfm is not supported.\n";
  74. }
  75. EXPECT_TRUE(PerfCounters::Initialize());
  76. auto counters =
  77. PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent2});
  78. EXPECT_TRUE(counters.IsValid());
  79. PerfCounterValues values1(2);
  80. EXPECT_TRUE(counters.Snapshot(&values1));
  81. EXPECT_GT(values1[0], 0);
  82. EXPECT_GT(values1[1], 0);
  83. PerfCounterValues values2(2);
  84. EXPECT_TRUE(counters.Snapshot(&values2));
  85. EXPECT_GT(values2[0], 0);
  86. EXPECT_GT(values2[1], 0);
  87. }
  88. size_t do_work() {
  89. size_t res = 0;
  90. for (size_t i = 0; i < 100000000; ++i) res += i * i;
  91. return res;
  92. }
  93. void measure(size_t threadcount, PerfCounterValues* values1,
  94. PerfCounterValues* values2) {
  95. BM_CHECK_NE(values1, nullptr);
  96. BM_CHECK_NE(values2, nullptr);
  97. std::vector<std::thread> threads(threadcount);
  98. auto work = [&]() { BM_CHECK(do_work() > 1000); };
  99. // We need to first set up the counters, then start the threads, so the
  100. // threads would inherit the counters. But later, we need to first destroy the
  101. // thread pool (so all the work finishes), then measure the counters. So the
  102. // scopes overlap, and we need to explicitly control the scope of the
  103. // threadpool.
  104. auto counters =
  105. PerfCounters::Create({kGenericPerfEvent1, kGenericPerfEvent3});
  106. for (auto& t : threads) t = std::thread(work);
  107. counters.Snapshot(values1);
  108. for (auto& t : threads) t.join();
  109. counters.Snapshot(values2);
  110. }
  111. TEST(PerfCountersTest, MultiThreaded) {
  112. if (!PerfCounters::kSupported) {
  113. GTEST_SKIP() << "Test skipped because libpfm is not supported.";
  114. }
  115. EXPECT_TRUE(PerfCounters::Initialize());
  116. PerfCounterValues values1(2);
  117. PerfCounterValues values2(2);
  118. measure(2, &values1, &values2);
  119. std::vector<double> D1{static_cast<double>(values2[0] - values1[0]),
  120. static_cast<double>(values2[1] - values1[1])};
  121. measure(4, &values1, &values2);
  122. std::vector<double> D2{static_cast<double>(values2[0] - values1[0]),
  123. static_cast<double>(values2[1] - values1[1])};
  124. // Some extra work will happen on the main thread - like joining the threads
  125. // - so the ratio won't be quite 2.0, but very close.
  126. EXPECT_GE(D2[0], 1.9 * D1[0]);
  127. EXPECT_GE(D2[1], 1.9 * D1[1]);
  128. }
  129. } // namespace