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 46 : class AllocationProfile : public v8::AllocationProfile {
27 : public:
28 23 : AllocationProfile() : nodes_() {}
29 :
30 27 : v8::AllocationProfile::Node* GetRootNode() override {
31 27 : 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 98794 : profiler(profiler_) {}
63 98794 : ~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 212 : pinned_(false) {}
82 212 : ~AllocationNode() {
83 604 : for (auto child : children_) {
84 180 : delete child.second;
85 : }
86 212 : }
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 74485 : if (script_id == v8::UnboundScript::kNoScriptId) {
97 8467 : 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 66018 : 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 56 : rate_(rate) {}
169 112 : virtual ~SamplingAllocationObserver() {}
170 :
171 : protected:
172 49397 : 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 49397 : if (soon_object) {
176 : // TODO(ofrobots): it would be better to sample the next object rather
177 : // than skipping this sample epoch if soon_object happens to be null.
178 49397 : profiler_->SampleObject(soon_object, size);
179 : }
180 49397 : }
181 :
182 49397 : intptr_t GetNextStepSize() override { return GetNextSampleInterval(rate_); }
183 :
184 : private:
185 : intptr_t GetNextSampleInterval(uint64_t rate);
186 : SamplingHeapProfiler* const profiler_;
187 : Heap* const heap_;
188 : base::RandomNumberGenerator* const random_;
189 : uint64_t const rate_;
190 : };
191 :
192 : } // namespace internal
193 : } // namespace v8
194 :
195 : #endif // V8_PROFILER_SAMPLING_HEAP_PROFILER_H_
|