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