blob: a8afbca061271995fee7e63ee393e8fa442837b5 [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2// Copyright 2009 Google Inc. All Rights Reserved.
3// Author: Nabeel Mian (nabeelmian@google.com)
4// Chris Demetriou (cgd@google.com)
5//
6// Use of this source code is governed by a BSD-style license that can
7// be found in the LICENSE file.
8//
9//
10// This file contains the unit tests for profile-handler.h interface.
Austin Schuh745610d2015-09-06 18:19:50 -070011
12#include "config.h"
13#include "profile-handler.h"
14
15#include <assert.h>
16#include <pthread.h>
17#include <sys/time.h>
18#include <time.h>
19#include "base/logging.h"
20#include "base/simple_mutex.h"
21
22// Some helpful macros for the test class
23#define TEST_F(cls, fn) void cls :: fn()
24
25// Do we expect the profiler to be enabled?
26DEFINE_bool(test_profiler_enabled, true,
27 "expect profiler to be enabled during tests");
28
Austin Schuh745610d2015-09-06 18:19:50 -070029namespace {
30
31// TODO(csilvers): error-checking on the pthreads routines
32class Thread {
33 public:
34 Thread() : joinable_(false) { }
35 virtual ~Thread() { }
36 void SetJoinable(bool value) { joinable_ = value; }
37 void Start() {
38 pthread_attr_t attr;
39 pthread_attr_init(&attr);
40 pthread_attr_setdetachstate(&attr, joinable_ ? PTHREAD_CREATE_JOINABLE
41 : PTHREAD_CREATE_DETACHED);
42 pthread_create(&thread_, &attr, &DoRun, this);
43 pthread_attr_destroy(&attr);
44 }
45 void Join() {
46 assert(joinable_);
47 pthread_join(thread_, NULL);
48 }
49 virtual void Run() = 0;
50 private:
51 static void* DoRun(void* cls) {
52 ProfileHandlerRegisterThread();
53 reinterpret_cast<Thread*>(cls)->Run();
54 return NULL;
55 }
56 pthread_t thread_;
57 bool joinable_;
58};
59
60// Sleep interval in nano secs. ITIMER_PROF goes off only afer the specified CPU
61// time is consumed. Under heavy load this process may no get scheduled in a
62// timely fashion. Therefore, give enough time (20x of ProfileHandle timer
63// interval 10ms (100Hz)) for this process to accumulate enought CPU time to get
64// a profile tick.
65int kSleepInterval = 200000000;
66
67// Sleep interval in nano secs. To ensure that if the timer has expired it is
68// reset.
69int kTimerResetInterval = 5000000;
70
Austin Schuh745610d2015-09-06 18:19:50 -070071static bool linux_per_thread_timers_mode_ = false;
Austin Schuh745610d2015-09-06 18:19:50 -070072static int timer_type_ = ITIMER_PROF;
Austin Schuh745610d2015-09-06 18:19:50 -070073
74// Delays processing by the specified number of nano seconds. 'delay_ns'
75// must be less than the number of nano seconds in a second (1000000000).
76void Delay(int delay_ns) {
77 static const int kNumNSecInSecond = 1000000000;
78 EXPECT_LT(delay_ns, kNumNSecInSecond);
79 struct timespec delay = { 0, delay_ns };
80 nanosleep(&delay, 0);
81}
82
83// Checks whether the profile timer is enabled for the current thread.
84bool IsTimerEnabled() {
85 itimerval current_timer;
86 EXPECT_EQ(0, getitimer(timer_type_, &current_timer));
87 if ((current_timer.it_value.tv_sec == 0) &&
88 (current_timer.it_value.tv_usec != 0)) {
89 // May be the timer has expired. Sleep for a bit and check again.
90 Delay(kTimerResetInterval);
91 EXPECT_EQ(0, getitimer(timer_type_, &current_timer));
92 }
93 return (current_timer.it_value.tv_sec != 0 ||
94 current_timer.it_value.tv_usec != 0);
95}
96
Austin Schuh745610d2015-09-06 18:19:50 -070097// Dummy worker thread to accumulate cpu time.
98class BusyThread : public Thread {
99 public:
100 BusyThread() : stop_work_(false) {
101 }
102
103 // Setter/Getters
104 bool stop_work() {
105 MutexLock lock(&mu_);
106 return stop_work_;
107 }
108 void set_stop_work(bool stop_work) {
109 MutexLock lock(&mu_);
110 stop_work_ = stop_work;
111 }
112
113 private:
114 // Protects stop_work_ below.
115 Mutex mu_;
116 // Whether to stop work?
117 bool stop_work_;
118
119 // Do work until asked to stop.
120 void Run() {
121 while (!stop_work()) {
122 }
Austin Schuh745610d2015-09-06 18:19:50 -0700123 }
124};
125
126class NullThread : public Thread {
127 private:
128 void Run() {
Austin Schuh745610d2015-09-06 18:19:50 -0700129 }
130};
131
132// Signal handler which tracks the profile timer ticks.
133static void TickCounter(int sig, siginfo_t* sig_info, void *vuc,
134 void* tick_counter) {
135 int* counter = static_cast<int*>(tick_counter);
136 ++(*counter);
137}
138
139// This class tests the profile-handler.h interface.
140class ProfileHandlerTest {
141 protected:
142
Brian Silverman20350ac2021-11-17 18:19:55 -0800143 // Determines the timer type.
Austin Schuh745610d2015-09-06 18:19:50 -0700144 static void SetUpTestCase() {
145 timer_type_ = (getenv("CPUPROFILE_REALTIME") ? ITIMER_REAL : ITIMER_PROF);
Austin Schuh745610d2015-09-06 18:19:50 -0700146
Austin Schuh745610d2015-09-06 18:19:50 -0700147#if HAVE_LINUX_SIGEV_THREAD_ID
148 linux_per_thread_timers_mode_ = (getenv("CPUPROFILE_PER_THREAD_TIMERS") != NULL);
149 const char *signal_number = getenv("CPUPROFILE_TIMER_SIGNAL");
150 if (signal_number) {
Brian Silverman20350ac2021-11-17 18:19:55 -0800151 //signal_number_ = strtol(signal_number, NULL, 0);
Austin Schuh745610d2015-09-06 18:19:50 -0700152 linux_per_thread_timers_mode_ = true;
Brian Silverman20350ac2021-11-17 18:19:55 -0800153 Delay(kTimerResetInterval);
Austin Schuh745610d2015-09-06 18:19:50 -0700154 }
155#endif
Austin Schuh745610d2015-09-06 18:19:50 -0700156 }
157
158 // Sets up the profile timers and SIGPROF/SIGALRM handler in a known state.
159 // It does the following:
Brian Silverman20350ac2021-11-17 18:19:55 -0800160 // 1. Unregisters all the callbacks, stops the timer and clears out
161 // timer_sharing state in the ProfileHandler. This clears out any state
162 // left behind by the previous test or during module initialization when
163 // the test program was started.
Austin Schuh745610d2015-09-06 18:19:50 -0700164 // 3. Starts a busy worker thread to accumulate CPU usage.
165 virtual void SetUp() {
166 // Reset the state of ProfileHandler between each test. This unregisters
Brian Silverman20350ac2021-11-17 18:19:55 -0800167 // all callbacks and stops the timer.
Austin Schuh745610d2015-09-06 18:19:50 -0700168 ProfileHandlerReset();
169 EXPECT_EQ(0, GetCallbackCount());
170 VerifyDisabled();
Austin Schuh745610d2015-09-06 18:19:50 -0700171 // Start worker to accumulate cpu usage.
172 StartWorker();
173 }
174
175 virtual void TearDown() {
176 ProfileHandlerReset();
177 // Stops the worker thread.
178 StopWorker();
179 }
180
Austin Schuh745610d2015-09-06 18:19:50 -0700181 // Starts a busy worker thread to accumulate cpu time. There should be only
182 // one busy worker running. This is required for the case where there are
183 // separate timers for each thread.
184 void StartWorker() {
185 busy_worker_ = new BusyThread();
186 busy_worker_->SetJoinable(true);
187 busy_worker_->Start();
188 // Wait for worker to start up and register with the ProfileHandler.
189 // TODO(nabeelmian) This may not work under very heavy load.
190 Delay(kSleepInterval);
191 }
192
193 // Stops the worker thread.
194 void StopWorker() {
195 busy_worker_->set_stop_work(true);
196 busy_worker_->Join();
197 delete busy_worker_;
198 }
199
Austin Schuh745610d2015-09-06 18:19:50 -0700200 // Gets the number of callbacks registered with the ProfileHandler.
201 uint32 GetCallbackCount() {
202 ProfileHandlerState state;
203 ProfileHandlerGetState(&state);
204 return state.callback_count;
205 }
206
207 // Gets the current ProfileHandler interrupt count.
208 uint64 GetInterruptCount() {
209 ProfileHandlerState state;
210 ProfileHandlerGetState(&state);
211 return state.interrupts;
212 }
213
214 // Verifies that a callback is correctly registered and receiving
215 // profile ticks.
216 void VerifyRegistration(const int& tick_counter) {
217 // Check the callback count.
218 EXPECT_GT(GetCallbackCount(), 0);
219 // Check that the profile timer is enabled.
220 EXPECT_EQ(FLAGS_test_profiler_enabled, linux_per_thread_timers_mode_ || IsTimerEnabled());
Austin Schuh745610d2015-09-06 18:19:50 -0700221 uint64 interrupts_before = GetInterruptCount();
222 // Sleep for a bit and check that tick counter is making progress.
223 int old_tick_count = tick_counter;
224 Delay(kSleepInterval);
225 int new_tick_count = tick_counter;
226 uint64 interrupts_after = GetInterruptCount();
227 if (FLAGS_test_profiler_enabled) {
228 EXPECT_GT(new_tick_count, old_tick_count);
229 EXPECT_GT(interrupts_after, interrupts_before);
230 } else {
231 EXPECT_EQ(new_tick_count, old_tick_count);
232 EXPECT_EQ(interrupts_after, interrupts_before);
233 }
234 }
235
236 // Verifies that a callback is not receiving profile ticks.
237 void VerifyUnregistration(const int& tick_counter) {
238 // Sleep for a bit and check that tick counter is not making progress.
239 int old_tick_count = tick_counter;
240 Delay(kSleepInterval);
241 int new_tick_count = tick_counter;
242 EXPECT_EQ(old_tick_count, new_tick_count);
Brian Silverman20350ac2021-11-17 18:19:55 -0800243 // If no callbacks, timer should be disabled.
Austin Schuh745610d2015-09-06 18:19:50 -0700244 if (GetCallbackCount() == 0) {
Brian Silverman20350ac2021-11-17 18:19:55 -0800245 EXPECT_FALSE(IsTimerEnabled());
Austin Schuh745610d2015-09-06 18:19:50 -0700246 }
247 }
248
Brian Silverman20350ac2021-11-17 18:19:55 -0800249 // Verifies that the timer is disabled. Expects the worker to be running.
Austin Schuh745610d2015-09-06 18:19:50 -0700250 void VerifyDisabled() {
Austin Schuh745610d2015-09-06 18:19:50 -0700251 // Check that the callback count is 0.
252 EXPECT_EQ(0, GetCallbackCount());
Brian Silverman20350ac2021-11-17 18:19:55 -0800253 // Check that the timer is disabled.
254 EXPECT_FALSE(IsTimerEnabled());
Austin Schuh745610d2015-09-06 18:19:50 -0700255 // Verify that the ProfileHandler is not accumulating profile ticks.
256 uint64 interrupts_before = GetInterruptCount();
257 Delay(kSleepInterval);
258 uint64 interrupts_after = GetInterruptCount();
259 EXPECT_EQ(interrupts_before, interrupts_after);
260 }
261
262 // Registers a callback and waits for kTimerResetInterval for timers to get
263 // reset.
264 ProfileHandlerToken* RegisterCallback(void* callback_arg) {
265 ProfileHandlerToken* token = ProfileHandlerRegisterCallback(
266 TickCounter, callback_arg);
267 Delay(kTimerResetInterval);
268 return token;
269 }
270
271 // Unregisters a callback and waits for kTimerResetInterval for timers to get
272 // reset.
273 void UnregisterCallback(ProfileHandlerToken* token) {
274 ProfileHandlerUnregisterCallback(token);
275 Delay(kTimerResetInterval);
276 }
277
278 // Busy worker thread to accumulate cpu usage.
279 BusyThread* busy_worker_;
280
281 private:
282 // The tests to run
283 void RegisterUnregisterCallback();
284 void MultipleCallbacks();
285 void Reset();
286 void RegisterCallbackBeforeThread();
287
288 public:
289#define RUN(test) do { \
290 printf("Running %s\n", #test); \
291 ProfileHandlerTest pht; \
292 pht.SetUp(); \
293 pht.test(); \
294 pht.TearDown(); \
295} while (0)
296
297 static int RUN_ALL_TESTS() {
298 SetUpTestCase();
299 RUN(RegisterUnregisterCallback);
300 RUN(MultipleCallbacks);
301 RUN(Reset);
302 RUN(RegisterCallbackBeforeThread);
303 printf("Done\n");
304 return 0;
305 }
306};
307
308// Verifies ProfileHandlerRegisterCallback and
309// ProfileHandlerUnregisterCallback.
310TEST_F(ProfileHandlerTest, RegisterUnregisterCallback) {
311 int tick_count = 0;
312 ProfileHandlerToken* token = RegisterCallback(&tick_count);
313 VerifyRegistration(tick_count);
314 UnregisterCallback(token);
315 VerifyUnregistration(tick_count);
316}
317
318// Verifies that multiple callbacks can be registered.
319TEST_F(ProfileHandlerTest, MultipleCallbacks) {
320 // Register first callback.
Brian Silverman20350ac2021-11-17 18:19:55 -0800321 int first_tick_count = 0;
Austin Schuh745610d2015-09-06 18:19:50 -0700322 ProfileHandlerToken* token1 = RegisterCallback(&first_tick_count);
323 // Check that callback was registered correctly.
324 VerifyRegistration(first_tick_count);
325 EXPECT_EQ(1, GetCallbackCount());
326
327 // Register second callback.
Brian Silverman20350ac2021-11-17 18:19:55 -0800328 int second_tick_count = 0;
Austin Schuh745610d2015-09-06 18:19:50 -0700329 ProfileHandlerToken* token2 = RegisterCallback(&second_tick_count);
330 // Check that callback was registered correctly.
331 VerifyRegistration(second_tick_count);
332 EXPECT_EQ(2, GetCallbackCount());
333
334 // Unregister first callback.
335 UnregisterCallback(token1);
336 VerifyUnregistration(first_tick_count);
337 EXPECT_EQ(1, GetCallbackCount());
338 // Verify that second callback is still registered.
339 VerifyRegistration(second_tick_count);
340
341 // Unregister second callback.
342 UnregisterCallback(token2);
343 VerifyUnregistration(second_tick_count);
344 EXPECT_EQ(0, GetCallbackCount());
345
Brian Silverman20350ac2021-11-17 18:19:55 -0800346 // Verify that the timers is correctly disabled.
347 if (!linux_per_thread_timers_mode_) VerifyDisabled();
Austin Schuh745610d2015-09-06 18:19:50 -0700348}
349
350// Verifies ProfileHandlerReset
351TEST_F(ProfileHandlerTest, Reset) {
352 // Verify that the profile timer interrupt is disabled.
Brian Silverman20350ac2021-11-17 18:19:55 -0800353 if (!linux_per_thread_timers_mode_) VerifyDisabled();
354 int first_tick_count = 0;
Austin Schuh745610d2015-09-06 18:19:50 -0700355 RegisterCallback(&first_tick_count);
356 VerifyRegistration(first_tick_count);
357 EXPECT_EQ(1, GetCallbackCount());
358
359 // Register second callback.
Brian Silverman20350ac2021-11-17 18:19:55 -0800360 int second_tick_count = 0;
Austin Schuh745610d2015-09-06 18:19:50 -0700361 RegisterCallback(&second_tick_count);
362 VerifyRegistration(second_tick_count);
363 EXPECT_EQ(2, GetCallbackCount());
364
365 // Reset the profile handler and verify that callback were correctly
Brian Silverman20350ac2021-11-17 18:19:55 -0800366 // unregistered and the timer is disabled.
Austin Schuh745610d2015-09-06 18:19:50 -0700367 ProfileHandlerReset();
368 VerifyUnregistration(first_tick_count);
369 VerifyUnregistration(second_tick_count);
Brian Silverman20350ac2021-11-17 18:19:55 -0800370 if (!linux_per_thread_timers_mode_) VerifyDisabled();
Austin Schuh745610d2015-09-06 18:19:50 -0700371}
372
373// Verifies that ProfileHandler correctly handles a case where a callback was
374// registered before the second thread started.
375TEST_F(ProfileHandlerTest, RegisterCallbackBeforeThread) {
376 // Stop the worker.
377 StopWorker();
Brian Silverman20350ac2021-11-17 18:19:55 -0800378 // Unregister all existing callbacks and stop the timer.
Austin Schuh745610d2015-09-06 18:19:50 -0700379 ProfileHandlerReset();
380 EXPECT_EQ(0, GetCallbackCount());
381 VerifyDisabled();
382
Brian Silverman20350ac2021-11-17 18:19:55 -0800383 // Start the worker.
Austin Schuh745610d2015-09-06 18:19:50 -0700384 StartWorker();
Brian Silverman20350ac2021-11-17 18:19:55 -0800385 // Register a callback and check that profile ticks are being delivered and
386 // the timer is enabled.
387 int tick_count = 0;
Austin Schuh745610d2015-09-06 18:19:50 -0700388 RegisterCallback(&tick_count);
389 EXPECT_EQ(1, GetCallbackCount());
390 VerifyRegistration(tick_count);
Austin Schuh745610d2015-09-06 18:19:50 -0700391 EXPECT_EQ(FLAGS_test_profiler_enabled, linux_per_thread_timers_mode_ || IsTimerEnabled());
Austin Schuh745610d2015-09-06 18:19:50 -0700392}
393
394} // namespace
395
396int main(int argc, char** argv) {
397 return ProfileHandlerTest::RUN_ALL_TESTS();
398}