OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2014 The WebRTC Project Authors. All rights reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <set> | 11 #include <set> |
12 #include <vector> | 12 #include <vector> |
13 | 13 |
| 14 #include "webrtc/base/arraysize.h" |
| 15 #include "webrtc/base/checks.h" |
14 #include "webrtc/base/criticalsection.h" | 16 #include "webrtc/base/criticalsection.h" |
15 #include "webrtc/base/event.h" | 17 #include "webrtc/base/event.h" |
16 #include "webrtc/base/gunit.h" | 18 #include "webrtc/base/gunit.h" |
| 19 #include "webrtc/base/platform_thread.h" |
17 #include "webrtc/base/scoped_ptr.h" | 20 #include "webrtc/base/scoped_ptr.h" |
18 #include "webrtc/base/scopedptrcollection.h" | 21 #include "webrtc/base/scopedptrcollection.h" |
19 #include "webrtc/base/thread.h" | 22 #include "webrtc/base/thread.h" |
20 | 23 |
21 namespace rtc { | 24 namespace rtc { |
22 | 25 |
23 namespace { | 26 namespace { |
24 | 27 |
25 const int kLongTime = 10000; // 10 seconds | 28 const int kLongTime = 10000; // 10 seconds |
26 const int kNumThreads = 16; | 29 const int kNumThreads = 16; |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 cs.Leave(); | 316 cs.Leave(); |
314 EXPECT_FALSE(cs.IsLocked()); | 317 EXPECT_FALSE(cs.IsLocked()); |
315 if (!cs.TryEnter()) | 318 if (!cs.TryEnter()) |
316 FAIL(); | 319 FAIL(); |
317 EXPECT_TRUE(cs.IsLocked()); | 320 EXPECT_TRUE(cs.IsLocked()); |
318 cs.Leave(); | 321 cs.Leave(); |
319 EXPECT_FALSE(cs.IsLocked()); | 322 EXPECT_FALSE(cs.IsLocked()); |
320 } | 323 } |
321 #endif | 324 #endif |
322 | 325 |
| 326 class PerfTestData { |
| 327 public: |
| 328 PerfTestData(int expected_count, Event* event) |
| 329 : cache_line_barrier_1_(), cache_line_barrier_2_(), |
| 330 expected_count_(expected_count), event_(event) { |
| 331 cache_line_barrier_1_[0]++; // Avoid 'is not used'. |
| 332 cache_line_barrier_2_[0]++; // Avoid 'is not used'. |
| 333 } |
| 334 ~PerfTestData() {} |
| 335 |
| 336 void AddToCounter(int add) { |
| 337 rtc::CritScope cs(&lock_); |
| 338 my_counter_ += add; |
| 339 if (my_counter_ == expected_count_) |
| 340 event_->Set(); |
| 341 } |
| 342 |
| 343 int64_t total() const { |
| 344 // Assume that only one thread is running now. |
| 345 return my_counter_; |
| 346 } |
| 347 |
| 348 private: |
| 349 uint8_t cache_line_barrier_1_[64]; |
| 350 CriticalSection lock_; |
| 351 uint8_t cache_line_barrier_2_[64]; |
| 352 int64_t my_counter_ = 0; |
| 353 const int expected_count_; |
| 354 Event* const event_; |
| 355 }; |
| 356 |
| 357 class PerfTestThread { |
| 358 public: |
| 359 PerfTestThread() : thread_(&ThreadFunc, this, "CsPerf") {} |
| 360 |
| 361 void Start(PerfTestData* data, int repeats, int id) { |
| 362 RTC_DCHECK(!thread_.IsRunning()); |
| 363 RTC_DCHECK(!data_); |
| 364 data_ = data; |
| 365 repeats_ = repeats; |
| 366 my_id_ = id; |
| 367 thread_.Start(); |
| 368 } |
| 369 |
| 370 void Stop() { |
| 371 RTC_DCHECK(thread_.IsRunning()); |
| 372 RTC_DCHECK(data_); |
| 373 thread_.Stop(); |
| 374 repeats_ = 0; |
| 375 data_ = nullptr; |
| 376 my_id_ = 0; |
| 377 } |
| 378 |
| 379 private: |
| 380 static bool ThreadFunc(void* param) { |
| 381 PerfTestThread* me = static_cast<PerfTestThread*>(param); |
| 382 for (int i = 0; i < me->repeats_; ++i) |
| 383 me->data_->AddToCounter(me->my_id_); |
| 384 return false; |
| 385 } |
| 386 |
| 387 PlatformThread thread_; |
| 388 PerfTestData* data_ = nullptr; |
| 389 int repeats_ = 0; |
| 390 int my_id_ = 0; |
| 391 }; |
| 392 |
| 393 // Comparison of output of this test as tested on a MacBook Pro Retina, 15-inch, |
| 394 // Mid 2014, 2,8 GHz Intel Core i7, 16 GB 1600 MHz DDR3, |
| 395 // running OS X El Capitan, 10.11.2. |
| 396 // |
| 397 // Native mutex implementation: |
| 398 // Approximate CPU usage: |
| 399 // System: ~16% |
| 400 // User mode: ~1.3% |
| 401 // Idle: ~82% |
| 402 // Unit test output: |
| 403 // [ OK ] CriticalSectionTest.Performance (234545 ms) |
| 404 // |
| 405 // Special partially spin lock based implementation: |
| 406 // Approximate CPU usage: |
| 407 // System: ~75% |
| 408 // User mode: ~16% |
| 409 // Idle: ~8% |
| 410 // Unit test output: |
| 411 // [ OK ] CriticalSectionTest.Performance (2107 ms) |
| 412 // |
| 413 // The test is disabled by default to avoid unecessarily loading the bots. |
| 414 TEST(CriticalSectionTest, DISABLED_Performance) { |
| 415 PerfTestThread threads[8]; |
| 416 Event event(false, false); |
| 417 |
| 418 static const int kThreadRepeats = 10000000; |
| 419 static const int kExpectedCount = kThreadRepeats * arraysize(threads); |
| 420 PerfTestData test_data(kExpectedCount, &event); |
| 421 |
| 422 for (auto& t : threads) |
| 423 t.Start(&test_data, kThreadRepeats, 1); |
| 424 |
| 425 event.Wait(Event::kForever); |
| 426 |
| 427 for (auto& t : threads) |
| 428 t.Stop(); |
| 429 } |
| 430 |
323 } // namespace rtc | 431 } // namespace rtc |
OLD | NEW |