xref: /aosp_15_r20/external/cronet/base/profiler/stack_sampling_profiler_test_util.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 The Chromium Authors
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 <string>
10 #include <string_view>
11 #include <vector>
12 
13 #include "base/base_export.h"
14 #include "base/functional/callback.h"
15 #include "base/memory/raw_ptr.h"
16 #include "base/native_library.h"
17 #include "base/profiler/frame.h"
18 #include "base/profiler/sampling_profiler_thread_token.h"
19 #include "base/profiler/stack_sampling_profiler.h"
20 #include "base/synchronization/waitable_event.h"
21 #include "base/threading/platform_thread.h"
22 
23 namespace base {
24 
25 class Unwinder;
26 class ModuleCache;
27 
28 // A thread to target for profiling that will run the supplied closure.
29 class TargetThread : public PlatformThread::Delegate {
30  public:
31   explicit TargetThread(OnceClosure to_run);
32 
33   TargetThread(const TargetThread&) = delete;
34   TargetThread& operator=(const TargetThread&) = delete;
35 
36   ~TargetThread() override;
37 
38   void Start();
39   void Join();
40 
41   // PlatformThread::Delegate:
42   void ThreadMain() override;
43 
thread_token()44   SamplingProfilerThreadToken thread_token() const { return thread_token_; }
45 
46  private:
47   SamplingProfilerThreadToken thread_token_ = {0};
48   OnceClosure to_run_;
49   PlatformThreadHandle target_thread_handle_;
50 };
51 
52 // Addresses near the start and end of a function.
53 struct FunctionAddressRange {
54   raw_ptr<const void> start;
55   raw_ptr<const void> end;
56 };
57 
58 // Represents a stack unwind scenario to be sampled by the
59 // StackSamplingProfiler.
60 class UnwindScenario {
61  public:
62   // A callback provided by the caller that sets up the unwind scenario, then
63   // calls into the passed closure to wait for a sample to be taken. Returns the
64   // address range of the function that sets up the unwind scenario. The passed
65   // closure will be null when invoked solely to obtain the address range.
66   using SetupFunction = RepeatingCallback<FunctionAddressRange(OnceClosure)>;
67 
68   // Events to coordinate the sampling.
69   struct SampleEvents {
70     WaitableEvent ready_for_sample;
71     WaitableEvent sample_finished;
72   };
73 
74   explicit UnwindScenario(const SetupFunction& setup_function);
75   ~UnwindScenario();
76 
77   UnwindScenario(const UnwindScenario&) = delete;
78   UnwindScenario& operator=(const UnwindScenario&) = delete;
79 
80   // The address range of the innermost function that waits for the sample.
81   FunctionAddressRange GetWaitForSampleAddressRange() const;
82 
83   // The address range of the provided setup function.
84   FunctionAddressRange GetSetupFunctionAddressRange() const;
85 
86   // The address range of the outer function that indirectly invokes the setup
87   // function.
88   FunctionAddressRange GetOuterFunctionAddressRange() const;
89 
90   // Executes the scenario.
91   void Execute(SampleEvents* events);
92 
93  private:
94   static FunctionAddressRange InvokeSetupFunction(
95       const SetupFunction& setup_function,
96       SampleEvents* events);
97 
98   static FunctionAddressRange WaitForSample(SampleEvents* events);
99 
100   const SetupFunction setup_function_;
101 };
102 
103 class TestModule : public ModuleCache::Module {
104  public:
105   explicit TestModule(uintptr_t base_address = 0,
106                       size_t size = 0,
107                       bool is_native = true)
base_address_(base_address)108       : base_address_(base_address), size_(size), is_native_(is_native) {}
109 
110   uintptr_t GetBaseAddress() const override;
111   std::string GetId() const override;
112   FilePath GetDebugBasename() const override;
113   size_t GetSize() const override;
114   bool IsNative() const override;
115 
set_id(const std::string & id)116   void set_id(const std::string& id) { id_ = id; }
set_debug_basename(const FilePath & basename)117   void set_debug_basename(const FilePath& basename) {
118     debug_basename_ = basename;
119   }
120 
121  private:
122   const uintptr_t base_address_;
123   const size_t size_;
124   const bool is_native_;
125   std::string id_;
126   FilePath debug_basename_;
127 };
128 
129 bool operator==(const Frame& a, const Frame& b);
130 
131 // UnwindScenario setup function that calls into |wait_for_sample| without doing
132 // any special unwinding setup, to exercise the "normal" unwind scenario.
133 FunctionAddressRange CallWithPlainFunction(OnceClosure wait_for_sample);
134 
135 // Calls into |wait_for_sample| after using alloca(), to test unwinding with a
136 // frame pointer.
137 FunctionAddressRange CallWithAlloca(OnceClosure wait_for_sample);
138 
139 // Calls into |wait_for_sample| through a function within another library, to
140 // test unwinding through multiple modules and scenarios involving unloaded
141 // modules.
142 FunctionAddressRange CallThroughOtherLibrary(NativeLibrary library,
143                                              OnceClosure wait_for_sample);
144 
145 // The callback to perform profiling on the provided thread.
146 using ProfileCallback = OnceCallback<void(SamplingProfilerThreadToken)>;
147 
148 // Executes |profile_callback| while running |scenario| on the target
149 // thread. Performs all necessary target thread startup and shutdown work before
150 // and afterward.
151 void WithTargetThread(UnwindScenario* scenario,
152                       ProfileCallback profile_callback);
153 
154 using UnwinderFactory = OnceCallback<std::unique_ptr<Unwinder>()>;
155 
156 // Returns the sample seen when taking one sample of |scenario|.
157 std::vector<Frame> SampleScenario(
158     UnwindScenario* scenario,
159     ModuleCache* module_cache,
160     UnwinderFactory aux_unwinder_factory = UnwinderFactory());
161 
162 // Formats a sample into a string that can be output for test diagnostics.
163 std::string FormatSampleForDiagnosticOutput(const std::vector<Frame>& sample);
164 
165 // Expects that the stack contains the functions with the specified address
166 // ranges, in the specified order.
167 void ExpectStackContains(const std::vector<Frame>& stack,
168                          const std::vector<FunctionAddressRange>& functions);
169 
170 // Expects that the stack contains the function names in the specified order.
171 void ExpectStackContainsNames(const std::vector<Frame>& stack,
172                               const std::vector<std::string>& function_names);
173 
174 // Expects that the stack does not contain the functions with the specified
175 // address ranges.
176 void ExpectStackDoesNotContain(
177     const std::vector<Frame>& stack,
178     const std::vector<FunctionAddressRange>& functions);
179 
180 // Load test library with given name.
181 NativeLibrary LoadTestLibrary(std::string_view library_name);
182 
183 // Loads the other library, which defines a function to be called in the
184 // WITH_OTHER_LIBRARY configuration.
185 NativeLibrary LoadOtherLibrary();
186 
187 uintptr_t GetAddressInOtherLibrary(NativeLibrary library);
188 
189 // Creates a list of core unwinders required for StackSamplingProfilerTest.
190 // This is useful notably on Android, which requires ChromeUnwinderAndroid in
191 // addition to the native one.
192 StackSamplingProfiler::UnwindersFactory CreateCoreUnwindersFactoryForTesting(
193     ModuleCache* module_cache);
194 
195 }  // namespace base
196 
197 #endif  // BASE_PROFILER_STACK_SAMPLING_PROFILER_TEST_UTIL_H_
198