blob: ea50e67a2da81d7868e93c58bb4171cc1c0fe008 [file] [log] [blame]
Alexei Filippov9fbb7542018-02-07 09:56:571// 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
Alexei Filippov0a57e5d2018-05-23 18:13:555#ifndef BASE_SAMPLING_HEAP_PROFILER_SAMPLING_HEAP_PROFILER_H_
6#define BASE_SAMPLING_HEAP_PROFILER_SAMPLING_HEAP_PROFILER_H_
Alexei Filippov9fbb7542018-02-07 09:56:577
Alexei Filippov0a57e5d2018-05-23 18:13:558#include <memory>
9#include <stack>
Alexei Filippov9fbb7542018-02-07 09:56:5710#include <unordered_map>
11#include <vector>
12
Alexei Filippov83717622018-02-21 21:44:4013#include "base/base_export.h"
Alexei Filippov9fbb7542018-02-07 09:56:5714#include "base/macros.h"
15#include "base/synchronization/lock.h"
16#include "base/threading/thread_local.h"
Alexei Filippov9fbb7542018-02-07 09:56:5717
18namespace base {
Alexei Filippov83717622018-02-21 21:44:4019
Alexei Filippov9fbb7542018-02-07 09:56:5720template <typename T>
Alexei Filippov83717622018-02-21 21:44:4021class NoDestructor;
Alexei Filippov9fbb7542018-02-07 09:56:5722
Alexei Filippov0bed5b242018-07-04 02:08:3823class LockFreeAddressHashSet;
24
Alexei Filippov83717622018-02-21 21:44:4025// 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.
30class BASE_EXPORT SamplingHeapProfiler {
Alexei Filippov9fbb7542018-02-07 09:56:5731 public:
Alexei Filippov83717622018-02-21 21:44:4032 class BASE_EXPORT Sample {
Alexei Filippov9fbb7542018-02-07 09:56:5733 public:
Alexei Filippov83717622018-02-21 21:44:4034 Sample(const Sample&);
35 ~Sample();
36
Alexei Filippove6633efc2018-03-01 19:31:5837 size_t size; // Allocation size.
38 size_t total; // Total size attributed to the sample.
Alexei Filippov9fbb7542018-02-07 09:56:5739 std::vector<void*> stack;
40
41 private:
42 friend class SamplingHeapProfiler;
43
Alexei Filippove6633efc2018-03-01 19:31:5844 Sample(size_t, size_t total, uint32_t ordinal);
Alexei Filippov9fbb7542018-02-07 09:56:5745
46 uint32_t ordinal;
47 };
48
Alexei Filippov05852612018-02-10 08:22:2949 class SamplesObserver {
50 public:
51 virtual ~SamplesObserver() = default;
Alexei Filippove6633efc2018-03-01 19:31:5852 virtual void SampleAdded(uint32_t id, size_t size, size_t total) = 0;
Alexei Filippov05852612018-02-10 08:22:2953 virtual void SampleRemoved(uint32_t id) = 0;
54 };
55
Alexei Filippovb956afc2018-03-12 22:41:0856 // Must be called early during the process initialization. It creates and
57 // reserves a TLS slot.
58 static void InitTLSSlot();
59
Alexei Filippov1eb85b5b2018-02-22 03:58:4760 // 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
Alexei Filippov05852612018-02-10 08:22:2970 void AddSamplesObserver(SamplesObserver*);
71 void RemoveSamplesObserver(SamplesObserver*);
72
Alexei Filippov9fbb7542018-02-07 09:56:5773 uint32_t Start();
74 void Stop();
75 void SetSamplingInterval(size_t sampling_interval);
Alexei Filippovc3857682018-03-01 05:23:0476 void SuppressRandomnessForTest(bool suppress);
Alexei Filippov9fbb7542018-02-07 09:56:5777
78 std::vector<Sample> GetSamples(uint32_t profile_id);
79
Alexei Filippov1eb85b5b2018-02-22 03:58:4780 static void RecordAlloc(void* address, size_t, uint32_t skip_frames = 0);
81 static void RecordFree(void* address);
Alexei Filippov9fbb7542018-02-07 09:56:5782
83 static SamplingHeapProfiler* GetInstance();
84
85 private:
Alexei Filippov9fbb7542018-02-07 09:56:5786 SamplingHeapProfiler();
Alexei Filippov83717622018-02-21 21:44:4087 ~SamplingHeapProfiler() = delete;
Alexei Filippov9fbb7542018-02-07 09:56:5788
89 static void InstallAllocatorHooksOnce();
90 static bool InstallAllocatorHooks();
91 static size_t GetNextSampleInterval(size_t base_interval);
92
Alexei Filippov1eb85b5b2018-02-22 03:58:4793 void DoRecordAlloc(size_t total_allocated,
94 size_t allocation_size,
95 void* address,
96 uint32_t skip_frames);
97 void DoRecordFree(void* address);
Alexei Filippov13bf5022018-02-08 05:25:5998 void RecordStackTrace(Sample*, uint32_t skip_frames);
Alexei Filippov0bed5b242018-07-04 02:08:3899 static LockFreeAddressHashSet& sampled_addresses_set();
100
101 void BalanceAddressesHashSet();
Alexei Filippov9fbb7542018-02-07 09:56:57102
103 base::ThreadLocalBoolean entered_;
104 base::Lock mutex_;
Alexei Filippov0bed5b242018-07-04 02:08:38105 std::stack<std::unique_ptr<LockFreeAddressHashSet>> sampled_addresses_stack_;
106 std::unordered_map<void*, Sample> samples_;
Alexei Filippov05852612018-02-10 08:22:29107 std::vector<SamplesObserver*> observers_;
Dirk Pranke0a3c0492018-07-11 22:26:10108 uint32_t last_sample_ordinal_ = 1;
Alexei Filippov9fbb7542018-02-07 09:56:57109
Alexei Filippovb956afc2018-03-12 22:41:08110 static SamplingHeapProfiler* instance_;
111
Alexei Filippov83717622018-02-21 21:44:40112 friend class base::NoDestructor<SamplingHeapProfiler>;
Alexei Filippov9fbb7542018-02-07 09:56:57113
114 DISALLOW_COPY_AND_ASSIGN(SamplingHeapProfiler);
115};
116
Alexei Filippov83717622018-02-21 21:44:40117} // namespace base
Alexei Filippov9fbb7542018-02-07 09:56:57118
Alexei Filippov0a57e5d2018-05-23 18:13:55119#endif // BASE_SAMPLING_HEAP_PROFILER_SAMPLING_HEAP_PROFILER_H_