xref: /aosp_15_r20/external/libchrome/base/profiler/stack_sampling_profiler_unittest.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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([&params, &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       [&params, &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([&params, &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         [&params, &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