lock_perftest.cc 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/compiler_specific.h"
  5. #include "base/memory/raw_ptr.h"
  6. #include "base/synchronization/lock.h"
  7. #include "base/threading/platform_thread.h"
  8. #include "base/time/time.h"
  9. #include "base/timer/lap_timer.h"
  10. #include "testing/gtest/include/gtest/gtest.h"
  11. #include "testing/perf/perf_result_reporter.h"
  12. namespace base {
  13. namespace {
  14. constexpr int kWarmupRuns = 1;
  15. constexpr TimeDelta kTimeLimit = Seconds(1);
  16. constexpr int kTimeCheckInterval = 100000;
  17. constexpr char kMetricPrefixLock[] = "Lock.";
  18. constexpr char kMetricLockUnlockThroughput[] = "lock_unlock_throughput";
  19. constexpr char kStoryBaseline[] = "baseline_story";
  20. constexpr char kStoryWithCompetingThread[] = "with_competing_thread";
  21. perf_test::PerfResultReporter SetUpReporter(const std::string& story_name) {
  22. perf_test::PerfResultReporter reporter(kMetricPrefixLock, story_name);
  23. reporter.RegisterImportantMetric(kMetricLockUnlockThroughput, "runs/s");
  24. return reporter;
  25. }
  26. class Spin : public PlatformThread::Delegate {
  27. public:
  28. Spin(Lock* lock, uint32_t* data)
  29. : lock_(lock), data_(data), should_stop_(false) {}
  30. ~Spin() override = default;
  31. void ThreadMain() override {
  32. // Local variable to avoid "cache line ping-pong" from influencing the
  33. // results.
  34. uint32_t count = 0;
  35. while (!should_stop_.load(std::memory_order_relaxed)) {
  36. lock_->Acquire();
  37. count++;
  38. lock_->Release();
  39. }
  40. lock_->Acquire();
  41. (*data_) += count;
  42. lock_->Release();
  43. }
  44. // Called from another thread to stop the loop.
  45. void Stop() { should_stop_ = true; }
  46. private:
  47. raw_ptr<Lock> lock_;
  48. raw_ptr<uint32_t> data_ GUARDED_BY(lock_);
  49. std::atomic<bool> should_stop_;
  50. };
  51. } // namespace
  52. TEST(LockPerfTest, Simple) {
  53. LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval);
  54. [[maybe_unused]] uint32_t data = 0;
  55. Lock lock;
  56. do {
  57. lock.Acquire();
  58. data += 1;
  59. lock.Release();
  60. timer.NextLap();
  61. } while (!timer.HasTimeLimitExpired());
  62. auto reporter = SetUpReporter(kStoryBaseline);
  63. reporter.AddResult(kMetricLockUnlockThroughput, timer.LapsPerSecond());
  64. }
  65. TEST(LockPerfTest, WithCompetingThread) {
  66. LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval);
  67. uint32_t data = 0;
  68. Lock lock;
  69. // Starts a competing thread executing the same loop as this thread.
  70. Spin thread_main(&lock, &data);
  71. PlatformThreadHandle thread_handle;
  72. ASSERT_TRUE(PlatformThread::Create(0, &thread_main, &thread_handle));
  73. do {
  74. lock.Acquire();
  75. data += 1;
  76. lock.Release();
  77. timer.NextLap();
  78. } while (!timer.HasTimeLimitExpired());
  79. thread_main.Stop();
  80. PlatformThread::Join(thread_handle);
  81. auto reporter = SetUpReporter(kStoryWithCompetingThread);
  82. reporter.AddResult(kMetricLockUnlockThroughput, timer.LapsPerSecond());
  83. }
  84. } // namespace base