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<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 void** CaptureStackTrace(void** frames, size_t max_entries, size_t* count); 104 105 static void Init(); 106 static SamplingHeapProfiler* Get(); 107 108 SamplingHeapProfiler(const SamplingHeapProfiler&) = delete; 109 SamplingHeapProfiler& operator=(const SamplingHeapProfiler&) = delete; 110 111 // ThreadIdNameManager::Observer implementation: 112 void OnThreadNameChanged(const char* name) override; 113 114 private: 115 SamplingHeapProfiler(); 116 ~SamplingHeapProfiler() override; 117 118 // PoissonAllocationSampler::SamplesObserver 119 void SampleAdded(void* address, 120 size_t size, 121 size_t total, 122 base::allocator::dispatcher::AllocationSubsystem type, 123 const char* context) override; 124 void SampleRemoved(void* address) override; 125 126 void CaptureNativeStack(const char* context, Sample* sample); 127 const char* RecordString(const char* string) EXCLUSIVE_LOCKS_REQUIRED(mutex_); 128 129 // Delete all samples recorded, to ensure the profiler is in a consistent 130 // state at the beginning of a test. This should only be called within the 131 // scope of a PoissonAllocationSampler::ScopedMuteHookedSamplesForTesting so 132 // that new hooked samples don't arrive while it's running. 133 void ClearSamplesForTesting(); 134 135 // Mutex to access |samples_| and |strings_|. 136 Lock mutex_; 137 138 // Samples of the currently live allocations. 139 std::unordered_map<void*, Sample> samples_ GUARDED_BY(mutex_); 140 141 // Contains pointers to static sample context strings that are never deleted. 142 std::unordered_set<const char*> strings_ GUARDED_BY(mutex_); 143 144 // Mutex to make |running_sessions_| and Add/Remove samples observer access 145 // atomic. 146 Lock start_stop_mutex_; 147 148 // Number of the running sessions. 149 int running_sessions_ = 0; 150 151 // Last sample ordinal used to mark samples recorded during single session. 152 std::atomic<uint32_t> last_sample_ordinal_{1}; 153 154 // Whether it should record thread names. 155 std::atomic<bool> record_thread_names_{false}; 156 157 // Which unwinder to use. 158 std::atomic<StackUnwinder> unwinder_{StackUnwinder::kDefault}; 159 160 friend class heap_profiling::HeapProfilerControllerTest; 161 friend class NoDestructor<SamplingHeapProfiler>; 162 friend class SamplingHeapProfilerTest; 163 }; 164 165 } // namespace base 166 167 #endif // BASE_SAMPLING_HEAP_PROFILER_SAMPLING_HEAP_PROFILER_H_ 168