Line data Source code
1 : // Copyright 2015 the V8 project 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 V8_PROFILER_SAMPLING_HEAP_PROFILER_H_
6 : #define V8_PROFILER_SAMPLING_HEAP_PROFILER_H_
7 :
8 : #include <deque>
9 : #include <map>
10 : #include <memory>
11 : #include <set>
12 : #include "include/v8-profiler.h"
13 : #include "src/heap/heap.h"
14 : #include "src/profiler/strings-storage.h"
15 :
16 : namespace v8 {
17 :
18 : namespace base {
19 : class RandomNumberGenerator;
20 : }
21 :
22 : namespace internal {
23 :
24 : class SamplingAllocationObserver;
25 :
26 60 : class AllocationProfile : public v8::AllocationProfile {
27 : public:
28 30 : AllocationProfile() : nodes_() {}
29 :
30 36 : v8::AllocationProfile::Node* GetRootNode() override {
31 36 : return nodes_.size() == 0 ? nullptr : &nodes_.front();
32 : }
33 :
34 : std::deque<v8::AllocationProfile::Node>& nodes() { return nodes_; }
35 :
36 : private:
37 : std::deque<v8::AllocationProfile::Node> nodes_;
38 :
39 : DISALLOW_COPY_AND_ASSIGN(AllocationProfile);
40 : };
41 :
42 : class SamplingHeapProfiler {
43 : public:
44 : SamplingHeapProfiler(Heap* heap, StringsStorage* names, uint64_t rate,
45 : int stack_depth, v8::HeapProfiler::SamplingFlags flags);
46 : ~SamplingHeapProfiler();
47 :
48 : v8::AllocationProfile* GetAllocationProfile();
49 :
50 : StringsStorage* names() const { return names_; }
51 :
52 : class AllocationNode;
53 :
54 : struct Sample {
55 : public:
56 : Sample(size_t size_, AllocationNode* owner_, Local<Value> local_,
57 : SamplingHeapProfiler* profiler_)
58 : : size(size_),
59 : owner(owner_),
60 : global(Global<Value>(
61 : reinterpret_cast<v8::Isolate*>(profiler_->isolate_), local_)),
62 81326 : profiler(profiler_) {}
63 81326 : ~Sample() { global.Reset(); }
64 : const size_t size;
65 : AllocationNode* const owner;
66 : Global<Value> global;
67 : SamplingHeapProfiler* const profiler;
68 :
69 : private:
70 : DISALLOW_COPY_AND_ASSIGN(Sample);
71 : };
72 :
73 : class AllocationNode {
74 : public:
75 : AllocationNode(AllocationNode* parent, const char* name, int script_id,
76 : int start_position)
77 : : parent_(parent),
78 : script_id_(script_id),
79 : script_position_(start_position),
80 : name_(name),
81 302 : pinned_(false) {}
82 302 : ~AllocationNode() {
83 864 : for (auto child : children_) {
84 260 : delete child.second;
85 : }
86 302 : }
87 :
88 : private:
89 : typedef uint64_t FunctionId;
90 : static FunctionId function_id(int script_id, int start_position,
91 : const char* name) {
92 : // script_id == kNoScriptId case:
93 : // Use function name pointer as an id. Names derived from VM state
94 : // must not collide with the builtin names. The least significant bit
95 : // of the id is set to 1.
96 78332 : if (script_id == v8::UnboundScript::kNoScriptId) {
97 10259 : return reinterpret_cast<intptr_t>(name) | 1;
98 : }
99 : // script_id != kNoScriptId case:
100 : // Use script_id, start_position pair to uniquelly identify the node.
101 : // The least significant bit of the id is set to 0.
102 : DCHECK(static_cast<unsigned>(start_position) < (1u << 31));
103 68073 : return (static_cast<uint64_t>(script_id) << 32) + (start_position << 1);
104 : }
105 : AllocationNode* FindOrAddChildNode(const char* name, int script_id,
106 : int start_position);
107 : // TODO(alph): make use of unordered_map's here. Pay attention to
108 : // iterator invalidation during TranslateAllocationNode.
109 : std::map<size_t, unsigned int> allocations_;
110 : std::map<FunctionId, AllocationNode*> children_;
111 : AllocationNode* const parent_;
112 : const int script_id_;
113 : const int script_position_;
114 : const char* const name_;
115 : bool pinned_;
116 :
117 : friend class SamplingHeapProfiler;
118 :
119 : DISALLOW_COPY_AND_ASSIGN(AllocationNode);
120 : };
121 :
122 : private:
123 : Heap* heap() const { return heap_; }
124 :
125 : void SampleObject(Address soon_object, size_t size);
126 :
127 : static void OnWeakCallback(const WeakCallbackInfo<Sample>& data);
128 :
129 : // Methods that construct v8::AllocationProfile.
130 :
131 : // Translates the provided AllocationNode *node* returning an equivalent
132 : // AllocationProfile::Node. The newly created AllocationProfile::Node is added
133 : // to the provided AllocationProfile *profile*. Line numbers, column numbers,
134 : // and script names are resolved using *scripts* which maps all currently
135 : // loaded scripts keyed by their script id.
136 : v8::AllocationProfile::Node* TranslateAllocationNode(
137 : AllocationProfile* profile, SamplingHeapProfiler::AllocationNode* node,
138 : const std::map<int, Handle<Script>>& scripts);
139 : v8::AllocationProfile::Allocation ScaleSample(size_t size,
140 : unsigned int count);
141 : AllocationNode* AddStack();
142 :
143 : Isolate* const isolate_;
144 : Heap* const heap_;
145 : std::unique_ptr<SamplingAllocationObserver> new_space_observer_;
146 : std::unique_ptr<SamplingAllocationObserver> other_spaces_observer_;
147 : StringsStorage* const names_;
148 : AllocationNode profile_root_;
149 : std::set<Sample*> samples_;
150 : const int stack_depth_;
151 : const uint64_t rate_;
152 : v8::HeapProfiler::SamplingFlags flags_;
153 :
154 : friend class SamplingAllocationObserver;
155 :
156 : DISALLOW_COPY_AND_ASSIGN(SamplingHeapProfiler);
157 : };
158 :
159 : class SamplingAllocationObserver : public AllocationObserver {
160 : public:
161 : SamplingAllocationObserver(Heap* heap, intptr_t step_size, uint64_t rate,
162 : SamplingHeapProfiler* profiler,
163 : base::RandomNumberGenerator* random)
164 : : AllocationObserver(step_size),
165 : profiler_(profiler),
166 : heap_(heap),
167 : random_(random),
168 72 : rate_(rate) {}
169 144 : virtual ~SamplingAllocationObserver() {}
170 :
171 : protected:
172 40663 : void Step(int bytes_allocated, Address soon_object, size_t size) override {
173 : USE(heap_);
174 : DCHECK(heap_->gc_state() == Heap::NOT_IN_GC);
175 : DCHECK(soon_object);
176 40663 : profiler_->SampleObject(soon_object, size);
177 40663 : }
178 :
179 40663 : intptr_t GetNextStepSize() override { return GetNextSampleInterval(rate_); }
180 :
181 : private:
182 : intptr_t GetNextSampleInterval(uint64_t rate);
183 : SamplingHeapProfiler* const profiler_;
184 : Heap* const heap_;
185 : base::RandomNumberGenerator* const random_;
186 : uint64_t const rate_;
187 : };
188 :
189 : } // namespace internal
190 : } // namespace v8
191 :
192 : #endif // V8_PROFILER_SAMPLING_HEAP_PROFILER_H_
|