• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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