1 // Copyright 2015 The Chromium 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 <stddef.h>
6 #include <stdint.h>
7
8 #include <algorithm>
9 #include <cstdlib>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13
14 #include "base/bind.h"
15 #include "base/callback.h"
16 #include "base/compiler_specific.h"
17 #include "base/files/file_util.h"
18 #include "base/macros.h"
19 #include "base/memory/ptr_util.h"
20 #include "base/native_library.h"
21 #include "base/path_service.h"
22 #include "base/profiler/native_stack_sampler.h"
23 #include "base/profiler/stack_sampling_profiler.h"
24 #include "base/run_loop.h"
25 #include "base/scoped_native_library.h"
26 #include "base/stl_util.h"
27 #include "base/strings/stringprintf.h"
28 #include "base/strings/utf_string_conversions.h"
29 #include "base/synchronization/lock.h"
30 #include "base/synchronization/waitable_event.h"
31 #include "base/test/bind_test_util.h"
32 #include "base/threading/platform_thread.h"
33 #include "base/threading/simple_thread.h"
34 #include "base/time/time.h"
35 #include "build/build_config.h"
36 #include "testing/gtest/include/gtest/gtest.h"
37
38 #if defined(OS_WIN)
39 #include <intrin.h>
40 #include <malloc.h>
41 #include <windows.h>
42 #else
43 #include <alloca.h>
44 #endif
45
46 // STACK_SAMPLING_PROFILER_SUPPORTED is used to conditionally enable the tests
47 // below for supported platforms (currently Win x64 and Mac x64).
48 #if defined(_WIN64) || (defined(OS_MACOSX) && !defined(OS_IOS))
49 #define STACK_SAMPLING_PROFILER_SUPPORTED 1
50 #endif
51
52 #if defined(OS_WIN)
53 #pragma intrinsic(_ReturnAddress)
54 #endif
55
56 namespace base {
57
58 #if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
59 #define PROFILER_TEST_F(TestClass, TestName) TEST_F(TestClass, TestName)
60 #else
61 #define PROFILER_TEST_F(TestClass, TestName) \
62 TEST_F(TestClass, DISABLED_##TestName)
63 #endif
64
65 using SamplingParams = StackSamplingProfiler::SamplingParams;
66 using Frame = StackSamplingProfiler::Frame;
67 using Frames = std::vector<Frame>;
68 using InternalFrame = StackSamplingProfiler::InternalFrame;
69 using InternalFrames = std::vector<InternalFrame>;
70 using InternalFrameSets = std::vector<std::vector<InternalFrame>>;
71 using Module = StackSamplingProfiler::Module;
72 using InternalModule = StackSamplingProfiler::InternalModule;
73 using Sample = StackSamplingProfiler::Sample;
74
75 namespace {
76
77 // Configuration for the frames that appear on the stack.
78 struct StackConfiguration {
79 enum Config { NORMAL, WITH_ALLOCA, WITH_OTHER_LIBRARY };
80
StackConfigurationbase::__anon480abaac0111::StackConfiguration81 explicit StackConfiguration(Config config)
82 : StackConfiguration(config, nullptr) {
83 EXPECT_NE(config, WITH_OTHER_LIBRARY);
84 }
85
StackConfigurationbase::__anon480abaac0111::StackConfiguration86 StackConfiguration(Config config, NativeLibrary library)
87 : config(config), library(library) {
88 EXPECT_TRUE(config != WITH_OTHER_LIBRARY || library);
89 }
90
91 Config config;
92
93 // Only used if config == WITH_OTHER_LIBRARY.
94 NativeLibrary library;
95 };
96
97 // Signature for a target function that is expected to appear in the stack. See
98 // SignalAndWaitUntilSignaled() below. The return value should be a program
99 // counter pointer near the end of the function.
100 using TargetFunction = const void* (*)(WaitableEvent*,
101 WaitableEvent*,
102 const StackConfiguration*);
103
104 // A thread to target for profiling, whose stack is guaranteed to contain
105 // SignalAndWaitUntilSignaled() when coordinated with the main thread.
106 class TargetThread : public PlatformThread::Delegate {
107 public:
108 explicit TargetThread(const StackConfiguration& stack_config);
109
110 // PlatformThread::Delegate:
111 void ThreadMain() override;
112
113 // Waits for the thread to have started and be executing in
114 // SignalAndWaitUntilSignaled().
115 void WaitForThreadStart();
116
117 // Allows the thread to return from SignalAndWaitUntilSignaled() and finish
118 // execution.
119 void SignalThreadToFinish();
120
121 // This function is guaranteed to be executing between calls to
122 // WaitForThreadStart() and SignalThreadToFinish() when invoked with
123 // |thread_started_event_| and |finish_event_|. Returns a program counter
124 // value near the end of the function. May be invoked with null WaitableEvents
125 // to just return the program counter.
126 //
127 // This function is static so that we can get a straightforward address
128 // for it in one of the tests below, rather than dealing with the complexity
129 // of a member function pointer representation.
130 static const void* SignalAndWaitUntilSignaled(
131 WaitableEvent* thread_started_event,
132 WaitableEvent* finish_event,
133 const StackConfiguration* stack_config);
134
135 // Calls into SignalAndWaitUntilSignaled() after allocating memory on the
136 // stack with alloca.
137 static const void* CallWithAlloca(WaitableEvent* thread_started_event,
138 WaitableEvent* finish_event,
139 const StackConfiguration* stack_config);
140
141 // Calls into SignalAndWaitUntilSignaled() via a function in
142 // base_profiler_test_support_library.
143 static const void* CallThroughOtherLibrary(
144 WaitableEvent* thread_started_event,
145 WaitableEvent* finish_event,
146 const StackConfiguration* stack_config);
147
id() const148 PlatformThreadId id() const { return id_; }
149
150 private:
151 struct TargetFunctionArgs {
152 WaitableEvent* thread_started_event;
153 WaitableEvent* finish_event;
154 const StackConfiguration* stack_config;
155 };
156
157 // Callback function to be provided when calling through the other library.
158 static void OtherLibraryCallback(void* arg);
159
160 // Returns the current program counter, or a value very close to it.
161 static const void* GetProgramCounter();
162
163 WaitableEvent thread_started_event_;
164 WaitableEvent finish_event_;
165 PlatformThreadId id_;
166 const StackConfiguration stack_config_;
167
168 DISALLOW_COPY_AND_ASSIGN(TargetThread);
169 };
170
TargetThread(const StackConfiguration & stack_config)171 TargetThread::TargetThread(const StackConfiguration& stack_config)
172 : thread_started_event_(WaitableEvent::ResetPolicy::AUTOMATIC,
173 WaitableEvent::InitialState::NOT_SIGNALED),
174 finish_event_(WaitableEvent::ResetPolicy::AUTOMATIC,
175 WaitableEvent::InitialState::NOT_SIGNALED),
176 id_(0),
177 stack_config_(stack_config) {}
178
ThreadMain()179 void TargetThread::ThreadMain() {
180 id_ = PlatformThread::CurrentId();
181 switch (stack_config_.config) {
182 case StackConfiguration::NORMAL:
183 SignalAndWaitUntilSignaled(&thread_started_event_, &finish_event_,
184 &stack_config_);
185 break;
186
187 case StackConfiguration::WITH_ALLOCA:
188 CallWithAlloca(&thread_started_event_, &finish_event_, &stack_config_);
189 break;
190
191 case StackConfiguration::WITH_OTHER_LIBRARY:
192 CallThroughOtherLibrary(&thread_started_event_, &finish_event_,
193 &stack_config_);
194 break;
195 }
196 }
197
WaitForThreadStart()198 void TargetThread::WaitForThreadStart() {
199 thread_started_event_.Wait();
200 }
201
SignalThreadToFinish()202 void TargetThread::SignalThreadToFinish() {
203 finish_event_.Signal();
204 }
205
206 // static
207 // Disable inlining for this function so that it gets its own stack frame.
SignalAndWaitUntilSignaled(WaitableEvent * thread_started_event,WaitableEvent * finish_event,const StackConfiguration * stack_config)208 NOINLINE const void* TargetThread::SignalAndWaitUntilSignaled(
209 WaitableEvent* thread_started_event,
210 WaitableEvent* finish_event,
211 const StackConfiguration* stack_config) {
212 if (thread_started_event && finish_event) {
213 thread_started_event->Signal();
214 finish_event->Wait();
215 }
216
217 // Volatile to prevent a tail call to GetProgramCounter().
218 const void* volatile program_counter = GetProgramCounter();
219 return program_counter;
220 }
221
222 // static
223 // Disable inlining for this function so that it gets its own stack frame.
CallWithAlloca(WaitableEvent * thread_started_event,WaitableEvent * finish_event,const StackConfiguration * stack_config)224 NOINLINE const void* TargetThread::CallWithAlloca(
225 WaitableEvent* thread_started_event,
226 WaitableEvent* finish_event,
227 const StackConfiguration* stack_config) {
228 const size_t alloca_size = 100;
229 // Memset to 0 to generate a clean failure.
230 std::memset(alloca(alloca_size), 0, alloca_size);
231
232 SignalAndWaitUntilSignaled(thread_started_event, finish_event, stack_config);
233
234 // Volatile to prevent a tail call to GetProgramCounter().
235 const void* volatile program_counter = GetProgramCounter();
236 return program_counter;
237 }
238
239 // static
CallThroughOtherLibrary(WaitableEvent * thread_started_event,WaitableEvent * finish_event,const StackConfiguration * stack_config)240 NOINLINE const void* TargetThread::CallThroughOtherLibrary(
241 WaitableEvent* thread_started_event,
242 WaitableEvent* finish_event,
243 const StackConfiguration* stack_config) {
244 if (stack_config) {
245 // A function whose arguments are a function accepting void*, and a void*.
246 using InvokeCallbackFunction = void (*)(void (*)(void*), void*);
247 EXPECT_TRUE(stack_config->library);
248 InvokeCallbackFunction function = reinterpret_cast<InvokeCallbackFunction>(
249 GetFunctionPointerFromNativeLibrary(stack_config->library,
250 "InvokeCallbackFunction"));
251 EXPECT_TRUE(function);
252
253 TargetFunctionArgs args = {thread_started_event, finish_event,
254 stack_config};
255 (*function)(&OtherLibraryCallback, &args);
256 }
257
258 // Volatile to prevent a tail call to GetProgramCounter().
259 const void* volatile program_counter = GetProgramCounter();
260 return program_counter;
261 }
262
263 // static
OtherLibraryCallback(void * arg)264 void TargetThread::OtherLibraryCallback(void* arg) {
265 const TargetFunctionArgs* args = static_cast<TargetFunctionArgs*>(arg);
266 SignalAndWaitUntilSignaled(args->thread_started_event, args->finish_event,
267 args->stack_config);
268 // Prevent tail call.
269 volatile int i = 0;
270 ALLOW_UNUSED_LOCAL(i);
271 }
272
273 // static
274 // Disable inlining for this function so that it gets its own stack frame.
GetProgramCounter()275 NOINLINE const void* TargetThread::GetProgramCounter() {
276 #if defined(OS_WIN)
277 return _ReturnAddress();
278 #else
279 return __builtin_return_address(0);
280 #endif
281 }
282
283 // Profile consists of a set of internal frame sets and other sampling
284 // information.
285 struct Profile {
286 Profile() = default;
287 Profile(Profile&& other) = default;
288 Profile(const InternalFrameSets& frame_sets,
289 int annotation_count,
290 TimeDelta profile_duration,
291 TimeDelta sampling_period);
292
293 ~Profile() = default;
294
295 Profile& operator=(Profile&& other) = default;
296
297 // The collected internal frame sets.
298 InternalFrameSets frame_sets;
299
300 // The number of invocations of RecordAnnotations().
301 int annotation_count;
302
303 // Duration of this profile.
304 TimeDelta profile_duration;
305
306 // Time between samples.
307 TimeDelta sampling_period;
308 };
309
Profile(const InternalFrameSets & frame_sets,int annotation_count,TimeDelta profile_duration,TimeDelta sampling_period)310 Profile::Profile(const InternalFrameSets& frame_sets,
311 int annotation_count,
312 TimeDelta profile_duration,
313 TimeDelta sampling_period)
314 : frame_sets(frame_sets),
315 annotation_count(annotation_count),
316 profile_duration(profile_duration),
317 sampling_period(sampling_period) {}
318
319 // The callback type used to collect a profile. The passed Profile is move-only.
320 // Other threads, including the UI thread, may block on callback completion so
321 // this should run as quickly as possible.
322 using ProfileCompletedCallback = Callback<void(Profile)>;
323
324 // TestProfileBuilder collects internal frames produced by the profiler.
325 class TestProfileBuilder : public StackSamplingProfiler::ProfileBuilder {
326 public:
327 TestProfileBuilder(const ProfileCompletedCallback& callback);
328
329 ~TestProfileBuilder() override;
330
331 // StackSamplingProfiler::ProfileBuilder:
332 void RecordAnnotations() override;
333 void OnSampleCompleted(InternalFrames internal_frames) override;
334 void OnProfileCompleted(TimeDelta profile_duration,
335 TimeDelta sampling_period) override;
336
337 private:
338 // The sets of internal frames recorded.
339 std::vector<InternalFrames> frame_sets_;
340
341 // The number of invocations of RecordAnnotations().
342 int annotation_count_ = 0;
343
344 // Callback made when sampling a profile completes.
345 const ProfileCompletedCallback callback_;
346
347 DISALLOW_COPY_AND_ASSIGN(TestProfileBuilder);
348 };
349
TestProfileBuilder(const ProfileCompletedCallback & callback)350 TestProfileBuilder::TestProfileBuilder(const ProfileCompletedCallback& callback)
351 : callback_(callback) {}
352
353 TestProfileBuilder::~TestProfileBuilder() = default;
354
RecordAnnotations()355 void TestProfileBuilder::RecordAnnotations() {
356 ++annotation_count_;
357 }
358
OnSampleCompleted(InternalFrames internal_frames)359 void TestProfileBuilder::OnSampleCompleted(InternalFrames internal_frames) {
360 frame_sets_.push_back(std::move(internal_frames));
361 }
362
OnProfileCompleted(TimeDelta profile_duration,TimeDelta sampling_period)363 void TestProfileBuilder::OnProfileCompleted(TimeDelta profile_duration,
364 TimeDelta sampling_period) {
365 callback_.Run(Profile(frame_sets_, annotation_count_, profile_duration,
366 sampling_period));
367 }
368
369 // Loads the other library, which defines a function to be called in the
370 // WITH_OTHER_LIBRARY configuration.
LoadOtherLibrary()371 NativeLibrary LoadOtherLibrary() {
372 // The lambda gymnastics works around the fact that we can't use ASSERT_*
373 // macros in a function returning non-null.
374 const auto load = [](NativeLibrary* library) {
375 FilePath other_library_path;
376 ASSERT_TRUE(PathService::Get(DIR_EXE, &other_library_path));
377 other_library_path = other_library_path.AppendASCII(
378 GetNativeLibraryName("base_profiler_test_support_library"));
379 NativeLibraryLoadError load_error;
380 *library = LoadNativeLibrary(other_library_path, &load_error);
381 ASSERT_TRUE(*library) << "error loading " << other_library_path.value()
382 << ": " << load_error.ToString();
383 };
384
385 NativeLibrary library = nullptr;
386 load(&library);
387 return library;
388 }
389
390 // Unloads |library| and returns when it has completed unloading. Unloading a
391 // library is asynchronous on Windows, so simply calling UnloadNativeLibrary()
392 // is insufficient to ensure it's been unloaded.
SynchronousUnloadNativeLibrary(NativeLibrary library)393 void SynchronousUnloadNativeLibrary(NativeLibrary library) {
394 UnloadNativeLibrary(library);
395 #if defined(OS_WIN)
396 // NativeLibrary is a typedef for HMODULE, which is actually the base address
397 // of the module.
398 uintptr_t module_base_address = reinterpret_cast<uintptr_t>(library);
399 HMODULE module_handle;
400 // Keep trying to get the module handle until the call fails.
401 while (::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
402 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
403 reinterpret_cast<LPCTSTR>(module_base_address),
404 &module_handle) ||
405 ::GetLastError() != ERROR_MOD_NOT_FOUND) {
406 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
407 }
408 #elif defined(OS_MACOSX)
409 // Unloading a library on the Mac is synchronous.
410 #else
411 NOTIMPLEMENTED();
412 #endif
413 }
414
415 // Executes the function with the target thread running and executing within
416 // SignalAndWaitUntilSignaled(). Performs all necessary target thread startup
417 // and shutdown work before and afterward.
418 template <class Function>
WithTargetThread(Function function,const StackConfiguration & stack_config)419 void WithTargetThread(Function function,
420 const StackConfiguration& stack_config) {
421 TargetThread target_thread(stack_config);
422 PlatformThreadHandle target_thread_handle;
423 EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle));
424
425 target_thread.WaitForThreadStart();
426
427 function(target_thread.id());
428
429 target_thread.SignalThreadToFinish();
430
431 PlatformThread::Join(target_thread_handle);
432 }
433
434 template <class Function>
WithTargetThread(Function function)435 void WithTargetThread(Function function) {
436 WithTargetThread(function, StackConfiguration(StackConfiguration::NORMAL));
437 }
438
439 struct TestProfilerInfo {
TestProfilerInfobase::__anon480abaac0111::TestProfilerInfo440 TestProfilerInfo(PlatformThreadId thread_id,
441 const SamplingParams& params,
442 NativeStackSamplerTestDelegate* delegate = nullptr)
443 : completed(WaitableEvent::ResetPolicy::MANUAL,
444 WaitableEvent::InitialState::NOT_SIGNALED),
445 profiler(thread_id,
446 params,
447 std::make_unique<TestProfileBuilder>(
448 BindLambdaForTesting([this](Profile result_profile) {
449 profile = std::move(result_profile);
450 completed.Signal();
451 })),
452 delegate) {}
453
454 // The order here is important to ensure objects being referenced don't get
455 // destructed until after the objects referencing them.
456 Profile profile;
457 WaitableEvent completed;
458 StackSamplingProfiler profiler;
459
460 private:
461 DISALLOW_COPY_AND_ASSIGN(TestProfilerInfo);
462 };
463
464 // Creates multiple profilers based on a vector of parameters.
CreateProfilers(PlatformThreadId target_thread_id,const std::vector<SamplingParams> & params)465 std::vector<std::unique_ptr<TestProfilerInfo>> CreateProfilers(
466 PlatformThreadId target_thread_id,
467 const std::vector<SamplingParams>& params) {
468 DCHECK(!params.empty());
469
470 std::vector<std::unique_ptr<TestProfilerInfo>> profilers;
471 for (size_t i = 0; i < params.size(); ++i) {
472 profilers.push_back(
473 std::make_unique<TestProfilerInfo>(target_thread_id, params[i]));
474 }
475
476 return profilers;
477 }
478
479 // Captures internal frames as specified by |params| on the TargetThread, and
480 // returns them. Waits up to |profiler_wait_time| for the profiler to complete.
CaptureFrameSets(const SamplingParams & params,TimeDelta profiler_wait_time)481 InternalFrameSets CaptureFrameSets(const SamplingParams& params,
482 TimeDelta profiler_wait_time) {
483 InternalFrameSets frame_sets;
484 WithTargetThread([¶ms, &frame_sets,
485 profiler_wait_time](PlatformThreadId target_thread_id) {
486 TestProfilerInfo info(target_thread_id, params);
487 info.profiler.Start();
488 info.completed.TimedWait(profiler_wait_time);
489 info.profiler.Stop();
490 info.completed.Wait();
491 frame_sets = std::move(info.profile.frame_sets);
492 });
493
494 return frame_sets;
495 }
496
497 // Waits for one of multiple samplings to complete.
WaitForSamplingComplete(const std::vector<std::unique_ptr<TestProfilerInfo>> & infos)498 size_t WaitForSamplingComplete(
499 const std::vector<std::unique_ptr<TestProfilerInfo>>& infos) {
500 // Map unique_ptrs to something that WaitMany can accept.
501 std::vector<WaitableEvent*> sampling_completed_rawptrs(infos.size());
502 std::transform(infos.begin(), infos.end(), sampling_completed_rawptrs.begin(),
503 [](const std::unique_ptr<TestProfilerInfo>& info) {
504 return &info.get()->completed;
505 });
506 // Wait for one profiler to finish.
507 return WaitableEvent::WaitMany(sampling_completed_rawptrs.data(),
508 sampling_completed_rawptrs.size());
509 }
510
511 // If this executable was linked with /INCREMENTAL (the default for non-official
512 // debug and release builds on Windows), function addresses do not correspond to
513 // function code itself, but instead to instructions in the Incremental Link
514 // Table that jump to the functions. Checks for a jump instruction and if
515 // present does a little decompilation to find the function's actual starting
516 // address.
MaybeFixupFunctionAddressForILT(const void * function_address)517 const void* MaybeFixupFunctionAddressForILT(const void* function_address) {
518 #if defined(_WIN64)
519 const unsigned char* opcode =
520 reinterpret_cast<const unsigned char*>(function_address);
521 if (*opcode == 0xe9) {
522 // This is a relative jump instruction. Assume we're in the ILT and compute
523 // the function start address from the instruction offset.
524 const int32_t* offset = reinterpret_cast<const int32_t*>(opcode + 1);
525 const unsigned char* next_instruction =
526 reinterpret_cast<const unsigned char*>(offset + 1);
527 return next_instruction + *offset;
528 }
529 #endif
530 return function_address;
531 }
532
533 // Searches through the frames in |sample|, returning an iterator to the first
534 // frame that has an instruction pointer within |target_function|. Returns
535 // sample.end() if no such frames are found.
FindFirstFrameWithinFunction(const InternalFrames & frames,TargetFunction target_function)536 InternalFrames::const_iterator FindFirstFrameWithinFunction(
537 const InternalFrames& frames,
538 TargetFunction target_function) {
539 uintptr_t function_start =
540 reinterpret_cast<uintptr_t>(MaybeFixupFunctionAddressForILT(
541 reinterpret_cast<const void*>(target_function)));
542 uintptr_t function_end =
543 reinterpret_cast<uintptr_t>(target_function(nullptr, nullptr, nullptr));
544 for (auto it = frames.begin(); it != frames.end(); ++it) {
545 if (it->instruction_pointer >= function_start &&
546 it->instruction_pointer <= function_end) {
547 return it;
548 }
549 }
550 return frames.end();
551 }
552
553 // Formats a sample into a string that can be output for test diagnostics.
FormatSampleForDiagnosticOutput(const InternalFrames & frames)554 std::string FormatSampleForDiagnosticOutput(const InternalFrames& frames) {
555 std::string output;
556 for (const auto& frame : frames) {
557 output += StringPrintf(
558 "0x%p %s\n", reinterpret_cast<const void*>(frame.instruction_pointer),
559 frame.internal_module.filename.AsUTF8Unsafe().c_str());
560 }
561 return output;
562 }
563
564 // Returns a duration that is longer than the test timeout. We would use
565 // TimeDelta::Max() but https://crbug.com/465948.
AVeryLongTimeDelta()566 TimeDelta AVeryLongTimeDelta() {
567 return TimeDelta::FromDays(1);
568 }
569
570 // Tests the scenario where the library is unloaded after copying the stack, but
571 // before walking it. If |wait_until_unloaded| is true, ensures that the
572 // asynchronous library loading has completed before walking the stack. If
573 // false, the unloading may still be occurring during the stack walk.
TestLibraryUnload(bool wait_until_unloaded)574 void TestLibraryUnload(bool wait_until_unloaded) {
575 // Test delegate that supports intervening between the copying of the stack
576 // and the walking of the stack.
577 class StackCopiedSignaler : public NativeStackSamplerTestDelegate {
578 public:
579 StackCopiedSignaler(WaitableEvent* stack_copied,
580 WaitableEvent* start_stack_walk,
581 bool wait_to_walk_stack)
582 : stack_copied_(stack_copied),
583 start_stack_walk_(start_stack_walk),
584 wait_to_walk_stack_(wait_to_walk_stack) {}
585
586 void OnPreStackWalk() override {
587 stack_copied_->Signal();
588 if (wait_to_walk_stack_)
589 start_stack_walk_->Wait();
590 }
591
592 private:
593 WaitableEvent* const stack_copied_;
594 WaitableEvent* const start_stack_walk_;
595 const bool wait_to_walk_stack_;
596 };
597
598 SamplingParams params;
599 params.sampling_interval = TimeDelta::FromMilliseconds(0);
600 params.samples_per_profile = 1;
601
602 NativeLibrary other_library = LoadOtherLibrary();
603 TargetThread target_thread(StackConfiguration(
604 StackConfiguration::WITH_OTHER_LIBRARY, other_library));
605
606 PlatformThreadHandle target_thread_handle;
607 EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle));
608
609 target_thread.WaitForThreadStart();
610
611 WaitableEvent sampling_thread_completed(
612 WaitableEvent::ResetPolicy::MANUAL,
613 WaitableEvent::InitialState::NOT_SIGNALED);
614 Profile profile;
615
616 WaitableEvent stack_copied(WaitableEvent::ResetPolicy::MANUAL,
617 WaitableEvent::InitialState::NOT_SIGNALED);
618 WaitableEvent start_stack_walk(WaitableEvent::ResetPolicy::MANUAL,
619 WaitableEvent::InitialState::NOT_SIGNALED);
620 StackCopiedSignaler test_delegate(&stack_copied, &start_stack_walk,
621 wait_until_unloaded);
622 StackSamplingProfiler profiler(
623 target_thread.id(), params,
624 std::make_unique<TestProfileBuilder>(BindLambdaForTesting(
625 [&profile, &sampling_thread_completed](Profile result_profile) {
626 profile = std::move(result_profile);
627 sampling_thread_completed.Signal();
628 })),
629 &test_delegate);
630
631 profiler.Start();
632
633 // Wait for the stack to be copied and the target thread to be resumed.
634 stack_copied.Wait();
635
636 // Cause the target thread to finish, so that it's no longer executing code in
637 // the library we're about to unload.
638 target_thread.SignalThreadToFinish();
639 PlatformThread::Join(target_thread_handle);
640
641 // Unload the library now that it's not being used.
642 if (wait_until_unloaded)
643 SynchronousUnloadNativeLibrary(other_library);
644 else
645 UnloadNativeLibrary(other_library);
646
647 // Let the stack walk commence after unloading the library, if we're waiting
648 // on that event.
649 start_stack_walk.Signal();
650
651 // Wait for the sampling thread to complete and fill out |profile|.
652 sampling_thread_completed.Wait();
653
654 // Look up the frames.
655 ASSERT_EQ(1u, profile.frame_sets.size());
656 const InternalFrames& frames = profile.frame_sets[0];
657
658 // Check that the stack contains a frame for
659 // TargetThread::SignalAndWaitUntilSignaled().
660 InternalFrames::const_iterator end_frame = FindFirstFrameWithinFunction(
661 frames, &TargetThread::SignalAndWaitUntilSignaled);
662 ASSERT_TRUE(end_frame != frames.end())
663 << "Function at "
664 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
665 &TargetThread::SignalAndWaitUntilSignaled))
666 << " was not found in stack:\n"
667 << FormatSampleForDiagnosticOutput(frames);
668
669 if (wait_until_unloaded) {
670 // The stack should look like this, resulting one frame after
671 // SignalAndWaitUntilSignaled. The frame in the now-unloaded library is
672 // not recorded since we can't get module information.
673 //
674 // ... WaitableEvent and system frames ...
675 // TargetThread::SignalAndWaitUntilSignaled
676 // TargetThread::OtherLibraryCallback
677 EXPECT_EQ(2, frames.end() - end_frame)
678 << "Stack:\n"
679 << FormatSampleForDiagnosticOutput(frames);
680 } else {
681 // We didn't wait for the asynchronous unloading to complete, so the results
682 // are non-deterministic: if the library finished unloading we should have
683 // the same stack as |wait_until_unloaded|, if not we should have the full
684 // stack. The important thing is that we should not crash.
685
686 if (frames.end() - end_frame == 2) {
687 // This is the same case as |wait_until_unloaded|.
688 return;
689 }
690
691 // Check that the stack contains a frame for
692 // TargetThread::CallThroughOtherLibrary().
693 InternalFrames::const_iterator other_library_frame =
694 FindFirstFrameWithinFunction(frames,
695 &TargetThread::CallThroughOtherLibrary);
696 ASSERT_TRUE(other_library_frame != frames.end())
697 << "Function at "
698 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
699 &TargetThread::CallThroughOtherLibrary))
700 << " was not found in stack:\n"
701 << FormatSampleForDiagnosticOutput(frames);
702
703 // The stack should look like this, resulting in three frames between
704 // SignalAndWaitUntilSignaled and CallThroughOtherLibrary:
705 //
706 // ... WaitableEvent and system frames ...
707 // TargetThread::SignalAndWaitUntilSignaled
708 // TargetThread::OtherLibraryCallback
709 // InvokeCallbackFunction (in other library)
710 // TargetThread::CallThroughOtherLibrary
711 EXPECT_EQ(3, other_library_frame - end_frame)
712 << "Stack:\n"
713 << FormatSampleForDiagnosticOutput(frames);
714 }
715 }
716
717 // Provide a suitable (and clean) environment for the tests below. All tests
718 // must use this class to ensure that proper clean-up is done and thus be
719 // usable in a later test.
720 class StackSamplingProfilerTest : public testing::Test {
721 public:
SetUp()722 void SetUp() override {
723 // The idle-shutdown time is too long for convenient (and accurate) testing.
724 // That behavior is checked instead by artificially triggering it through
725 // the TestAPI.
726 StackSamplingProfiler::TestAPI::DisableIdleShutdown();
727 }
728
TearDown()729 void TearDown() override {
730 // Be a good citizen and clean up after ourselves. This also re-enables the
731 // idle-shutdown behavior.
732 StackSamplingProfiler::TestAPI::Reset();
733 }
734 };
735
736 } // namespace
737
738 // Checks that the basic expected information is present in sampled internal
739 // frames.
740 //
741 // macOS ASAN is not yet supported - crbug.com/718628.
742 #if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX))
743 #define MAYBE_Basic Basic
744 #else
745 #define MAYBE_Basic DISABLED_Basic
746 #endif
PROFILER_TEST_F(StackSamplingProfilerTest,MAYBE_Basic)747 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_Basic) {
748 SamplingParams params;
749 params.sampling_interval = TimeDelta::FromMilliseconds(0);
750 params.samples_per_profile = 1;
751
752 InternalFrameSets frame_sets = CaptureFrameSets(params, AVeryLongTimeDelta());
753
754 // Check that the size of the frame sets are correct.
755 ASSERT_EQ(1u, frame_sets.size());
756 const InternalFrames& frames = frame_sets[0];
757
758 // Check that all the modules are valid.
759 for (const auto& frame : frames)
760 EXPECT_TRUE(frame.internal_module.is_valid);
761
762 // Check that the stack contains a frame for
763 // TargetThread::SignalAndWaitUntilSignaled().
764 InternalFrames::const_iterator loc = FindFirstFrameWithinFunction(
765 frames, &TargetThread::SignalAndWaitUntilSignaled);
766 ASSERT_TRUE(loc != frames.end())
767 << "Function at "
768 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
769 &TargetThread::SignalAndWaitUntilSignaled))
770 << " was not found in stack:\n"
771 << FormatSampleForDiagnosticOutput(frames);
772 }
773
774 // Checks that the profiler handles stacks containing dynamically-allocated
775 // stack memory.
776 // macOS ASAN is not yet supported - crbug.com/718628.
777 #if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX))
778 #define MAYBE_Alloca Alloca
779 #else
780 #define MAYBE_Alloca DISABLED_Alloca
781 #endif
PROFILER_TEST_F(StackSamplingProfilerTest,MAYBE_Alloca)782 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_Alloca) {
783 SamplingParams params;
784 params.sampling_interval = TimeDelta::FromMilliseconds(0);
785 params.samples_per_profile = 1;
786
787 Profile profile;
788 WithTargetThread(
789 [¶ms, &profile](PlatformThreadId target_thread_id) {
790 WaitableEvent sampling_thread_completed(
791 WaitableEvent::ResetPolicy::MANUAL,
792 WaitableEvent::InitialState::NOT_SIGNALED);
793 StackSamplingProfiler profiler(
794 target_thread_id, params,
795 std::make_unique<TestProfileBuilder>(BindLambdaForTesting(
796 [&profile, &sampling_thread_completed](Profile result_profile) {
797 profile = std::move(result_profile);
798 sampling_thread_completed.Signal();
799 })));
800 profiler.Start();
801 sampling_thread_completed.Wait();
802 },
803 StackConfiguration(StackConfiguration::WITH_ALLOCA));
804
805 // Look up the frames.
806 ASSERT_EQ(1u, profile.frame_sets.size());
807 const InternalFrames& frames = profile.frame_sets[0];
808
809 // Check that the stack contains a frame for
810 // TargetThread::SignalAndWaitUntilSignaled().
811 InternalFrames::const_iterator end_frame = FindFirstFrameWithinFunction(
812 frames, &TargetThread::SignalAndWaitUntilSignaled);
813 ASSERT_TRUE(end_frame != frames.end())
814 << "Function at "
815 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
816 &TargetThread::SignalAndWaitUntilSignaled))
817 << " was not found in stack:\n"
818 << FormatSampleForDiagnosticOutput(frames);
819
820 // Check that the stack contains a frame for TargetThread::CallWithAlloca().
821 InternalFrames::const_iterator alloca_frame =
822 FindFirstFrameWithinFunction(frames, &TargetThread::CallWithAlloca);
823 ASSERT_TRUE(alloca_frame != frames.end())
824 << "Function at "
825 << MaybeFixupFunctionAddressForILT(
826 reinterpret_cast<const void*>(&TargetThread::CallWithAlloca))
827 << " was not found in stack:\n"
828 << FormatSampleForDiagnosticOutput(frames);
829
830 // These frames should be adjacent on the stack.
831 EXPECT_EQ(1, alloca_frame - end_frame)
832 << "Stack:\n"
833 << FormatSampleForDiagnosticOutput(frames);
834 }
835
836 // Checks that a profiler can stop/destruct without ever having started.
PROFILER_TEST_F(StackSamplingProfilerTest,StopWithoutStarting)837 PROFILER_TEST_F(StackSamplingProfilerTest, StopWithoutStarting) {
838 WithTargetThread([](PlatformThreadId target_thread_id) {
839 SamplingParams params;
840 params.sampling_interval = TimeDelta::FromMilliseconds(0);
841 params.samples_per_profile = 1;
842
843 Profile profile;
844 WaitableEvent sampling_completed(WaitableEvent::ResetPolicy::MANUAL,
845 WaitableEvent::InitialState::NOT_SIGNALED);
846
847 StackSamplingProfiler profiler(
848 target_thread_id, params,
849 std::make_unique<TestProfileBuilder>(BindLambdaForTesting(
850 [&profile, &sampling_completed](Profile result_profile) {
851 profile = std::move(result_profile);
852 sampling_completed.Signal();
853 })));
854
855 profiler.Stop(); // Constructed but never started.
856 EXPECT_FALSE(sampling_completed.IsSignaled());
857 });
858 }
859
860 // Checks that its okay to stop a profiler before it finishes even when the
861 // sampling thread continues to run.
PROFILER_TEST_F(StackSamplingProfilerTest,StopSafely)862 PROFILER_TEST_F(StackSamplingProfilerTest, StopSafely) {
863 // Test delegate that counts samples.
864 class SampleRecordedCounter : public NativeStackSamplerTestDelegate {
865 public:
866 SampleRecordedCounter() = default;
867
868 void OnPreStackWalk() override {
869 AutoLock lock(lock_);
870 ++count_;
871 }
872
873 size_t Get() {
874 AutoLock lock(lock_);
875 return count_;
876 }
877
878 private:
879 Lock lock_;
880 size_t count_ = 0;
881 };
882
883 WithTargetThread([](PlatformThreadId target_thread_id) {
884 SamplingParams params[2];
885
886 // Providing an initial delay makes it more likely that both will be
887 // scheduled before either starts to run. Once started, samples will
888 // run ordered by their scheduled, interleaved times regardless of
889 // whatever interval the thread wakes up.
890 params[0].initial_delay = TimeDelta::FromMilliseconds(10);
891 params[0].sampling_interval = TimeDelta::FromMilliseconds(1);
892 params[0].samples_per_profile = 100000;
893
894 params[1].initial_delay = TimeDelta::FromMilliseconds(10);
895 params[1].sampling_interval = TimeDelta::FromMilliseconds(1);
896 params[1].samples_per_profile = 100000;
897
898 SampleRecordedCounter samples_recorded[size(params)];
899
900 TestProfilerInfo profiler_info0(target_thread_id, params[0],
901 &samples_recorded[0]);
902 TestProfilerInfo profiler_info1(target_thread_id, params[1],
903 &samples_recorded[1]);
904
905 profiler_info0.profiler.Start();
906 profiler_info1.profiler.Start();
907
908 // Wait for both to start accumulating samples. Using a WaitableEvent is
909 // possible but gets complicated later on because there's no way of knowing
910 // if 0 or 1 additional sample will be taken after Stop() and thus no way
911 // of knowing how many Wait() calls to make on it.
912 while (samples_recorded[0].Get() == 0 || samples_recorded[1].Get() == 0)
913 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
914
915 // Ensure that the first sampler can be safely stopped while the second
916 // continues to run. The stopped first profiler will still have a
917 // RecordSampleTask pending that will do nothing when executed because the
918 // collection will have been removed by Stop().
919 profiler_info0.profiler.Stop();
920 profiler_info0.completed.Wait();
921 size_t count0 = samples_recorded[0].Get();
922 size_t count1 = samples_recorded[1].Get();
923
924 // Waiting for the second sampler to collect a couple samples ensures that
925 // the pending RecordSampleTask for the first has executed because tasks are
926 // always ordered by their next scheduled time.
927 while (samples_recorded[1].Get() < count1 + 2)
928 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
929
930 // Ensure that the first profiler didn't do anything since it was stopped.
931 EXPECT_EQ(count0, samples_recorded[0].Get());
932 });
933 }
934
935 // Checks that no internal frames are captured if the profiling is stopped
936 // during the initial delay.
PROFILER_TEST_F(StackSamplingProfilerTest,StopDuringInitialDelay)937 PROFILER_TEST_F(StackSamplingProfilerTest, StopDuringInitialDelay) {
938 SamplingParams params;
939 params.initial_delay = TimeDelta::FromSeconds(60);
940
941 InternalFrameSets frame_sets =
942 CaptureFrameSets(params, TimeDelta::FromMilliseconds(0));
943
944 EXPECT_TRUE(frame_sets.empty());
945 }
946
947 // Checks that tasks can be stopped before completion and incomplete internal
948 // frames are captured.
PROFILER_TEST_F(StackSamplingProfilerTest,StopDuringInterSampleInterval)949 PROFILER_TEST_F(StackSamplingProfilerTest, StopDuringInterSampleInterval) {
950 // Test delegate that counts samples.
951 class SampleRecordedEvent : public NativeStackSamplerTestDelegate {
952 public:
953 SampleRecordedEvent()
954 : sample_recorded_(WaitableEvent::ResetPolicy::MANUAL,
955 WaitableEvent::InitialState::NOT_SIGNALED) {}
956
957 void OnPreStackWalk() override { sample_recorded_.Signal(); }
958
959 void WaitForSample() { sample_recorded_.Wait(); }
960
961 private:
962 WaitableEvent sample_recorded_;
963 };
964
965 WithTargetThread([](PlatformThreadId target_thread_id) {
966 SamplingParams params;
967
968 params.sampling_interval = AVeryLongTimeDelta();
969 params.samples_per_profile = 2;
970
971 SampleRecordedEvent samples_recorded;
972 TestProfilerInfo profiler_info(target_thread_id, params, &samples_recorded);
973
974 profiler_info.profiler.Start();
975
976 // Wait for profiler to start accumulating samples.
977 samples_recorded.WaitForSample();
978
979 // Ensure that it can stop safely.
980 profiler_info.profiler.Stop();
981 profiler_info.completed.Wait();
982
983 EXPECT_EQ(1u, profiler_info.profile.frame_sets.size());
984 });
985 }
986
987 // Checks that we can destroy the profiler while profiling.
PROFILER_TEST_F(StackSamplingProfilerTest,DestroyProfilerWhileProfiling)988 PROFILER_TEST_F(StackSamplingProfilerTest, DestroyProfilerWhileProfiling) {
989 SamplingParams params;
990 params.sampling_interval = TimeDelta::FromMilliseconds(10);
991
992 Profile profile;
993 WithTargetThread([¶ms, &profile](PlatformThreadId target_thread_id) {
994 std::unique_ptr<StackSamplingProfiler> profiler;
995 auto profile_builder = std::make_unique<TestProfileBuilder>(
996 BindLambdaForTesting([&profile](Profile result_profile) {
997 profile = std::move(result_profile);
998 }));
999 profiler.reset(new StackSamplingProfiler(target_thread_id, params,
1000 std::move(profile_builder)));
1001 profiler->Start();
1002 profiler.reset();
1003
1004 // Wait longer than a sample interval to catch any use-after-free actions by
1005 // the profiler thread.
1006 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
1007 });
1008 }
1009
1010 // Checks that the different profilers may be run.
PROFILER_TEST_F(StackSamplingProfilerTest,CanRunMultipleProfilers)1011 PROFILER_TEST_F(StackSamplingProfilerTest, CanRunMultipleProfilers) {
1012 SamplingParams params;
1013 params.sampling_interval = TimeDelta::FromMilliseconds(0);
1014 params.samples_per_profile = 1;
1015
1016 InternalFrameSets frame_sets = CaptureFrameSets(params, AVeryLongTimeDelta());
1017 ASSERT_EQ(1u, frame_sets.size());
1018
1019 frame_sets = CaptureFrameSets(params, AVeryLongTimeDelta());
1020 ASSERT_EQ(1u, frame_sets.size());
1021 }
1022
1023 // Checks that a sampler can be started while another is running.
PROFILER_TEST_F(StackSamplingProfilerTest,MultipleStart)1024 PROFILER_TEST_F(StackSamplingProfilerTest, MultipleStart) {
1025 WithTargetThread([](PlatformThreadId target_thread_id) {
1026 std::vector<SamplingParams> params(2);
1027
1028 params[0].initial_delay = AVeryLongTimeDelta();
1029 params[0].samples_per_profile = 1;
1030
1031 params[1].sampling_interval = TimeDelta::FromMilliseconds(1);
1032 params[1].samples_per_profile = 1;
1033
1034 std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos =
1035 CreateProfilers(target_thread_id, params);
1036
1037 profiler_infos[0]->profiler.Start();
1038 profiler_infos[1]->profiler.Start();
1039 profiler_infos[1]->completed.Wait();
1040 EXPECT_EQ(1u, profiler_infos[1]->profile.frame_sets.size());
1041 });
1042 }
1043
1044 // Checks that the profile duration and the sampling interval are calculated
1045 // correctly. Also checks that RecordAnnotations() is invoked each time a sample
1046 // is recorded.
PROFILER_TEST_F(StackSamplingProfilerTest,ProfileGeneralInfo)1047 PROFILER_TEST_F(StackSamplingProfilerTest, ProfileGeneralInfo) {
1048 WithTargetThread([](PlatformThreadId target_thread_id) {
1049 SamplingParams params;
1050 params.sampling_interval = TimeDelta::FromMilliseconds(1);
1051 params.samples_per_profile = 3;
1052
1053 TestProfilerInfo profiler_info(target_thread_id, params);
1054
1055 profiler_info.profiler.Start();
1056 profiler_info.completed.Wait();
1057 EXPECT_EQ(3u, profiler_info.profile.frame_sets.size());
1058
1059 // The profile duration should be greater than the total sampling intervals.
1060 EXPECT_GT(profiler_info.profile.profile_duration,
1061 profiler_info.profile.sampling_period * 3);
1062
1063 EXPECT_EQ(TimeDelta::FromMilliseconds(1),
1064 profiler_info.profile.sampling_period);
1065
1066 // The number of invocations of RecordAnnotations() should be equal to the
1067 // number of samples recorded.
1068 EXPECT_EQ(3, profiler_info.profile.annotation_count);
1069 });
1070 }
1071
1072 // Checks that the sampling thread can shut down.
PROFILER_TEST_F(StackSamplingProfilerTest,SamplerIdleShutdown)1073 PROFILER_TEST_F(StackSamplingProfilerTest, SamplerIdleShutdown) {
1074 SamplingParams params;
1075 params.sampling_interval = TimeDelta::FromMilliseconds(0);
1076 params.samples_per_profile = 1;
1077
1078 InternalFrameSets frame_sets = CaptureFrameSets(params, AVeryLongTimeDelta());
1079 ASSERT_EQ(1u, frame_sets.size());
1080
1081 // Capture thread should still be running at this point.
1082 ASSERT_TRUE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning());
1083
1084 // Initiate an "idle" shutdown and ensure it happens. Idle-shutdown was
1085 // disabled by the test fixture so the test will fail due to a timeout if
1086 // it does not exit.
1087 StackSamplingProfiler::TestAPI::PerformSamplingThreadIdleShutdown(false);
1088
1089 // While the shutdown has been initiated, the actual exit of the thread still
1090 // happens asynchronously. Watch until the thread actually exits. This test
1091 // will time-out in the case of failure.
1092 while (StackSamplingProfiler::TestAPI::IsSamplingThreadRunning())
1093 PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
1094 }
1095
1096 // Checks that additional requests will restart a stopped profiler.
PROFILER_TEST_F(StackSamplingProfilerTest,WillRestartSamplerAfterIdleShutdown)1097 PROFILER_TEST_F(StackSamplingProfilerTest,
1098 WillRestartSamplerAfterIdleShutdown) {
1099 SamplingParams params;
1100 params.sampling_interval = TimeDelta::FromMilliseconds(0);
1101 params.samples_per_profile = 1;
1102
1103 InternalFrameSets frame_sets = CaptureFrameSets(params, AVeryLongTimeDelta());
1104 ASSERT_EQ(1u, frame_sets.size());
1105
1106 // Capture thread should still be running at this point.
1107 ASSERT_TRUE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning());
1108
1109 // Post a ShutdownTask on the sampling thread which, when executed, will
1110 // mark the thread as EXITING and begin shut down of the thread.
1111 StackSamplingProfiler::TestAPI::PerformSamplingThreadIdleShutdown(false);
1112
1113 // Ensure another capture will start the sampling thread and run.
1114 frame_sets = CaptureFrameSets(params, AVeryLongTimeDelta());
1115 ASSERT_EQ(1u, frame_sets.size());
1116 EXPECT_TRUE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning());
1117 }
1118
1119 // Checks that it's safe to stop a task after it's completed and the sampling
1120 // thread has shut-down for being idle.
PROFILER_TEST_F(StackSamplingProfilerTest,StopAfterIdleShutdown)1121 PROFILER_TEST_F(StackSamplingProfilerTest, StopAfterIdleShutdown) {
1122 WithTargetThread([](PlatformThreadId target_thread_id) {
1123 SamplingParams params;
1124
1125 params.sampling_interval = TimeDelta::FromMilliseconds(1);
1126 params.samples_per_profile = 1;
1127
1128 TestProfilerInfo profiler_info(target_thread_id, params);
1129
1130 profiler_info.profiler.Start();
1131 profiler_info.completed.Wait();
1132
1133 // Capture thread should still be running at this point.
1134 ASSERT_TRUE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning());
1135
1136 // Perform an idle shutdown.
1137 StackSamplingProfiler::TestAPI::PerformSamplingThreadIdleShutdown(false);
1138
1139 // Stop should be safe though its impossible to know at this moment if the
1140 // sampling thread has completely exited or will just "stop soon".
1141 profiler_info.profiler.Stop();
1142 });
1143 }
1144
1145 // Checks that profilers can run both before and after the sampling thread has
1146 // started.
PROFILER_TEST_F(StackSamplingProfilerTest,ProfileBeforeAndAfterSamplingThreadRunning)1147 PROFILER_TEST_F(StackSamplingProfilerTest,
1148 ProfileBeforeAndAfterSamplingThreadRunning) {
1149 WithTargetThread([](PlatformThreadId target_thread_id) {
1150 std::vector<SamplingParams> params(2);
1151
1152 params[0].initial_delay = AVeryLongTimeDelta();
1153 params[0].sampling_interval = TimeDelta::FromMilliseconds(1);
1154 params[0].samples_per_profile = 1;
1155
1156 params[1].initial_delay = TimeDelta::FromMilliseconds(0);
1157 params[1].sampling_interval = TimeDelta::FromMilliseconds(1);
1158 params[1].samples_per_profile = 1;
1159
1160 std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos =
1161 CreateProfilers(target_thread_id, params);
1162
1163 // First profiler is started when there has never been a sampling thread.
1164 EXPECT_FALSE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning());
1165 profiler_infos[0]->profiler.Start();
1166 // Second profiler is started when sampling thread is already running.
1167 EXPECT_TRUE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning());
1168 profiler_infos[1]->profiler.Start();
1169
1170 // Only the second profiler should finish before test times out.
1171 size_t completed_profiler = WaitForSamplingComplete(profiler_infos);
1172 EXPECT_EQ(1U, completed_profiler);
1173 });
1174 }
1175
1176 // Checks that an idle-shutdown task will abort if a new profiler starts
1177 // between when it was posted and when it runs.
PROFILER_TEST_F(StackSamplingProfilerTest,IdleShutdownAbort)1178 PROFILER_TEST_F(StackSamplingProfilerTest, IdleShutdownAbort) {
1179 WithTargetThread([](PlatformThreadId target_thread_id) {
1180 SamplingParams params;
1181
1182 params.sampling_interval = TimeDelta::FromMilliseconds(1);
1183 params.samples_per_profile = 1;
1184
1185 TestProfilerInfo profiler_info(target_thread_id, params);
1186
1187 profiler_info.profiler.Start();
1188 profiler_info.completed.Wait();
1189 EXPECT_EQ(1u, profiler_info.profile.frame_sets.size());
1190
1191 // Perform an idle shutdown but simulate that a new capture is started
1192 // before it can actually run.
1193 StackSamplingProfiler::TestAPI::PerformSamplingThreadIdleShutdown(true);
1194
1195 // Though the shutdown-task has been executed, any actual exit of the
1196 // thread is asynchronous so there is no way to detect that *didn't* exit
1197 // except to wait a reasonable amount of time and then check. Since the
1198 // thread was just running ("perform" blocked until it was), it should
1199 // finish almost immediately and without any waiting for tasks or events.
1200 PlatformThread::Sleep(TimeDelta::FromMilliseconds(200));
1201 EXPECT_TRUE(StackSamplingProfiler::TestAPI::IsSamplingThreadRunning());
1202
1203 // Ensure that it's still possible to run another sampler.
1204 TestProfilerInfo another_info(target_thread_id, params);
1205 another_info.profiler.Start();
1206 another_info.completed.Wait();
1207 EXPECT_EQ(1u, another_info.profile.frame_sets.size());
1208 });
1209 }
1210
1211 // Checks that synchronized multiple sampling requests execute in parallel.
PROFILER_TEST_F(StackSamplingProfilerTest,ConcurrentProfiling_InSync)1212 PROFILER_TEST_F(StackSamplingProfilerTest, ConcurrentProfiling_InSync) {
1213 WithTargetThread([](PlatformThreadId target_thread_id) {
1214 std::vector<SamplingParams> params(2);
1215
1216 // Providing an initial delay makes it more likely that both will be
1217 // scheduled before either starts to run. Once started, samples will
1218 // run ordered by their scheduled, interleaved times regardless of
1219 // whatever interval the thread wakes up. Thus, total execution time
1220 // will be 10ms (delay) + 10x1ms (sampling) + 1/2 timer minimum interval.
1221 params[0].initial_delay = TimeDelta::FromMilliseconds(10);
1222 params[0].sampling_interval = TimeDelta::FromMilliseconds(1);
1223 params[0].samples_per_profile = 9;
1224
1225 params[1].initial_delay = TimeDelta::FromMilliseconds(11);
1226 params[1].sampling_interval = TimeDelta::FromMilliseconds(1);
1227 params[1].samples_per_profile = 8;
1228
1229 std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos =
1230 CreateProfilers(target_thread_id, params);
1231
1232 profiler_infos[0]->profiler.Start();
1233 profiler_infos[1]->profiler.Start();
1234
1235 // Wait for one profiler to finish.
1236 size_t completed_profiler = WaitForSamplingComplete(profiler_infos);
1237
1238 size_t other_profiler = 1 - completed_profiler;
1239 // Wait for the other profiler to finish.
1240 profiler_infos[other_profiler]->completed.Wait();
1241
1242 // Ensure each got the correct number of frame sets.
1243 EXPECT_EQ(9u, profiler_infos[0]->profile.frame_sets.size());
1244 EXPECT_EQ(8u, profiler_infos[1]->profile.frame_sets.size());
1245 });
1246 }
1247
1248 // Checks that several mixed sampling requests execute in parallel.
PROFILER_TEST_F(StackSamplingProfilerTest,ConcurrentProfiling_Mixed)1249 PROFILER_TEST_F(StackSamplingProfilerTest, ConcurrentProfiling_Mixed) {
1250 WithTargetThread([](PlatformThreadId target_thread_id) {
1251 std::vector<SamplingParams> params(3);
1252
1253 params[0].initial_delay = TimeDelta::FromMilliseconds(8);
1254 params[0].sampling_interval = TimeDelta::FromMilliseconds(4);
1255 params[0].samples_per_profile = 10;
1256
1257 params[1].initial_delay = TimeDelta::FromMilliseconds(9);
1258 params[1].sampling_interval = TimeDelta::FromMilliseconds(3);
1259 params[1].samples_per_profile = 10;
1260
1261 params[2].initial_delay = TimeDelta::FromMilliseconds(10);
1262 params[2].sampling_interval = TimeDelta::FromMilliseconds(2);
1263 params[2].samples_per_profile = 10;
1264
1265 std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos =
1266 CreateProfilers(target_thread_id, params);
1267
1268 for (size_t i = 0; i < profiler_infos.size(); ++i)
1269 profiler_infos[i]->profiler.Start();
1270
1271 // Wait for one profiler to finish.
1272 size_t completed_profiler = WaitForSamplingComplete(profiler_infos);
1273 EXPECT_EQ(10u,
1274 profiler_infos[completed_profiler]->profile.frame_sets.size());
1275 // Stop and destroy all profilers, always in the same order. Don't crash.
1276 for (size_t i = 0; i < profiler_infos.size(); ++i)
1277 profiler_infos[i]->profiler.Stop();
1278 for (size_t i = 0; i < profiler_infos.size(); ++i)
1279 profiler_infos[i].reset();
1280 });
1281 }
1282
1283 // Checks that a stack that runs through another library produces a stack with
1284 // the expected functions.
1285 // macOS ASAN is not yet supported - crbug.com/718628.
1286 #if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX))
1287 #define MAYBE_OtherLibrary OtherLibrary
1288 #else
1289 #define MAYBE_OtherLibrary DISABLED_OtherLibrary
1290 #endif
PROFILER_TEST_F(StackSamplingProfilerTest,MAYBE_OtherLibrary)1291 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_OtherLibrary) {
1292 SamplingParams params;
1293 params.sampling_interval = TimeDelta::FromMilliseconds(0);
1294 params.samples_per_profile = 1;
1295
1296 Profile profile;
1297 {
1298 ScopedNativeLibrary other_library(LoadOtherLibrary());
1299 WithTargetThread(
1300 [¶ms, &profile](PlatformThreadId target_thread_id) {
1301 WaitableEvent sampling_thread_completed(
1302 WaitableEvent::ResetPolicy::MANUAL,
1303 WaitableEvent::InitialState::NOT_SIGNALED);
1304 StackSamplingProfiler profiler(
1305 target_thread_id, params,
1306 std::make_unique<TestProfileBuilder>(
1307 BindLambdaForTesting([&profile, &sampling_thread_completed](
1308 Profile result_profile) {
1309 profile = std::move(result_profile);
1310 sampling_thread_completed.Signal();
1311 })));
1312 profiler.Start();
1313 sampling_thread_completed.Wait();
1314 },
1315 StackConfiguration(StackConfiguration::WITH_OTHER_LIBRARY,
1316 other_library.get()));
1317 }
1318
1319 // Look up the frames.
1320 ASSERT_EQ(1u, profile.frame_sets.size());
1321 const InternalFrames& frames = profile.frame_sets[0];
1322
1323 // Check that the stack contains a frame for
1324 // TargetThread::CallThroughOtherLibrary().
1325 InternalFrames::const_iterator other_library_frame =
1326 FindFirstFrameWithinFunction(frames,
1327 &TargetThread::CallThroughOtherLibrary);
1328 ASSERT_TRUE(other_library_frame != frames.end())
1329 << "Function at "
1330 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
1331 &TargetThread::CallThroughOtherLibrary))
1332 << " was not found in stack:\n"
1333 << FormatSampleForDiagnosticOutput(frames);
1334
1335 // Check that the stack contains a frame for
1336 // TargetThread::SignalAndWaitUntilSignaled().
1337 InternalFrames::const_iterator end_frame = FindFirstFrameWithinFunction(
1338 frames, &TargetThread::SignalAndWaitUntilSignaled);
1339 ASSERT_TRUE(end_frame != frames.end())
1340 << "Function at "
1341 << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
1342 &TargetThread::SignalAndWaitUntilSignaled))
1343 << " was not found in stack:\n"
1344 << FormatSampleForDiagnosticOutput(frames);
1345
1346 // The stack should look like this, resulting in three frames between
1347 // SignalAndWaitUntilSignaled and CallThroughOtherLibrary:
1348 //
1349 // ... WaitableEvent and system frames ...
1350 // TargetThread::SignalAndWaitUntilSignaled
1351 // TargetThread::OtherLibraryCallback
1352 // InvokeCallbackFunction (in other library)
1353 // TargetThread::CallThroughOtherLibrary
1354 EXPECT_EQ(3, other_library_frame - end_frame)
1355 << "Stack:\n"
1356 << FormatSampleForDiagnosticOutput(frames);
1357 }
1358
1359 // Checks that a stack that runs through a library that is unloading produces a
1360 // stack, and doesn't crash.
1361 // Unloading is synchronous on the Mac, so this test is inapplicable.
1362 #if !defined(OS_MACOSX)
1363 #define MAYBE_UnloadingLibrary UnloadingLibrary
1364 #else
1365 #define MAYBE_UnloadingLibrary DISABLED_UnloadingLibrary
1366 #endif
PROFILER_TEST_F(StackSamplingProfilerTest,MAYBE_UnloadingLibrary)1367 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_UnloadingLibrary) {
1368 TestLibraryUnload(false);
1369 }
1370
1371 // Checks that a stack that runs through a library that has been unloaded
1372 // produces a stack, and doesn't crash.
1373 // macOS ASAN is not yet supported - crbug.com/718628.
1374 #if !(defined(ADDRESS_SANITIZER) && defined(OS_MACOSX))
1375 #define MAYBE_UnloadedLibrary UnloadedLibrary
1376 #else
1377 #define MAYBE_UnloadedLibrary DISABLED_UnloadedLibrary
1378 #endif
PROFILER_TEST_F(StackSamplingProfilerTest,MAYBE_UnloadedLibrary)1379 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_UnloadedLibrary) {
1380 TestLibraryUnload(true);
1381 }
1382
1383 // Checks that different threads can be sampled in parallel.
PROFILER_TEST_F(StackSamplingProfilerTest,MultipleSampledThreads)1384 PROFILER_TEST_F(StackSamplingProfilerTest, MultipleSampledThreads) {
1385 // Create target threads. The extra parethesis around the StackConfiguration
1386 // call are to avoid the most-vexing-parse problem.
1387 TargetThread target_thread1((StackConfiguration(StackConfiguration::NORMAL)));
1388 TargetThread target_thread2((StackConfiguration(StackConfiguration::NORMAL)));
1389 PlatformThreadHandle target_thread_handle1, target_thread_handle2;
1390 EXPECT_TRUE(
1391 PlatformThread::Create(0, &target_thread1, &target_thread_handle1));
1392 EXPECT_TRUE(
1393 PlatformThread::Create(0, &target_thread2, &target_thread_handle2));
1394 target_thread1.WaitForThreadStart();
1395 target_thread2.WaitForThreadStart();
1396
1397 // Providing an initial delay makes it more likely that both will be
1398 // scheduled before either starts to run. Once started, samples will
1399 // run ordered by their scheduled, interleaved times regardless of
1400 // whatever interval the thread wakes up.
1401 SamplingParams params1, params2;
1402 params1.initial_delay = TimeDelta::FromMilliseconds(10);
1403 params1.sampling_interval = TimeDelta::FromMilliseconds(1);
1404 params1.samples_per_profile = 9;
1405 params2.initial_delay = TimeDelta::FromMilliseconds(10);
1406 params2.sampling_interval = TimeDelta::FromMilliseconds(1);
1407 params2.samples_per_profile = 8;
1408
1409 Profile profile1, profile2;
1410
1411 WaitableEvent sampling_thread_completed1(
1412 WaitableEvent::ResetPolicy::MANUAL,
1413 WaitableEvent::InitialState::NOT_SIGNALED);
1414 StackSamplingProfiler profiler1(
1415 target_thread1.id(), params1,
1416 std::make_unique<TestProfileBuilder>(BindLambdaForTesting(
1417 [&profile1, &sampling_thread_completed1](Profile result_profile) {
1418 profile1 = std::move(result_profile);
1419 sampling_thread_completed1.Signal();
1420 })));
1421
1422 WaitableEvent sampling_thread_completed2(
1423 WaitableEvent::ResetPolicy::MANUAL,
1424 WaitableEvent::InitialState::NOT_SIGNALED);
1425 StackSamplingProfiler profiler2(
1426 target_thread2.id(), params2,
1427 std::make_unique<TestProfileBuilder>(BindLambdaForTesting(
1428 [&profile2, &sampling_thread_completed2](Profile result_profile) {
1429 profile2 = std::move(result_profile);
1430 sampling_thread_completed2.Signal();
1431 })));
1432
1433 // Finally the real work.
1434 profiler1.Start();
1435 profiler2.Start();
1436 sampling_thread_completed1.Wait();
1437 sampling_thread_completed2.Wait();
1438 EXPECT_EQ(9u, profile1.frame_sets.size());
1439 EXPECT_EQ(8u, profile2.frame_sets.size());
1440
1441 target_thread1.SignalThreadToFinish();
1442 target_thread2.SignalThreadToFinish();
1443 PlatformThread::Join(target_thread_handle1);
1444 PlatformThread::Join(target_thread_handle2);
1445 }
1446
1447 // A simple thread that runs a profiler on another thread.
1448 class ProfilerThread : public SimpleThread {
1449 public:
ProfilerThread(const std::string & name,PlatformThreadId thread_id,const SamplingParams & params)1450 ProfilerThread(const std::string& name,
1451 PlatformThreadId thread_id,
1452 const SamplingParams& params)
1453 : SimpleThread(name, Options()),
1454 run_(WaitableEvent::ResetPolicy::MANUAL,
1455 WaitableEvent::InitialState::NOT_SIGNALED),
1456 completed_(WaitableEvent::ResetPolicy::MANUAL,
1457 WaitableEvent::InitialState::NOT_SIGNALED),
1458 profiler_(thread_id,
1459 params,
1460 std::make_unique<TestProfileBuilder>(
1461 BindLambdaForTesting([this](Profile result_profile) {
1462 profile_ = std::move(result_profile);
1463 completed_.Signal();
1464 }))) {}
1465
Run()1466 void Run() override {
1467 run_.Wait();
1468 profiler_.Start();
1469 }
1470
Go()1471 void Go() { run_.Signal(); }
1472
Wait()1473 void Wait() { completed_.Wait(); }
1474
profile()1475 Profile& profile() { return profile_; }
1476
1477 private:
1478 WaitableEvent run_;
1479
1480 Profile profile_;
1481 WaitableEvent completed_;
1482 StackSamplingProfiler profiler_;
1483 };
1484
1485 // Checks that different threads can run samplers in parallel.
PROFILER_TEST_F(StackSamplingProfilerTest,MultipleProfilerThreads)1486 PROFILER_TEST_F(StackSamplingProfilerTest, MultipleProfilerThreads) {
1487 WithTargetThread([](PlatformThreadId target_thread_id) {
1488 // Providing an initial delay makes it more likely that both will be
1489 // scheduled before either starts to run. Once started, samples will
1490 // run ordered by their scheduled, interleaved times regardless of
1491 // whatever interval the thread wakes up.
1492 SamplingParams params1, params2;
1493 params1.initial_delay = TimeDelta::FromMilliseconds(10);
1494 params1.sampling_interval = TimeDelta::FromMilliseconds(1);
1495 params1.samples_per_profile = 9;
1496 params2.initial_delay = TimeDelta::FromMilliseconds(10);
1497 params2.sampling_interval = TimeDelta::FromMilliseconds(1);
1498 params2.samples_per_profile = 8;
1499
1500 // Start the profiler threads and give them a moment to get going.
1501 ProfilerThread profiler_thread1("profiler1", target_thread_id, params1);
1502 ProfilerThread profiler_thread2("profiler2", target_thread_id, params2);
1503 profiler_thread1.Start();
1504 profiler_thread2.Start();
1505 PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
1506
1507 // This will (approximately) synchronize the two threads.
1508 profiler_thread1.Go();
1509 profiler_thread2.Go();
1510
1511 // Wait for them both to finish and validate collection.
1512 profiler_thread1.Wait();
1513 profiler_thread2.Wait();
1514 EXPECT_EQ(9u, profiler_thread1.profile().frame_sets.size());
1515 EXPECT_EQ(8u, profiler_thread2.profile().frame_sets.size());
1516
1517 profiler_thread1.Join();
1518 profiler_thread2.Join();
1519 });
1520 }
1521
1522 } // namespace base
1523