1 // Copyright 2018 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_SAMPLING_HEAP_PROFILER_SAMPLING_HEAP_PROFILER_H_ 6 #define BASE_SAMPLING_HEAP_PROFILER_SAMPLING_HEAP_PROFILER_H_ 7 8 #include <atomic> 9 #include <unordered_map> 10 #include <unordered_set> 11 #include <vector> 12 13 #include "base/base_export.h" 14 #include "base/no_destructor.h" 15 #include "base/sampling_heap_profiler/poisson_allocation_sampler.h" 16 #include "base/synchronization/lock.h" 17 #include "base/thread_annotations.h" 18 #include "base/threading/thread_id_name_manager.h" 19 20 namespace heap_profiling { 21 class HeapProfilerControllerTest; 22 } 23 24 namespace base { 25 26 // The class implements sampling profiling of native memory heap. 27 // It uses PoissonAllocationSampler to aggregate the heap allocations and 28 // record samples. 29 // The recorded samples can then be retrieved using GetSamples method. 30 class BASE_EXPORT SamplingHeapProfiler 31 : private PoissonAllocationSampler::SamplesObserver, 32 public base::ThreadIdNameManager::Observer { 33 public: 34 class BASE_EXPORT Sample { 35 public: 36 Sample(const Sample&); 37 ~Sample(); 38 39 // Allocation size. 40 size_t size; 41 // Total size attributed to the sample. 42 size_t total; 43 // Type of the allocator. 44 base::allocator::dispatcher::AllocationSubsystem allocator; 45 // Context as provided by the allocation hook. 46 const char* context = nullptr; 47 // Name of the thread that made the sampled allocation. 48 const char* thread_name = nullptr; 49 // Call stack of PC addresses responsible for the allocation. 50 std::vector<const void*> stack; 51 52 // Public for testing. 53 Sample(size_t size, size_t total, uint32_t ordinal); 54 55 private: 56 friend class SamplingHeapProfiler; 57 58 59 uint32_t ordinal; 60 }; 61 62 // On Android this is logged to UMA - keep in sync AndroidStackUnwinder in 63 // enums.xml. 64 enum class StackUnwinder { 65 DEPRECATED_kNotChecked, 66 kDefault, 67 DEPRECATED_kCFIBacktrace, 68 kUnavailable, 69 kFramePointers, 70 kMaxValue = kFramePointers, 71 }; 72 73 // Starts collecting allocation samples. Returns the current profile_id. 74 // This value can then be passed to |GetSamples| to retrieve only samples 75 // recorded since the corresponding |Start| invocation. 76 uint32_t Start(); 77 78 // Stops recording allocation samples. 79 void Stop(); 80 81 // Sets sampling interval in bytes. 82 void SetSamplingInterval(size_t sampling_interval_bytes); 83 84 // Enables recording thread name that made the sampled allocation. 85 void SetRecordThreadNames(bool value); 86 87 // Returns the current thread name. 88 static const char* CachedThreadName(); 89 90 // Returns current samples recorded for the profile session. 91 // If |profile_id| is set to the value returned by the |Start| method, 92 // it returns only the samples recorded after the corresponding |Start| 93 // invocation. To retrieve all the collected samples |profile_id| must be 94 // set to 0. 95 std::vector<Sample> GetSamples(uint32_t profile_id); 96 97 // List of strings used in the profile call stacks. 98 std::vector<const char*> GetStrings(); 99 100 // Captures up to |max_entries| stack frames using the buffer pointed by 101 // |frames|. Puts the number of captured frames into the |count| output 102 // parameters. Returns the pointer to the topmost frame. 103 const void** CaptureStackTrace(const void** frames, 104 size_t max_entries, 105 size_t* count); 106 107 static void Init(); 108 static SamplingHeapProfiler* Get(); 109 110 SamplingHeapProfiler(const SamplingHeapProfiler&) = delete; 111 SamplingHeapProfiler& operator=(const SamplingHeapProfiler&) = delete; 112 113 // ThreadIdNameManager::Observer implementation: 114 void OnThreadNameChanged(const char* name) override; 115 116 private: 117 SamplingHeapProfiler(); 118 ~SamplingHeapProfiler() override; 119 120 // PoissonAllocationSampler::SamplesObserver 121 void SampleAdded(void* address, 122 size_t size, 123 size_t total, 124 base::allocator::dispatcher::AllocationSubsystem type, 125 const char* context) override; 126 void SampleRemoved(void* address) override; 127 128 void CaptureNativeStack(const char* context, Sample* sample); 129 const char* RecordString(const char* string) EXCLUSIVE_LOCKS_REQUIRED(mutex_); 130 131 // Delete all samples recorded, to ensure the profiler is in a consistent 132 // state at the beginning of a test. This should only be called within the 133 // scope of a PoissonAllocationSampler::ScopedMuteHookedSamplesForTesting so 134 // that new hooked samples don't arrive while it's running. 135 void ClearSamplesForTesting(); 136 137 // Mutex to access |samples_| and |strings_|. 138 Lock mutex_; 139 140 // Samples of the currently live allocations. 141 std::unordered_map<void*, Sample> samples_ GUARDED_BY(mutex_); 142 143 // Contains pointers to static sample context strings that are never deleted. 144 std::unordered_set<const char*> strings_ GUARDED_BY(mutex_); 145 146 // Mutex to make |running_sessions_| and Add/Remove samples observer access 147 // atomic. 148 Lock start_stop_mutex_; 149 150 // Number of the running sessions. 151 int running_sessions_ = 0; 152 153 // Last sample ordinal used to mark samples recorded during single session. 154 std::atomic<uint32_t> last_sample_ordinal_{1}; 155 156 // Whether it should record thread names. 157 std::atomic<bool> record_thread_names_{false}; 158 159 // Which unwinder to use. 160 std::atomic<StackUnwinder> unwinder_{StackUnwinder::kDefault}; 161 162 friend class heap_profiling::HeapProfilerControllerTest; 163 friend class NoDestructor<SamplingHeapProfiler>; 164 friend class SamplingHeapProfilerTest; 165 }; 166 167 } // namespace base 168 169 #endif // BASE_SAMPLING_HEAP_PROFILER_SAMPLING_HEAP_PROFILER_H_ 170