1 // Copyright 2018 The Chromium Authors. All rights reserved. 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 <memory> 9 #include <stack> 10 #include <unordered_map> 11 #include <vector> 12 13 #include "base/base_export.h" 14 #include "base/macros.h" 15 #include "base/synchronization/lock.h" 16 #include "base/threading/thread_local.h" 17 18 namespace base { 19 20 template <typename T> 21 class NoDestructor; 22 23 class LockFreeAddressHashSet; 24 25 // The class implements sampling profiling of native memory heap. 26 // It hooks on base::allocator and base::PartitionAlloc. 27 // When started it selects and records allocation samples based on 28 // the sampling_interval parameter. 29 // The recorded samples can then be retrieved using GetSamples method. 30 class BASE_EXPORT SamplingHeapProfiler { 31 public: 32 class BASE_EXPORT Sample { 33 public: 34 Sample(const Sample&); 35 ~Sample(); 36 37 size_t size; // Allocation size. 38 size_t total; // Total size attributed to the sample. 39 std::vector<void*> stack; 40 41 private: 42 friend class SamplingHeapProfiler; 43 44 Sample(size_t, size_t total, uint32_t ordinal); 45 46 uint32_t ordinal; 47 }; 48 49 class SamplesObserver { 50 public: 51 virtual ~SamplesObserver() = default; 52 virtual void SampleAdded(uint32_t id, size_t size, size_t total) = 0; 53 virtual void SampleRemoved(uint32_t id) = 0; 54 }; 55 56 // Must be called early during the process initialization. It creates and 57 // reserves a TLS slot. 58 static void InitTLSSlot(); 59 60 // This is an entry point for plugging in an external allocator. 61 // Profiler will invoke the provided callback upon initialization. 62 // The callback should install hooks onto the corresponding memory allocator 63 // and make them invoke SamplingHeapProfiler::RecordAlloc and 64 // SamplingHeapProfiler::RecordFree upon corresponding allocation events. 65 // 66 // If the method is called after profiler is initialized, the callback 67 // is invoked right away. 68 static void SetHooksInstallCallback(void (*hooks_install_callback)()); 69 70 void AddSamplesObserver(SamplesObserver*); 71 void RemoveSamplesObserver(SamplesObserver*); 72 73 uint32_t Start(); 74 void Stop(); 75 void SetSamplingInterval(size_t sampling_interval); 76 void SuppressRandomnessForTest(bool suppress); 77 78 std::vector<Sample> GetSamples(uint32_t profile_id); 79 80 static void RecordAlloc(void* address, size_t, uint32_t skip_frames = 0); 81 static void RecordFree(void* address); 82 83 static SamplingHeapProfiler* GetInstance(); 84 85 private: 86 SamplingHeapProfiler(); 87 ~SamplingHeapProfiler() = delete; 88 89 static void InstallAllocatorHooksOnce(); 90 static bool InstallAllocatorHooks(); 91 static size_t GetNextSampleInterval(size_t base_interval); 92 93 void DoRecordAlloc(size_t total_allocated, 94 size_t allocation_size, 95 void* address, 96 uint32_t skip_frames); 97 void DoRecordFree(void* address); 98 void RecordStackTrace(Sample*, uint32_t skip_frames); 99 static LockFreeAddressHashSet& sampled_addresses_set(); 100 101 void BalanceAddressesHashSet(); 102 103 base::ThreadLocalBoolean entered_; 104 base::Lock mutex_; 105 std::stack<std::unique_ptr<LockFreeAddressHashSet>> sampled_addresses_stack_; 106 std::unordered_map<void*, Sample> samples_; 107 std::vector<SamplesObserver*> observers_; 108 uint32_t last_sample_ordinal_ = 1; 109 110 static SamplingHeapProfiler* instance_; 111 112 friend class base::NoDestructor<SamplingHeapProfiler>; 113 114 DISALLOW_COPY_AND_ASSIGN(SamplingHeapProfiler); 115 }; 116 117 } // namespace base 118 119 #endif // BASE_SAMPLING_HEAP_PROFILER_SAMPLING_HEAP_PROFILER_H_ 120