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