xref: /aosp_15_r20/external/cronet/base/sampling_heap_profiler/sampling_heap_profiler.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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