blob: c5792208e1e6d7c1cce92b2eda17dd92bc431226 [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 Filippov83717622018-02-21 21:44:4023// The class implements sampling profiling of native memory heap.
24// It hooks on base::allocator and base::PartitionAlloc.
25// When started it selects and records allocation samples based on
26// the sampling_interval parameter.
27// The recorded samples can then be retrieved using GetSamples method.
28class BASE_EXPORT SamplingHeapProfiler {
Alexei Filippov9fbb7542018-02-07 09:56:5729 public:
Alexei Filippov83717622018-02-21 21:44:4030 class BASE_EXPORT Sample {
Alexei Filippov9fbb7542018-02-07 09:56:5731 public:
Alexei Filippov83717622018-02-21 21:44:4032 Sample(const Sample&);
33 ~Sample();
34
Alexei Filippove6633efc2018-03-01 19:31:5835 size_t size; // Allocation size.
36 size_t total; // Total size attributed to the sample.
Alexei Filippov9fbb7542018-02-07 09:56:5737 std::vector<void*> stack;
38
39 private:
40 friend class SamplingHeapProfiler;
41
Alexei Filippove6633efc2018-03-01 19:31:5842 Sample(size_t, size_t total, uint32_t ordinal);
Alexei Filippov9fbb7542018-02-07 09:56:5743
44 uint32_t ordinal;
45 };
46
Alexei Filippov05852612018-02-10 08:22:2947 class SamplesObserver {
48 public:
49 virtual ~SamplesObserver() = default;
Alexei Filippove6633efc2018-03-01 19:31:5850 virtual void SampleAdded(uint32_t id, size_t size, size_t total) = 0;
Alexei Filippov05852612018-02-10 08:22:2951 virtual void SampleRemoved(uint32_t id) = 0;
52 };
53
Alexei Filippovb956afc2018-03-12 22:41:0854 // Must be called early during the process initialization. It creates and
55 // reserves a TLS slot.
56 static void InitTLSSlot();
57
Alexei Filippov1eb85b5b2018-02-22 03:58:4758 // This is an entry point for plugging in an external allocator.
59 // Profiler will invoke the provided callback upon initialization.
60 // The callback should install hooks onto the corresponding memory allocator
61 // and make them invoke SamplingHeapProfiler::RecordAlloc and
62 // SamplingHeapProfiler::RecordFree upon corresponding allocation events.
63 //
64 // If the method is called after profiler is initialized, the callback
65 // is invoked right away.
66 static void SetHooksInstallCallback(void (*hooks_install_callback)());
67
Alexei Filippov05852612018-02-10 08:22:2968 void AddSamplesObserver(SamplesObserver*);
69 void RemoveSamplesObserver(SamplesObserver*);
70
Alexei Filippov9fbb7542018-02-07 09:56:5771 uint32_t Start();
72 void Stop();
73 void SetSamplingInterval(size_t sampling_interval);
Alexei Filippovc3857682018-03-01 05:23:0474 void SuppressRandomnessForTest(bool suppress);
Alexei Filippov9fbb7542018-02-07 09:56:5775
76 std::vector<Sample> GetSamples(uint32_t profile_id);
77
Alexei Filippov1eb85b5b2018-02-22 03:58:4778 static void RecordAlloc(void* address, size_t, uint32_t skip_frames = 0);
79 static void RecordFree(void* address);
Alexei Filippov9fbb7542018-02-07 09:56:5780
81 static SamplingHeapProfiler* GetInstance();
82
83 private:
Alexei Filippov0a57e5d2018-05-23 18:13:5584 using SamplesMap = std::unordered_map<void*, Sample>;
85
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 Filippov0a57e5d2018-05-23 18:13:5599 SamplesMap& EnsureNoRehashingMap();
100 static SamplesMap& samples();
Alexei Filippov9fbb7542018-02-07 09:56:57101
102 base::ThreadLocalBoolean entered_;
103 base::Lock mutex_;
Alexei Filippov0a57e5d2018-05-23 18:13:55104 std::stack<std::unique_ptr<SamplesMap>> sample_maps_;
Alexei Filippov05852612018-02-10 08:22:29105 std::vector<SamplesObserver*> observers_;
Alexei Filippov0a57e5d2018-05-23 18:13:55106 uint32_t last_sample_ordinal_ = 0;
Alexei Filippov9fbb7542018-02-07 09:56:57107
Alexei Filippovb956afc2018-03-12 22:41:08108 static SamplingHeapProfiler* instance_;
109
Alexei Filippov83717622018-02-21 21:44:40110 friend class base::NoDestructor<SamplingHeapProfiler>;
Alexei Filippov9fbb7542018-02-07 09:56:57111
112 DISALLOW_COPY_AND_ASSIGN(SamplingHeapProfiler);
113};
114
Alexei Filippov83717622018-02-21 21:44:40115} // namespace base
Alexei Filippov9fbb7542018-02-07 09:56:57116
Alexei Filippov0a57e5d2018-05-23 18:13:55117#endif // BASE_SAMPLING_HEAP_PROFILER_SAMPLING_HEAP_PROFILER_H_