Squashed 'third_party/gperftools/' content from commit 54505f1

Change-Id: Id02e833828732b0efe7dac722b8485279e67c5fa
git-subtree-dir: third_party/gperftools
git-subtree-split: 54505f1d50c2d1f4676f5e87090b64a117fd980e
diff --git a/src/tests/profile-handler_unittest.cc b/src/tests/profile-handler_unittest.cc
new file mode 100644
index 0000000..2984d0d
--- /dev/null
+++ b/src/tests/profile-handler_unittest.cc
@@ -0,0 +1,525 @@
+// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
+// Copyright 2009 Google Inc. All Rights Reserved.
+// Author: Nabeel Mian (nabeelmian@google.com)
+//         Chris Demetriou (cgd@google.com)
+//
+// Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+//
+//
+// This file contains the unit tests for profile-handler.h interface.
+//
+// It is linked into three separate unit tests:
+//     profile-handler_unittest tests basic functionality
+//     profile-handler_disable_test tests that the profiler
+//         is disabled with --install_signal_handlers=false
+//     profile-handler_conflict_test tests that the profiler
+//         is disabled when a SIGPROF handler is registered before InitGoogle.
+
+#include "config.h"
+#include "profile-handler.h"
+
+#include <assert.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <time.h>
+#include "base/logging.h"
+#include "base/simple_mutex.h"
+
+// Some helpful macros for the test class
+#define TEST_F(cls, fn)    void cls :: fn()
+
+// Do we expect the profiler to be enabled?
+DEFINE_bool(test_profiler_enabled, true,
+            "expect profiler to be enabled during tests");
+
+// Should we look at the kernel signal handler settings during the test?
+// Not if we're in conflict_test, because we can't distinguish its nop
+// handler from the real one.
+DEFINE_bool(test_profiler_signal_handler, true,
+            "check profiler signal handler during tests");
+
+namespace {
+
+// TODO(csilvers): error-checking on the pthreads routines
+class Thread {
+ public:
+  Thread() : joinable_(false) { }
+  virtual ~Thread() { }
+  void SetJoinable(bool value) { joinable_ = value; }
+  void Start() {
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, joinable_ ? PTHREAD_CREATE_JOINABLE
+                                                 : PTHREAD_CREATE_DETACHED);
+    pthread_create(&thread_, &attr, &DoRun, this);
+    pthread_attr_destroy(&attr);
+  }
+  void Join()  {
+    assert(joinable_);
+    pthread_join(thread_, NULL);
+  }
+  virtual void Run() = 0;
+ private:
+  static void* DoRun(void* cls) {
+    ProfileHandlerRegisterThread();
+    reinterpret_cast<Thread*>(cls)->Run();
+    return NULL;
+  }
+  pthread_t thread_;
+  bool joinable_;
+};
+
+// Sleep interval in nano secs. ITIMER_PROF goes off only afer the specified CPU
+// time is consumed. Under heavy load this process may no get scheduled in a
+// timely fashion. Therefore, give enough time (20x of ProfileHandle timer
+// interval 10ms (100Hz)) for this process to accumulate enought CPU time to get
+// a profile tick.
+int kSleepInterval = 200000000;
+
+// Sleep interval in nano secs. To ensure that if the timer has expired it is
+// reset.
+int kTimerResetInterval = 5000000;
+
+// Whether each thread has separate timers.
+static bool linux_per_thread_timers_mode_ = false;
+static bool timer_separate_ = false;
+static int timer_type_ = ITIMER_PROF;
+static int signal_number_ = SIGPROF;
+
+// Delays processing by the specified number of nano seconds. 'delay_ns'
+// must be less than the number of nano seconds in a second (1000000000).
+void Delay(int delay_ns) {
+  static const int kNumNSecInSecond = 1000000000;
+  EXPECT_LT(delay_ns, kNumNSecInSecond);
+  struct timespec delay = { 0, delay_ns };
+  nanosleep(&delay, 0);
+}
+
+// Checks whether the profile timer is enabled for the current thread.
+bool IsTimerEnabled() {
+  itimerval current_timer;
+  EXPECT_EQ(0, getitimer(timer_type_, &current_timer));
+  if ((current_timer.it_value.tv_sec == 0) &&
+      (current_timer.it_value.tv_usec != 0)) {
+    // May be the timer has expired. Sleep for a bit and check again.
+    Delay(kTimerResetInterval);
+    EXPECT_EQ(0, getitimer(timer_type_, &current_timer));
+  }
+  return (current_timer.it_value.tv_sec != 0 ||
+          current_timer.it_value.tv_usec != 0);
+}
+
+class VirtualTimerGetterThread : public Thread {
+ public:
+  VirtualTimerGetterThread() {
+    memset(&virtual_timer_, 0, sizeof virtual_timer_);
+  }
+  struct itimerval virtual_timer_;
+
+ private:
+  void Run() {
+    CHECK_EQ(0, getitimer(ITIMER_VIRTUAL, &virtual_timer_));
+  }
+};
+
+// This function checks whether the timers are shared between thread. This
+// function spawns a thread, so use it carefully when testing thread-dependent
+// behaviour.
+static bool threads_have_separate_timers() {
+  struct itimerval new_timer_val;
+
+  // Enable the virtual timer in the current thread.
+  memset(&new_timer_val, 0, sizeof new_timer_val);
+  new_timer_val.it_value.tv_sec = 1000000;  // seconds
+  CHECK_EQ(0, setitimer(ITIMER_VIRTUAL, &new_timer_val, NULL));
+
+  // Spawn a thread, get the virtual timer's value there.
+  VirtualTimerGetterThread thread;
+  thread.SetJoinable(true);
+  thread.Start();
+  thread.Join();
+
+  // Disable timer here.
+  memset(&new_timer_val, 0, sizeof new_timer_val);
+  CHECK_EQ(0, setitimer(ITIMER_VIRTUAL, &new_timer_val, NULL));
+
+  bool target_timer_enabled = (thread.virtual_timer_.it_value.tv_sec != 0 ||
+                               thread.virtual_timer_.it_value.tv_usec != 0);
+  if (!target_timer_enabled) {
+    LOG(INFO, "threads have separate timers");
+    return true;
+  } else {
+    LOG(INFO, "threads have shared timers");
+    return false;
+  }
+}
+
+// Dummy worker thread to accumulate cpu time.
+class BusyThread : public Thread {
+ public:
+  BusyThread() : stop_work_(false) {
+  }
+
+  // Setter/Getters
+  bool stop_work() {
+    MutexLock lock(&mu_);
+    return stop_work_;
+  }
+  void set_stop_work(bool stop_work) {
+    MutexLock lock(&mu_);
+    stop_work_ = stop_work;
+  }
+
+ private:
+  // Protects stop_work_ below.
+  Mutex mu_;
+  // Whether to stop work?
+  bool stop_work_;
+
+  // Do work until asked to stop.
+  void Run() {
+    while (!stop_work()) {
+    }
+    // If timers are separate, check that timer is enabled for this thread.
+    EXPECT_TRUE(linux_per_thread_timers_mode_ || !timer_separate_ || IsTimerEnabled());
+  }
+};
+
+class NullThread : public Thread {
+ private:
+  void Run() {
+    // If timers are separate, check that timer is enabled for this thread.
+    EXPECT_TRUE(linux_per_thread_timers_mode_ || !timer_separate_ || IsTimerEnabled());
+  }
+};
+
+// Signal handler which tracks the profile timer ticks.
+static void TickCounter(int sig, siginfo_t* sig_info, void *vuc,
+                        void* tick_counter) {
+  int* counter = static_cast<int*>(tick_counter);
+  ++(*counter);
+}
+
+// This class tests the profile-handler.h interface.
+class ProfileHandlerTest {
+ protected:
+
+  // Determines whether threads have separate timers.
+  static void SetUpTestCase() {
+    timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF);
+    signal_number_ = (getenv("CPUPROFILE_REALTIME") ? SIGALRM : SIGPROF);
+
+    timer_separate_ = threads_have_separate_timers();
+#if HAVE_LINUX_SIGEV_THREAD_ID
+    linux_per_thread_timers_mode_ = (getenv("CPUPROFILE_PER_THREAD_TIMERS") != NULL);
+    const char *signal_number = getenv("CPUPROFILE_TIMER_SIGNAL");
+    if (signal_number) {
+      signal_number_ = strtol(signal_number, NULL, 0);
+      linux_per_thread_timers_mode_ = true;
+    }
+#endif
+    Delay(kTimerResetInterval);
+  }
+
+  // Sets up the profile timers and SIGPROF/SIGALRM handler in a known state.
+  // It does the following:
+  // 1. Unregisters all the callbacks, stops the timer (if shared) and
+  //    clears out timer_sharing state in the ProfileHandler. This clears
+  //    out any state left behind by the previous test or during module
+  //    initialization when the test program was started.
+  // 2. Spawns two threads which will be registered with the ProfileHandler.
+  //    At this time ProfileHandler knows if the timers are shared.
+  // 3. Starts a busy worker thread to accumulate CPU usage.
+  virtual void SetUp() {
+    // Reset the state of ProfileHandler between each test. This unregisters
+    // all callbacks, stops timer (if shared) and clears timer sharing state.
+    ProfileHandlerReset();
+    EXPECT_EQ(0, GetCallbackCount());
+    VerifyDisabled();
+    // ProfileHandler requires at least two threads to be registerd to determine
+    // whether timers are shared.
+    RegisterThread();
+    RegisterThread();
+    // Now that two threads are started, verify that the signal handler is
+    // disabled and the timers are correctly enabled/disabled.
+    VerifyDisabled();
+    // Start worker to accumulate cpu usage.
+    StartWorker();
+  }
+
+  virtual void TearDown() {
+    ProfileHandlerReset();
+    // Stops the worker thread.
+    StopWorker();
+  }
+
+  // Starts a no-op thread that gets registered with the ProfileHandler. Waits
+  // for the thread to stop.
+  void RegisterThread() {
+    NullThread t;
+    t.SetJoinable(true);
+    t.Start();
+    t.Join();
+  }
+
+  // Starts a busy worker thread to accumulate cpu time. There should be only
+  // one busy worker running. This is required for the case where there are
+  // separate timers for each thread.
+  void StartWorker() {
+    busy_worker_ = new BusyThread();
+    busy_worker_->SetJoinable(true);
+    busy_worker_->Start();
+    // Wait for worker to start up and register with the ProfileHandler.
+    // TODO(nabeelmian) This may not work under very heavy load.
+    Delay(kSleepInterval);
+  }
+
+  // Stops the worker thread.
+  void StopWorker() {
+    busy_worker_->set_stop_work(true);
+    busy_worker_->Join();
+    delete busy_worker_;
+  }
+
+  // Checks whether SIGPROF/SIGALRM signal handler is enabled.
+  bool IsSignalEnabled() {
+    struct sigaction sa;
+    CHECK_EQ(sigaction(signal_number_, NULL, &sa), 0);
+    return ((sa.sa_handler == SIG_IGN) || (sa.sa_handler == SIG_DFL)) ?
+        false : true;
+  }
+
+  // Gets the number of callbacks registered with the ProfileHandler.
+  uint32 GetCallbackCount() {
+    ProfileHandlerState state;
+    ProfileHandlerGetState(&state);
+    return state.callback_count;
+  }
+
+  // Gets the current ProfileHandler interrupt count.
+  uint64 GetInterruptCount() {
+    ProfileHandlerState state;
+    ProfileHandlerGetState(&state);
+    return state.interrupts;
+  }
+
+  // Verifies that a callback is correctly registered and receiving
+  // profile ticks.
+  void VerifyRegistration(const int& tick_counter) {
+    // Check the callback count.
+    EXPECT_GT(GetCallbackCount(), 0);
+    // Check that the profile timer is enabled.
+    EXPECT_EQ(FLAGS_test_profiler_enabled, linux_per_thread_timers_mode_ || IsTimerEnabled());
+    // Check that the signal handler is enabled.
+    if (FLAGS_test_profiler_signal_handler) {
+      EXPECT_EQ(FLAGS_test_profiler_enabled, IsSignalEnabled());
+    }
+    uint64 interrupts_before = GetInterruptCount();
+    // Sleep for a bit and check that tick counter is making progress.
+    int old_tick_count = tick_counter;
+    Delay(kSleepInterval);
+    int new_tick_count = tick_counter;
+    uint64 interrupts_after = GetInterruptCount();
+    if (FLAGS_test_profiler_enabled) {
+      EXPECT_GT(new_tick_count, old_tick_count);
+      EXPECT_GT(interrupts_after, interrupts_before);
+    } else {
+      EXPECT_EQ(new_tick_count, old_tick_count);
+      EXPECT_EQ(interrupts_after, interrupts_before);
+    }
+  }
+
+  // Verifies that a callback is not receiving profile ticks.
+  void VerifyUnregistration(const int& tick_counter) {
+    // Sleep for a bit and check that tick counter is not making progress.
+    int old_tick_count = tick_counter;
+    Delay(kSleepInterval);
+    int new_tick_count = tick_counter;
+    EXPECT_EQ(old_tick_count, new_tick_count);
+    // If no callbacks, signal handler and shared timer should be disabled.
+    if (GetCallbackCount() == 0) {
+      if (FLAGS_test_profiler_signal_handler) {
+        EXPECT_FALSE(IsSignalEnabled());
+      }
+      if (!linux_per_thread_timers_mode_) {
+        if (timer_separate_) {
+          EXPECT_TRUE(IsTimerEnabled());
+        } else {
+          EXPECT_FALSE(IsTimerEnabled());
+        }
+      }
+    }
+  }
+
+  // Verifies that the SIGPROF/SIGALRM interrupt handler is disabled and the
+  // timer, if shared, is disabled. Expects the worker to be running.
+  void VerifyDisabled() {
+    // Check that the signal handler is disabled.
+    if (FLAGS_test_profiler_signal_handler) {
+      EXPECT_FALSE(IsSignalEnabled());
+    }
+    // Check that the callback count is 0.
+    EXPECT_EQ(0, GetCallbackCount());
+    // Check that the timer is disabled if shared, enabled otherwise.
+    if (!linux_per_thread_timers_mode_) {
+      if (timer_separate_) {
+        EXPECT_TRUE(IsTimerEnabled());
+      } else {
+        EXPECT_FALSE(IsTimerEnabled());
+      }
+    }
+    // Verify that the ProfileHandler is not accumulating profile ticks.
+    uint64 interrupts_before = GetInterruptCount();
+    Delay(kSleepInterval);
+    uint64 interrupts_after = GetInterruptCount();
+    EXPECT_EQ(interrupts_before, interrupts_after);
+  }
+
+  // Registers a callback and waits for kTimerResetInterval for timers to get
+  // reset.
+  ProfileHandlerToken* RegisterCallback(void* callback_arg) {
+    ProfileHandlerToken* token = ProfileHandlerRegisterCallback(
+        TickCounter, callback_arg);
+    Delay(kTimerResetInterval);
+    return token;
+  }
+
+  // Unregisters a callback and waits for kTimerResetInterval for timers to get
+  // reset.
+  void UnregisterCallback(ProfileHandlerToken* token) {
+    ProfileHandlerUnregisterCallback(token);
+    Delay(kTimerResetInterval);
+  }
+
+  // Busy worker thread to accumulate cpu usage.
+  BusyThread* busy_worker_;
+
+ private:
+  // The tests to run
+  void RegisterUnregisterCallback();
+  void MultipleCallbacks();
+  void Reset();
+  void RegisterCallbackBeforeThread();
+
+ public:
+#define RUN(test)  do {                         \
+    printf("Running %s\n", #test);              \
+    ProfileHandlerTest pht;                     \
+    pht.SetUp();                                \
+    pht.test();                                 \
+    pht.TearDown();                             \
+} while (0)
+
+  static int RUN_ALL_TESTS() {
+    SetUpTestCase();
+    RUN(RegisterUnregisterCallback);
+    RUN(MultipleCallbacks);
+    RUN(Reset);
+    RUN(RegisterCallbackBeforeThread);
+    printf("Done\n");
+    return 0;
+  }
+};
+
+// Verifies ProfileHandlerRegisterCallback and
+// ProfileHandlerUnregisterCallback.
+TEST_F(ProfileHandlerTest, RegisterUnregisterCallback) {
+  int tick_count = 0;
+  ProfileHandlerToken* token = RegisterCallback(&tick_count);
+  VerifyRegistration(tick_count);
+  UnregisterCallback(token);
+  VerifyUnregistration(tick_count);
+}
+
+// Verifies that multiple callbacks can be registered.
+TEST_F(ProfileHandlerTest, MultipleCallbacks) {
+  // Register first callback.
+  int first_tick_count;
+  ProfileHandlerToken* token1 = RegisterCallback(&first_tick_count);
+  // Check that callback was registered correctly.
+  VerifyRegistration(first_tick_count);
+  EXPECT_EQ(1, GetCallbackCount());
+
+  // Register second callback.
+  int second_tick_count;
+  ProfileHandlerToken* token2 = RegisterCallback(&second_tick_count);
+  // Check that callback was registered correctly.
+  VerifyRegistration(second_tick_count);
+  EXPECT_EQ(2, GetCallbackCount());
+
+  // Unregister first callback.
+  UnregisterCallback(token1);
+  VerifyUnregistration(first_tick_count);
+  EXPECT_EQ(1, GetCallbackCount());
+  // Verify that second callback is still registered.
+  VerifyRegistration(second_tick_count);
+
+  // Unregister second callback.
+  UnregisterCallback(token2);
+  VerifyUnregistration(second_tick_count);
+  EXPECT_EQ(0, GetCallbackCount());
+
+  // Verify that the signal handler and timers are correctly disabled.
+  VerifyDisabled();
+}
+
+// Verifies ProfileHandlerReset
+TEST_F(ProfileHandlerTest, Reset) {
+  // Verify that the profile timer interrupt is disabled.
+  VerifyDisabled();
+  int first_tick_count;
+  RegisterCallback(&first_tick_count);
+  VerifyRegistration(first_tick_count);
+  EXPECT_EQ(1, GetCallbackCount());
+
+  // Register second callback.
+  int second_tick_count;
+  RegisterCallback(&second_tick_count);
+  VerifyRegistration(second_tick_count);
+  EXPECT_EQ(2, GetCallbackCount());
+
+  // Reset the profile handler and verify that callback were correctly
+  // unregistered and timer/signal are disabled.
+  ProfileHandlerReset();
+  VerifyUnregistration(first_tick_count);
+  VerifyUnregistration(second_tick_count);
+  VerifyDisabled();
+}
+
+// Verifies that ProfileHandler correctly handles a case where a callback was
+// registered before the second thread started.
+TEST_F(ProfileHandlerTest, RegisterCallbackBeforeThread) {
+  // Stop the worker.
+  StopWorker();
+  // Unregister all existing callbacks, stop the timer (if shared), disable
+  // the signal handler and reset the timer sharing state in the Profile
+  // Handler.
+  ProfileHandlerReset();
+  EXPECT_EQ(0, GetCallbackCount());
+  VerifyDisabled();
+
+  // Start the worker. At this time ProfileHandler doesn't know if timers are
+  // shared as only one thread has registered so far.
+  StartWorker();
+  // Register a callback and check that profile ticks are being delivered.
+  int tick_count;
+  RegisterCallback(&tick_count);
+  EXPECT_EQ(1, GetCallbackCount());
+  VerifyRegistration(tick_count);
+
+  // Register a second thread and verify that timer and signal handler are
+  // correctly enabled.
+  RegisterThread();
+  EXPECT_EQ(1, GetCallbackCount());
+  EXPECT_EQ(FLAGS_test_profiler_enabled, linux_per_thread_timers_mode_ || IsTimerEnabled());
+  if (FLAGS_test_profiler_signal_handler) {
+    EXPECT_EQ(FLAGS_test_profiler_enabled, IsSignalEnabled());
+  }
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  return ProfileHandlerTest::RUN_ALL_TESTS();
+}