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