LCOV - code coverage report
Current view: top level - test/unittests/heap - barrier-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 60 60 100.0 %
Date: 2019-04-17 Functions: 15 24 62.5 %

          Line data    Source code
       1             : // Copyright 2017 the V8 project 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             : 
       5             : #include "src/heap/barrier.h"
       6             : #include "src/base/platform/platform.h"
       7             : #include "src/base/platform/time.h"
       8             : #include "testing/gtest/include/gtest/gtest.h"
       9             : 
      10             : namespace v8 {
      11             : namespace internal {
      12             : namespace heap {
      13             : 
      14             : namespace {
      15             : 
      16             : // Large timeout that will not trigger in tests.
      17             : constexpr base::TimeDelta test_timeout = base::TimeDelta::FromHours(3);
      18             : 
      19             : }  // namespace
      20             : 
      21       15443 : TEST(OneshotBarrier, InitializeNotDone) {
      22             :   OneshotBarrier barrier(test_timeout);
      23             :   EXPECT_FALSE(barrier.DoneForTesting());
      24           1 : }
      25             : 
      26       15443 : TEST(OneshotBarrier, DoneAfterWait_Sequential) {
      27             :   OneshotBarrier barrier(test_timeout);
      28             :   barrier.Start();
      29           1 :   barrier.Wait();
      30           1 :   EXPECT_TRUE(barrier.DoneForTesting());
      31           1 : }
      32             : 
      33             : namespace {
      34             : 
      35           4 : class ThreadWaitingOnBarrier final : public base::Thread {
      36             :  public:
      37             :   ThreadWaitingOnBarrier()
      38           4 :       : base::Thread(Options("ThreadWaitingOnBarrier")), barrier_(nullptr) {}
      39             : 
      40           4 :   void Initialize(OneshotBarrier* barrier) { barrier_ = barrier; }
      41             : 
      42           4 :   void Run() final { barrier_->Wait(); }
      43             : 
      44             :  private:
      45             :   OneshotBarrier* barrier_;
      46             : };
      47             : 
      48             : }  // namespace
      49             : 
      50       15443 : TEST(OneshotBarrier, DoneAfterWait_Concurrent) {
      51             :   const int kThreadCount = 2;
      52             :   OneshotBarrier barrier(test_timeout);
      53           8 :   ThreadWaitingOnBarrier threads[kThreadCount];
      54           5 :   for (int i = 0; i < kThreadCount; i++) {
      55           2 :     threads[i].Initialize(&barrier);
      56             :     // All threads need to call Wait() to be done.
      57             :     barrier.Start();
      58             :   }
      59           5 :   for (int i = 0; i < kThreadCount; i++) {
      60           2 :     threads[i].Start();
      61             :   }
      62           5 :   for (int i = 0; i < kThreadCount; i++) {
      63           2 :     threads[i].Join();
      64             :   }
      65           1 :   EXPECT_TRUE(barrier.DoneForTesting());
      66           1 : }
      67             : 
      68       15443 : TEST(OneshotBarrier, EarlyFinish_Concurrent) {
      69             :   const int kThreadCount = 2;
      70             :   OneshotBarrier barrier(test_timeout);
      71           8 :   ThreadWaitingOnBarrier threads[kThreadCount];
      72             :   // Test that one thread that actually finishes processing work before other
      73             :   // threads call Start() will move the barrier in Done state.
      74             :   barrier.Start();
      75           1 :   barrier.Wait();
      76           1 :   EXPECT_TRUE(barrier.DoneForTesting());
      77           5 :   for (int i = 0; i < kThreadCount; i++) {
      78           2 :     threads[i].Initialize(&barrier);
      79             :     // All threads need to call Wait() to be done.
      80             :     barrier.Start();
      81             :   }
      82           5 :   for (int i = 0; i < kThreadCount; i++) {
      83           2 :     threads[i].Start();
      84             :   }
      85           5 :   for (int i = 0; i < kThreadCount; i++) {
      86           2 :     threads[i].Join();
      87             :   }
      88           1 :   EXPECT_TRUE(barrier.DoneForTesting());
      89           1 : }
      90             : 
      91             : namespace {
      92             : 
      93           1 : class CountingThread final : public base::Thread {
      94             :  public:
      95             :   CountingThread(OneshotBarrier* barrier, base::Mutex* mutex, size_t* work)
      96             :       : base::Thread(Options("CountingThread")),
      97             :         barrier_(barrier),
      98             :         mutex_(mutex),
      99             :         work_(work),
     100           1 :         processed_work_(0) {}
     101             : 
     102           1 :   void Run() final {
     103        6016 :     do {
     104        6016 :       ProcessWork();
     105        6016 :     } while (!barrier_->Wait());
     106             :     // Main thread is not processing work, so we need one last step.
     107           1 :     ProcessWork();
     108           1 :   }
     109             : 
     110             :   size_t processed_work() const { return processed_work_; }
     111             : 
     112             :  private:
     113        6017 :   void ProcessWork() {
     114        6017 :     base::MutexGuard guard(mutex_);
     115        6017 :     processed_work_ += *work_;
     116        6017 :     *work_ = 0;
     117        6017 :   }
     118             : 
     119             :   OneshotBarrier* const barrier_;
     120             :   base::Mutex* const mutex_;
     121             :   size_t* const work_;
     122             :   size_t processed_work_;
     123             : };
     124             : 
     125             : }  // namespace
     126             : 
     127       15443 : TEST(OneshotBarrier, Processing_Concurrent) {
     128           1 :   const size_t kWorkCounter = 173173;
     129             :   OneshotBarrier barrier(test_timeout);
     130           2 :   base::Mutex mutex;
     131           1 :   size_t work = 0;
     132             :   CountingThread counting_thread(&barrier, &mutex, &work);
     133             :   barrier.Start();
     134             :   barrier.Start();
     135           2 :   EXPECT_FALSE(barrier.DoneForTesting());
     136           1 :   counting_thread.Start();
     137             : 
     138      346347 :   for (size_t i = 0; i < kWorkCounter; i++) {
     139             :     {
     140             :       base::MutexGuard guard(&mutex);
     141      173173 :       work++;
     142             :     }
     143      173173 :     barrier.NotifyAll();
     144             :   }
     145           1 :   barrier.Wait();
     146           1 :   counting_thread.Join();
     147           1 :   EXPECT_TRUE(barrier.DoneForTesting());
     148           2 :   EXPECT_EQ(kWorkCounter, counting_thread.processed_work());
     149           1 : }
     150             : 
     151             : }  // namespace heap
     152             : }  // namespace internal
     153        9264 : }  // namespace v8

Generated by: LCOV version 1.10