15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2009 Google Inc. All Rights Reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Nabeel Mian (nabeelmian@google.com)
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         Chris Demetriou (cgd@google.com)
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file contains the unit tests for profile-handler.h interface.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is linked into three separate unit tests:
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     profile-handler_unittest tests basic functionality
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     profile-handler_disable_test tests that the profiler
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         is disabled with --install_signal_handlers=false
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     profile-handler_conflict_test tests that the profiler
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//         is disabled when a SIGPROF handler is registered before InitGoogle.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "config.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "profile-handler.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h>
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pthread.h>
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/time.h>
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <time.h>
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/simple_mutex.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Some helpful macros for the test class
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define TEST_F(cls, fn)    void cls :: fn()
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Do we expect the profiler to be enabled?
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DEFINE_bool(test_profiler_enabled, true,
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "expect profiler to be enabled during tests");
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Should we look at the kernel signal handler settings during the test?
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Not if we're in conflict_test, because we can't distinguish its nop
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// handler from the real one.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DEFINE_bool(test_profiler_signal_handler, true,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            "check profiler signal handler during tests");
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(csilvers): error-checking on the pthreads routines
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Thread {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Thread() : joinable_(false) { }
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetJoinable(bool value) { joinable_ = value; }
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Start() {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_attr_t attr;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_attr_init(&attr);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_attr_setdetachstate(&attr, joinable_ ? PTHREAD_CREATE_JOINABLE
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                 : PTHREAD_CREATE_DETACHED);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_create(&thread_, &attr, &DoRun, this);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_attr_destroy(&attr);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Join()  {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert(joinable_);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_join(thread_, NULL);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Run() = 0;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void* DoRun(void* cls) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileHandlerRegisterThread();
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reinterpret_cast<Thread*>(cls)->Run();
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pthread_t thread_;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool joinable_;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sleep interval in nano secs. ITIMER_PROF goes off only afer the specified CPU
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// time is consumed. Under heavy load this process may no get scheduled in a
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// timely fashion. Therefore, give enough time (20x of ProfileHandle timer
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// interval 10ms (100Hz)) for this process to accumulate enought CPU time to get
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a profile tick.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int kSleepInterval = 200000000;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sleep interval in nano secs. To ensure that if the timer has expired it is
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// reset.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int kTimerResetInterval = 5000000;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Whether each thread has separate timers.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool timer_separate_ = false;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int timer_type_ = ITIMER_PROF;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int signal_number_ = SIGPROF;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Delays processing by the specified number of nano seconds. 'delay_ns'
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// must be less than the number of nano seconds in a second (1000000000).
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Delay(int delay_ns) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kNumNSecInSecond = 1000000000;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_LT(delay_ns, kNumNSecInSecond);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct timespec delay = { 0, delay_ns };
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nanosleep(&delay, 0);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Checks whether the profile timer is enabled for the current thread.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsTimerEnabled() {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  itimerval current_timer;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, getitimer(timer_type_, &current_timer));
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((current_timer.it_value.tv_sec == 0) &&
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (current_timer.it_value.tv_usec != 0)) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // May be the timer has expired. Sleep for a bit and check again.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delay(kTimerResetInterval);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(0, getitimer(timer_type_, &current_timer));
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (current_timer.it_value.tv_sec != 0 ||
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          current_timer.it_value.tv_usec != 0);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class VirtualTimerGetterThread : public Thread {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VirtualTimerGetterThread() {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(&virtual_timer_, 0, sizeof virtual_timer_);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct itimerval virtual_timer_;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Run() {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_EQ(0, getitimer(ITIMER_VIRTUAL, &virtual_timer_));
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function checks whether the timers are shared between thread. This
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// function spawns a thread, so use it carefully when testing thread-dependent
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// behaviour.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool threads_have_separate_timers() {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct itimerval new_timer_val;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Enable the virtual timer in the current thread.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&new_timer_val, 0, sizeof new_timer_val);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  new_timer_val.it_value.tv_sec = 1000000;  // seconds
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(0, setitimer(ITIMER_VIRTUAL, &new_timer_val, NULL));
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Spawn a thread, get the virtual timer's value there.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VirtualTimerGetterThread thread;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread.SetJoinable(true);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread.Start();
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  thread.Join();
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Disable timer here.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&new_timer_val, 0, sizeof new_timer_val);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_EQ(0, setitimer(ITIMER_VIRTUAL, &new_timer_val, NULL));
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool target_timer_enabled = (thread.virtual_timer_.it_value.tv_sec != 0 ||
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               thread.virtual_timer_.it_value.tv_usec != 0);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!target_timer_enabled) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(INFO, "threads have separate timers");
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(INFO, "threads have shared timers");
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Dummy worker thread to accumulate cpu time.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BusyThread : public Thread {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BusyThread() : stop_work_(false) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Setter/Getters
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool stop_work() {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MutexLock lock(&mu_);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return stop_work_;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void set_stop_work(bool stop_work) {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MutexLock lock(&mu_);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    stop_work_ = stop_work;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Protects stop_work_ below.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mutex mu_;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Whether to stop work?
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool stop_work_;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do work until asked to stop.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Run() {
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (!stop_work()) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If timers are separate, check that timer is enabled for this thread.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(!timer_separate_ || IsTimerEnabled());
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NullThread : public Thread {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Run() {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If timers are separate, check that timer is enabled for this thread.
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_TRUE(!timer_separate_ || IsTimerEnabled());
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Signal handler which tracks the profile timer ticks.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void TickCounter(int sig, siginfo_t* sig_info, void *vuc,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        void* tick_counter) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int* counter = static_cast<int*>(tick_counter);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ++(*counter);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class tests the profile-handler.h interface.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ProfileHandlerTest {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Determines whether threads have separate timers.
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void SetUpTestCase() {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    signal_number_ = (getenv("CPUPROFILE_REALTIME") ? SIGALRM : SIGPROF);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    timer_separate_ = threads_have_separate_timers();
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delay(kTimerResetInterval);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sets up the profile timers and SIGPROF/SIGALRM handler in a known state.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // It does the following:
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 1. Unregisters all the callbacks, stops the timer (if shared) and
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    clears out timer_sharing state in the ProfileHandler. This clears
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    out any state left behind by the previous test or during module
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    initialization when the test program was started.
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 2. Spawns two threads which will be registered with the ProfileHandler.
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //    At this time ProfileHandler knows if the timers are shared.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 3. Starts a busy worker thread to accumulate CPU usage.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void SetUp() {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Reset the state of ProfileHandler between each test. This unregisters
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // all callbacks, stops timer (if shared) and clears timer sharing state.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileHandlerReset();
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(0, GetCallbackCount());
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VerifyDisabled();
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // ProfileHandler requires at least two threads to be registerd to determine
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // whether timers are shared.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RegisterThread();
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RegisterThread();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Now that two threads are started, verify that the signal handler is
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // disabled and the timers are correctly enabled/disabled.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    VerifyDisabled();
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Start worker to accumulate cpu usage.
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StartWorker();
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void TearDown() {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileHandlerReset();
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Stops the worker thread.
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StopWorker();
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Starts a no-op thread that gets registered with the ProfileHandler. Waits
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for the thread to stop.
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RegisterThread() {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NullThread t;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    t.SetJoinable(true);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    t.Start();
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    t.Join();
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Starts a busy worker thread to accumulate cpu time. There should be only
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // one busy worker running. This is required for the case where there are
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // separate timers for each thread.
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void StartWorker() {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    busy_worker_ = new BusyThread();
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    busy_worker_->SetJoinable(true);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    busy_worker_->Start();
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait for worker to start up and register with the ProfileHandler.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(nabeelmian) This may not work under very heavy load.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delay(kSleepInterval);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stops the worker thread.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void StopWorker() {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    busy_worker_->set_stop_work(true);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    busy_worker_->Join();
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete busy_worker_;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Checks whether SIGPROF/SIGALRM signal handler is enabled.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool IsSignalEnabled() {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct sigaction sa;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_EQ(sigaction(signal_number_, NULL, &sa), 0);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ((sa.sa_handler == SIG_IGN) || (sa.sa_handler == SIG_DFL)) ?
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        false : true;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Gets the number of callbacks registered with the ProfileHandler.
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint32 GetCallbackCount() {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileHandlerState state;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileHandlerGetState(&state);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return state.callback_count;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Gets the current ProfileHandler interrupt count.
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint64 GetInterruptCount() {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileHandlerState state;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileHandlerGetState(&state);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return state.interrupts;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verifies that a callback is correctly registered and receiving
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // profile ticks.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void VerifyRegistration(const int& tick_counter) {
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check the callback count.
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_GT(GetCallbackCount(), 0);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check that the profile timer is enabled.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(FLAGS_test_profiler_enabled, IsTimerEnabled());
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check that the signal handler is enabled.
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FLAGS_test_profiler_signal_handler) {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_EQ(FLAGS_test_profiler_enabled, IsSignalEnabled());
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint64 interrupts_before = GetInterruptCount();
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sleep for a bit and check that tick counter is making progress.
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int old_tick_count = tick_counter;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delay(kSleepInterval);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int new_tick_count = tick_counter;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint64 interrupts_after = GetInterruptCount();
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FLAGS_test_profiler_enabled) {
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_GT(new_tick_count, old_tick_count);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_GT(interrupts_after, interrupts_before);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_EQ(new_tick_count, old_tick_count);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_EQ(interrupts_after, interrupts_before);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verifies that a callback is not receiving profile ticks.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void VerifyUnregistration(const int& tick_counter) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sleep for a bit and check that tick counter is not making progress.
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int old_tick_count = tick_counter;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delay(kSleepInterval);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int new_tick_count = tick_counter;
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(old_tick_count, new_tick_count);
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If no callbacks, signal handler and shared timer should be disabled.
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetCallbackCount() == 0) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (FLAGS_test_profiler_signal_handler) {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        EXPECT_FALSE(IsSignalEnabled());
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (timer_separate_) {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        EXPECT_TRUE(IsTimerEnabled());
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        EXPECT_FALSE(IsTimerEnabled());
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verifies that the SIGPROF/SIGALRM interrupt handler is disabled and the
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // timer, if shared, is disabled. Expects the worker to be running.
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void VerifyDisabled() {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check that the signal handler is disabled.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (FLAGS_test_profiler_signal_handler) {
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_FALSE(IsSignalEnabled());
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check that the callback count is 0.
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(0, GetCallbackCount());
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check that the timer is disabled if shared, enabled otherwise.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (timer_separate_) {
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_TRUE(IsTimerEnabled());
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EXPECT_FALSE(IsTimerEnabled());
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Verify that the ProfileHandler is not accumulating profile ticks.
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint64 interrupts_before = GetInterruptCount();
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delay(kSleepInterval);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint64 interrupts_after = GetInterruptCount();
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(interrupts_before, interrupts_after);
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Registers a callback and waits for kTimerResetInterval for timers to get
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reset.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileHandlerToken* RegisterCallback(void* callback_arg) {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileHandlerToken* token = ProfileHandlerRegisterCallback(
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TickCounter, callback_arg);
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delay(kTimerResetInterval);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return token;
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unregisters a callback and waits for kTimerResetInterval for timers to get
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reset.
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void UnregisterCallback(ProfileHandlerToken* token) {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileHandlerUnregisterCallback(token);
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Delay(kTimerResetInterval);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Busy worker thread to accumulate cpu usage.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BusyThread* busy_worker_;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The tests to run
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RegisterUnregisterCallback();
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void MultipleCallbacks();
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Reset();
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RegisterCallbackBeforeThread();
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define RUN(test)  do {                         \
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("Running %s\n", #test);              \
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ProfileHandlerTest pht;                     \
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pht.SetUp();                                \
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pht.test();                                 \
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pht.TearDown();                             \
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} while (0)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int RUN_ALL_TESTS() {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetUpTestCase();
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RUN(RegisterUnregisterCallback);
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RUN(MultipleCallbacks);
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RUN(Reset);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RUN(RegisterCallbackBeforeThread);
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    printf("Done\n");
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Verifies ProfileHandlerRegisterCallback and
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ProfileHandlerUnregisterCallback.
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ProfileHandlerTest, RegisterUnregisterCallback) {
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int tick_count = 0;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileHandlerToken* token = RegisterCallback(&tick_count);
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyRegistration(tick_count);
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UnregisterCallback(token);
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyUnregistration(tick_count);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Verifies that multiple callbacks can be registered.
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ProfileHandlerTest, MultipleCallbacks) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Register first callback.
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int first_tick_count;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileHandlerToken* token1 = RegisterCallback(&first_tick_count);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that callback was registered correctly.
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyRegistration(first_tick_count);
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, GetCallbackCount());
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Register second callback.
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int second_tick_count;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileHandlerToken* token2 = RegisterCallback(&second_tick_count);
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check that callback was registered correctly.
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyRegistration(second_tick_count);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2, GetCallbackCount());
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unregister first callback.
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UnregisterCallback(token1);
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyUnregistration(first_tick_count);
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, GetCallbackCount());
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that second callback is still registered.
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyRegistration(second_tick_count);
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unregister second callback.
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UnregisterCallback(token2);
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyUnregistration(second_tick_count);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, GetCallbackCount());
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that the signal handler and timers are correctly disabled.
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyDisabled();
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Verifies ProfileHandlerReset
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ProfileHandlerTest, Reset) {
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Verify that the profile timer interrupt is disabled.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyDisabled();
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int first_tick_count;
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegisterCallback(&first_tick_count);
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyRegistration(first_tick_count);
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, GetCallbackCount());
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Register second callback.
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int second_tick_count;
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegisterCallback(&second_tick_count);
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyRegistration(second_tick_count);
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(2, GetCallbackCount());
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reset the profile handler and verify that callback were correctly
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // unregistered and timer/signal are disabled.
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileHandlerReset();
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyUnregistration(first_tick_count);
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyUnregistration(second_tick_count);
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyDisabled();
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Verifies that ProfileHandler correctly handles a case where a callback was
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// registered before the second thread started.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST_F(ProfileHandlerTest, RegisterCallbackBeforeThread) {
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stop the worker.
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StopWorker();
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Unregister all existing callbacks, stop the timer (if shared), disable
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the signal handler and reset the timer sharing state in the Profile
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Handler.
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ProfileHandlerReset();
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(0, GetCallbackCount());
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyDisabled();
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start the worker. At this time ProfileHandler doesn't know if timers are
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // shared as only one thread has registered so far.
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartWorker();
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Register a callback and check that profile ticks are being delivered.
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int tick_count;
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegisterCallback(&tick_count);
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, GetCallbackCount());
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VerifyRegistration(tick_count);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Register a second thread and verify that timer and signal handler are
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // correctly enabled.
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RegisterThread();
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(1, GetCallbackCount());
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXPECT_EQ(FLAGS_test_profiler_enabled, IsTimerEnabled());
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FLAGS_test_profiler_signal_handler) {
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXPECT_EQ(FLAGS_test_profiler_enabled, IsSignalEnabled());
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int main(int argc, char** argv) {
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ProfileHandlerTest::RUN_ALL_TESTS();
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
507