This source file includes following definitions.
- Init
- Reset
- TimeOnThread
- ThreadNow
- RunPingPongTest
- FinishMeasurement
- NextThread
- PingPong
- TEST_F
- Init
- Reset
- WaitAndSignalOnThread
- PingPong
- TEST_F
- signaled_
- Signal
- Wait
- TEST_F
- Signal
- Wait
- TEST_F
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/scoped_vector.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
#if defined(OS_POSIX)
#include <pthread.h>
#endif
namespace base {
namespace {
const int kNumRuns = 100000;
class ThreadPerfTest : public testing::Test {
 public:
  ThreadPerfTest()
      : done_(false, false) {
    
    CommandLine::Init(0, NULL);
    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
        switches::kProfilerTiming,
        switches::kProfilerTimingDisabledValue);
  }
  
  
  
  virtual void Init() {}
  virtual void PingPong(int hops) = 0;
  virtual void Reset() {}
  void TimeOnThread(base::TimeTicks* ticks, base::WaitableEvent* done) {
    *ticks = base::TimeTicks::ThreadNow();
    done->Signal();
  }
  base::TimeTicks ThreadNow(base::Thread* thread) {
    base::WaitableEvent done(false, false);
    base::TimeTicks ticks;
    thread->message_loop_proxy()->PostTask(
        FROM_HERE,
        base::Bind(&ThreadPerfTest::TimeOnThread,
                   base::Unretained(this),
                   &ticks,
                   &done));
    done.Wait();
    return ticks;
  }
  void RunPingPongTest(const std::string& name, unsigned num_threads) {
    
    std::vector<base::TimeTicks> thread_starts;
    while (threads_.size() < num_threads) {
      threads_.push_back(new base::Thread("PingPonger"));
      threads_.back()->Start();
      if (base::TimeTicks::IsThreadNowSupported())
        thread_starts.push_back(ThreadNow(threads_.back()));
    }
    Init();
    base::TimeTicks start = base::TimeTicks::HighResNow();
    PingPong(kNumRuns);
    done_.Wait();
    base::TimeTicks end = base::TimeTicks::HighResNow();
    
    
    base::TimeDelta thread_time;
    while (threads_.size()) {
      if (base::TimeTicks::IsThreadNowSupported()) {
        thread_time += ThreadNow(threads_.back()) - thread_starts.back();
        thread_starts.pop_back();
      }
      threads_.pop_back();
    }
    Reset();
    double num_runs = static_cast<double>(kNumRuns);
    double us_per_task_clock = (end - start).InMicroseconds() / num_runs;
    double us_per_task_cpu = thread_time.InMicroseconds() / num_runs;
    
    perf_test::PrintResult(
        "task", "", name + "_time ", us_per_task_clock, "us/hop", true);
    
    if (base::TimeTicks::IsThreadNowSupported()) {
      perf_test::PrintResult(
          "task", "", name + "_cpu ", us_per_task_cpu, "us/hop", true);
    }
  }
 protected:
  void FinishMeasurement() { done_.Signal(); }
  ScopedVector<base::Thread> threads_;
 private:
  base::WaitableEvent done_;
};
class TaskPerfTest : public ThreadPerfTest {
  base::Thread* NextThread(int count) {
    return threads_[count % threads_.size()];
  }
  virtual void PingPong(int hops) OVERRIDE {
    if (!hops) {
      FinishMeasurement();
      return;
    }
    NextThread(hops)->message_loop_proxy()->PostTask(
        FROM_HERE,
        base::Bind(
            &ThreadPerfTest::PingPong, base::Unretained(this), hops - 1));
  }
};
TEST_F(TaskPerfTest, TaskPingPong) {
  RunPingPongTest("1_Task_Threads", 1);
  RunPingPongTest("4_Task_Threads", 4);
}
template <typename WaitableEventType>
class EventPerfTest : public ThreadPerfTest {
 public:
  virtual void Init() OVERRIDE {
    for (size_t i = 0; i < threads_.size(); i++)
      events_.push_back(new WaitableEventType(false, false));
  }
  virtual void Reset() OVERRIDE { events_.clear(); }
  void WaitAndSignalOnThread(size_t event) {
    size_t next_event = (event + 1) % events_.size();
    int my_hops = 0;
    do {
      events_[event]->Wait();
      my_hops = --remaining_hops_;  
      events_[next_event]->Signal();
    } while (my_hops > 0);
    
    
    if (!my_hops)
      FinishMeasurement();
  }
  virtual void PingPong(int hops) OVERRIDE {
    remaining_hops_ = hops;
    for (size_t i = 0; i < threads_.size(); i++) {
      threads_[i]->message_loop_proxy()->PostTask(
          FROM_HERE,
          base::Bind(&EventPerfTest::WaitAndSignalOnThread,
                     base::Unretained(this),
                     i));
    }
    
    events_.front()->Signal();
  }
  int remaining_hops_;
  ScopedVector<WaitableEventType> events_;
};
typedef EventPerfTest<base::WaitableEvent> WaitableEventPerfTest;
TEST_F(WaitableEventPerfTest, EventPingPong) {
  RunPingPongTest("4_WaitableEvent_Threads", 4);
}
class ConditionVariableEvent {
 public:
  ConditionVariableEvent(bool manual_reset, bool initially_signaled)
      : cond_(&lock_), signaled_(false) {
    DCHECK(!manual_reset);
    DCHECK(!initially_signaled);
  }
  void Signal() {
    {
      base::AutoLock scoped_lock(lock_);
      signaled_ = true;
    }
    cond_.Signal();
  }
  void Wait() {
    base::AutoLock scoped_lock(lock_);
    while (!signaled_)
      cond_.Wait();
    signaled_ = false;
  }
 private:
  base::Lock lock_;
  base::ConditionVariable cond_;
  bool signaled_;
};
typedef EventPerfTest<ConditionVariableEvent> ConditionVariablePerfTest;
TEST_F(ConditionVariablePerfTest, EventPingPong) {
  RunPingPongTest("4_ConditionVariable_Threads", 4);
}
#if defined(OS_POSIX)
class PthreadEvent {
 public:
  PthreadEvent(bool manual_reset, bool initially_signaled) {
    DCHECK(!manual_reset);
    DCHECK(!initially_signaled);
    pthread_mutex_init(&mutex_, 0);
    pthread_cond_init(&cond_, 0);
    signaled_ = false;
  }
  ~PthreadEvent() {
    pthread_cond_destroy(&cond_);
    pthread_mutex_destroy(&mutex_);
  }
  void Signal() {
    pthread_mutex_lock(&mutex_);
    signaled_ = true;
    pthread_mutex_unlock(&mutex_);
    pthread_cond_signal(&cond_);
  }
  void Wait() {
    pthread_mutex_lock(&mutex_);
    while (!signaled_)
      pthread_cond_wait(&cond_, &mutex_);
    signaled_ = false;
    pthread_mutex_unlock(&mutex_);
  }
 private:
  bool signaled_;
  pthread_mutex_t mutex_;
  pthread_cond_t cond_;
};
typedef EventPerfTest<PthreadEvent> PthreadEventPerfTest;
TEST_F(PthreadEventPerfTest, EventPingPong) {
  RunPingPongTest("4_PthreadCondVar_Threads", 4);
}
#endif
}  
}