1 // Copyright 2019 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 #ifndef BASE_PROFILER_STACK_SAMPLING_PROFILER_TEST_UTIL_H_
6 #define BASE_PROFILER_STACK_SAMPLING_PROFILER_TEST_UTIL_H_
7 
8 #include <memory>
9 #include <vector>
10 
11 #include "base/callback.h"
12 #include "base/native_library.h"
13 #include "base/profiler/frame.h"
14 #include "base/profiler/sampling_profiler_thread_token.h"
15 #include "base/profiler/stack_sampling_profiler.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/threading/platform_thread.h"
18 
19 namespace base {
20 
21 class Unwinder;
22 class ModuleCache;
23 
24 // A thread to target for profiling that will run the supplied closure.
25 class TargetThread : public PlatformThread::Delegate {
26  public:
27   TargetThread(OnceClosure to_run);
28   ~TargetThread() override;
29 
30   // PlatformThread::Delegate:
31   void ThreadMain() override;
32 
thread_token()33   SamplingProfilerThreadToken thread_token() const { return thread_token_; }
34 
35  private:
36   SamplingProfilerThreadToken thread_token_ = {0};
37   OnceClosure to_run_;
38 
39   DISALLOW_COPY_AND_ASSIGN(TargetThread);
40 };
41 
42 // Addresses near the start and end of a function.
43 struct FunctionAddressRange {
44   const void* start;
45   const void* end;
46 };
47 
48 // Represents a stack unwind scenario to be sampled by the
49 // StackSamplingProfiler.
50 class UnwindScenario {
51  public:
52   // A callback provided by the caller that sets up the unwind scenario, then
53   // calls into the passed closure to wait for a sample to be taken. Returns the
54   // address range of the function that sets up the unwind scenario. The passed
55   // closure will be null when invoked solely to obtain the address range.
56   using SetupFunction = RepeatingCallback<FunctionAddressRange(OnceClosure)>;
57 
58   // Events to coordinate the sampling.
59   struct SampleEvents {
60     WaitableEvent ready_for_sample;
61     WaitableEvent sample_finished;
62   };
63 
64   explicit UnwindScenario(const SetupFunction& setup_function);
65   ~UnwindScenario();
66 
67   UnwindScenario(const UnwindScenario&) = delete;
68   UnwindScenario& operator=(const UnwindScenario&) = delete;
69 
70   // The address range of the innermost function that waits for the sample.
71   FunctionAddressRange GetWaitForSampleAddressRange() const;
72 
73   // The address range of the provided setup function.
74   FunctionAddressRange GetSetupFunctionAddressRange() const;
75 
76   // The address range of the outer function that indirectly invokes the setup
77   // function.
78   FunctionAddressRange GetOuterFunctionAddressRange() const;
79 
80   // Executes the scenario.
81   void Execute(SampleEvents* events);
82 
83  private:
84   static FunctionAddressRange InvokeSetupFunction(
85       const SetupFunction& setup_function,
86       SampleEvents* events);
87 
88   static FunctionAddressRange WaitForSample(SampleEvents* events);
89 
90   const SetupFunction setup_function_;
91 };
92 
93 // UnwindScenario setup function that calls into |wait_for_sample| without doing
94 // any special unwinding setup, to exercise the "normal" unwind scenario.
95 FunctionAddressRange CallWithPlainFunction(OnceClosure wait_for_sample);
96 
97 // Calls into |wait_for_sample| after using alloca(), to test unwinding with a
98 // frame pointer.
99 FunctionAddressRange CallWithAlloca(OnceClosure wait_for_sample);
100 
101 // Calls into |wait_for_sample| through a function within another library, to
102 // test unwinding through multiple modules and scenarios involving unloaded
103 // modules.
104 FunctionAddressRange CallThroughOtherLibrary(NativeLibrary library,
105                                              OnceClosure wait_for_sample);
106 
107 // The callback to perform profiling on the provided thread.
108 using ProfileCallback = OnceCallback<void(SamplingProfilerThreadToken)>;
109 
110 // Executes |profile_callback| while running |scenario| on the target
111 // thread. Performs all necessary target thread startup and shutdown work before
112 // and afterward.
113 void WithTargetThread(UnwindScenario* scenario,
114                       ProfileCallback profile_callback);
115 
116 using UnwinderFactory = OnceCallback<std::unique_ptr<Unwinder>()>;
117 
118 // Returns the sample seen when taking one sample of |scenario|.
119 std::vector<Frame> SampleScenario(
120     UnwindScenario* scenario,
121     ModuleCache* module_cache,
122     UnwinderFactory aux_unwinder_factory = UnwinderFactory());
123 
124 // Formats a sample into a string that can be output for test diagnostics.
125 std::string FormatSampleForDiagnosticOutput(const std::vector<Frame>& sample);
126 
127 // Expects that the stack contains the functions with the specified address
128 // ranges, in the specified order.
129 void ExpectStackContains(const std::vector<Frame>& stack,
130                          const std::vector<FunctionAddressRange>& functions);
131 
132 // Expects that the stack does not contain the functions with the specified
133 // address ranges.
134 void ExpectStackDoesNotContain(
135     const std::vector<Frame>& stack,
136     const std::vector<FunctionAddressRange>& functions);
137 
138 // Loads the other library, which defines a function to be called in the
139 // WITH_OTHER_LIBRARY configuration.
140 NativeLibrary LoadOtherLibrary();
141 
142 uintptr_t GetAddressInOtherLibrary(NativeLibrary library);
143 
144 // Creates a list of core unwinders required for StackSamplingProfilerTest.
145 // This is useful notably on Android, which requires ChromeUnwinderAndroid in
146 // addition to the native one.
147 StackSamplingProfiler::UnwindersFactory CreateCoreUnwindersFactoryForTesting(
148     ModuleCache* module_cache);
149 
150 }  // namespace base
151 
152 #endif  // BASE_PROFILER_STACK_SAMPLING_PROFILER_TEST_UTIL_H_
153