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