Index: webrtc/base/criticalsection_unittest.cc |
diff --git a/webrtc/base/criticalsection_unittest.cc b/webrtc/base/criticalsection_unittest.cc |
index d6990c0023d8b02a33a97abdfce4da99ded00bc4..a0e103386280dbfd8cef4e5d8c2bd0fe1beb0f60 100644 |
--- a/webrtc/base/criticalsection_unittest.cc |
+++ b/webrtc/base/criticalsection_unittest.cc |
@@ -11,9 +11,12 @@ |
#include <set> |
#include <vector> |
+#include "webrtc/base/arraysize.h" |
+#include "webrtc/base/checks.h" |
#include "webrtc/base/criticalsection.h" |
#include "webrtc/base/event.h" |
#include "webrtc/base/gunit.h" |
+#include "webrtc/base/platform_thread.h" |
#include "webrtc/base/scoped_ptr.h" |
#include "webrtc/base/scopedptrcollection.h" |
#include "webrtc/base/thread.h" |
@@ -320,4 +323,109 @@ TEST(CriticalSectionTest, IsLocked) { |
} |
#endif |
+class PerfTestData { |
+ public: |
+ PerfTestData(int expected_count, Event* event) |
+ : cache_line_barrier_1_(), cache_line_barrier_2_(), |
+ expected_count_(expected_count), event_(event) { |
+ cache_line_barrier_1_[0]++; // Avoid 'is not used'. |
+ cache_line_barrier_2_[0]++; // Avoid 'is not used'. |
+ } |
+ ~PerfTestData() {} |
+ |
+ void AddToCounter(int add) { |
+ rtc::CritScope cs(&lock_); |
+ my_counter_ += add; |
+ if (my_counter_ == expected_count_) |
+ event_->Set(); |
+ } |
+ |
+ int64_t total() const { |
+ // Assume that only one thread is running now. |
+ return my_counter_; |
+ } |
+ |
+ private: |
+ uint8_t cache_line_barrier_1_[64]; |
+ CriticalSection lock_; |
+ uint8_t cache_line_barrier_2_[64]; |
+ int64_t my_counter_ = 0; |
+ const int expected_count_; |
+ Event* const event_; |
+}; |
+ |
+class PerfTestThread { |
+ public: |
+ PerfTestThread() : thread_(&ThreadFunc, this, "CsPerf") {} |
+ |
+ void Start(PerfTestData* data, int repeats, int id) { |
+ RTC_DCHECK(!thread_.IsRunning()); |
+ RTC_DCHECK(!data_); |
+ data_ = data; |
+ repeats_ = repeats; |
+ my_id_ = id; |
+ thread_.Start(); |
+ } |
+ |
+ void Stop() { |
+ RTC_DCHECK(thread_.IsRunning()); |
+ RTC_DCHECK(data_); |
+ thread_.Stop(); |
+ repeats_ = 0; |
+ data_ = nullptr; |
+ my_id_ = 0; |
+ } |
+ |
+ private: |
+ static bool ThreadFunc(void* param) { |
+ PerfTestThread* me = static_cast<PerfTestThread*>(param); |
+ for (int i = 0; i < me->repeats_; ++i) |
+ me->data_->AddToCounter(me->my_id_); |
+ return false; |
+ } |
+ |
+ PlatformThread thread_; |
+ PerfTestData* data_ = nullptr; |
+ int repeats_ = 0; |
+ int my_id_ = 0; |
+}; |
+ |
+// Comparison of output of this test as tested on a MacBook Pro Retina, 15-inch, |
+// Mid 2014, 2,8 GHz Intel Core i7, 16 GB 1600 MHz DDR3, |
+// running OS X El Capitan, 10.11.2. |
+// |
+// Native mutex implementation: |
+// Approximate CPU usage: |
+// System: ~16% |
+// User mode: ~1.3% |
+// Idle: ~82% |
+// Unit test output: |
+// [ OK ] CriticalSectionTest.Performance (234545 ms) |
+// |
+// Special partially spin lock based implementation: |
+// Approximate CPU usage: |
+// System: ~75% |
+// User mode: ~16% |
+// Idle: ~8% |
+// Unit test output: |
+// [ OK ] CriticalSectionTest.Performance (2107 ms) |
+// |
+// The test is disabled by default to avoid unecessarily loading the bots. |
+TEST(CriticalSectionTest, DISABLED_Performance) { |
+ PerfTestThread threads[8]; |
+ Event event(false, false); |
+ |
+ static const int kThreadRepeats = 10000000; |
+ static const int kExpectedCount = kThreadRepeats * arraysize(threads); |
+ PerfTestData test_data(kExpectedCount, &event); |
+ |
+ for (auto& t : threads) |
+ t.Start(&test_data, kThreadRepeats, 1); |
+ |
+ event.Wait(Event::kForever); |
+ |
+ for (auto& t : threads) |
+ t.Stop(); |
+} |
+ |
} // namespace rtc |