Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(100)

Side by Side Diff: src/profiler/sampling-heap-profiler.cc

Issue 1697903002: Sampling heap profiler data structure changes (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/profiler/sampling-heap-profiler.h" 5 #include "src/profiler/sampling-heap-profiler.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <memory> 8 #include <memory>
9 #include "src/api.h" 9 #include "src/api.h"
10 #include "src/base/utils/random-number-generator.h" 10 #include "src/base/utils/random-number-generator.h"
(...skipping 24 matching lines...) Expand all
35 35
36 SamplingHeapProfiler::SamplingHeapProfiler(Heap* heap, StringsStorage* names, 36 SamplingHeapProfiler::SamplingHeapProfiler(Heap* heap, StringsStorage* names,
37 uint64_t rate, int stack_depth) 37 uint64_t rate, int stack_depth)
38 : isolate_(heap->isolate()), 38 : isolate_(heap->isolate()),
39 heap_(heap), 39 heap_(heap),
40 new_space_observer_(new SamplingAllocationObserver( 40 new_space_observer_(new SamplingAllocationObserver(
41 heap_, rate, rate, this, heap->isolate()->random_number_generator())), 41 heap_, rate, rate, this, heap->isolate()->random_number_generator())),
42 other_spaces_observer_(new SamplingAllocationObserver( 42 other_spaces_observer_(new SamplingAllocationObserver(
43 heap_, rate, rate, this, heap->isolate()->random_number_generator())), 43 heap_, rate, rate, this, heap->isolate()->random_number_generator())),
44 names_(names), 44 names_(names),
45 samples_(),
46 stack_depth_(stack_depth) { 45 stack_depth_(stack_depth) {
46 FunctionInfo function_info("(root)");
47 profile_root_ = new SamplingHeapProfiler::AllocationNode(&function_info);
ofrobots 2016/02/14 23:57:42 drop the SamplingHeapProfiler:: namespace prefix h
mattloring 2016/02/16 05:28:40 Done.
47 heap->new_space()->AddAllocationObserver(new_space_observer_.get()); 48 heap->new_space()->AddAllocationObserver(new_space_observer_.get());
48 AllSpaces spaces(heap); 49 AllSpaces spaces(heap);
49 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { 50 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) {
50 if (space != heap->new_space()) { 51 if (space != heap->new_space()) {
51 space->AddAllocationObserver(other_spaces_observer_.get()); 52 space->AddAllocationObserver(other_spaces_observer_.get());
52 } 53 }
53 } 54 }
54 } 55 }
55 56
56 57
57 SamplingHeapProfiler::~SamplingHeapProfiler() { 58 SamplingHeapProfiler::~SamplingHeapProfiler() {
58 heap_->new_space()->RemoveAllocationObserver(new_space_observer_.get()); 59 heap_->new_space()->RemoveAllocationObserver(new_space_observer_.get());
59 AllSpaces spaces(heap_); 60 AllSpaces spaces(heap_);
60 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { 61 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) {
61 if (space != heap_->new_space()) { 62 if (space != heap_->new_space()) {
62 space->RemoveAllocationObserver(other_spaces_observer_.get()); 63 space->RemoveAllocationObserver(other_spaces_observer_.get());
63 } 64 }
64 } 65 }
65 66
66 // Clear samples and drop all the weak references we are keeping. 67 delete profile_root_;
67 std::set<SampledAllocation*>::iterator it;
68 for (it = samples_.begin(); it != samples_.end(); ++it) {
69 delete *it;
70 }
ofrobots 2016/02/14 23:57:42 Are we still clearing the weak references we have
mattloring 2016/02/16 05:28:40 Globals should be cleaned up now.
71 std::set<SampledAllocation*> empty;
72 samples_.swap(empty);
73 } 68 }
74 69
75 70
76 void SamplingHeapProfiler::SampleObject(Address soon_object, size_t size) { 71 void SamplingHeapProfiler::SampleObject(Address soon_object, size_t size) {
77 DisallowHeapAllocation no_allocation; 72 DisallowHeapAllocation no_allocation;
78 73
79 HandleScope scope(isolate_); 74 HandleScope scope(isolate_);
80 HeapObject* heap_object = HeapObject::FromAddress(soon_object); 75 HeapObject* heap_object = HeapObject::FromAddress(soon_object);
81 Handle<Object> obj(heap_object, isolate_); 76 Handle<Object> obj(heap_object, isolate_);
82 77
83 // Mark the new block as FreeSpace to make sure the heap is iterable while we 78 // Mark the new block as FreeSpace to make sure the heap is iterable while we
84 // are taking the sample. 79 // are taking the sample.
85 heap()->CreateFillerObjectAt(soon_object, static_cast<int>(size)); 80 heap()->CreateFillerObjectAt(soon_object, static_cast<int>(size));
86 81
87 Local<v8::Value> loc = v8::Utils::ToLocal(obj); 82 Local<v8::Value> loc = v8::Utils::ToLocal(obj);
83 Global<Value>* global =
84 new Global<Value>(reinterpret_cast<v8::Isolate*>(isolate_), loc);
88 85
89 SampledAllocation* sample = 86 std::vector<FunctionInfo*> stack = CollectStack(stack_depth_);
90 new SampledAllocation(this, isolate_, loc, size, stack_depth_); 87 SamplingHeapProfiler::AllocationNode* node = AddStack(stack);
91 samples_.insert(sample); 88 node->allocations_[size]++;
89 Sample* sample = new Sample({size, node, global});
ofrobots 2016/02/14 23:57:42 Prefereable to avoid list initialization. Prefer e
mattloring 2016/02/16 05:28:40 Doing it as {...} yields: error: excess elements i
ofrobots 2016/02/17 17:48:21 You will need to use a constructor that accepts th
mattloring 2016/02/17 17:59:47 Done.
90
91 global->SetWeak(sample, OnWeakCallback, WeakCallbackType::kParameter);
92 } 92 }
93 93
94 94 std::vector<SamplingHeapProfiler::FunctionInfo*>
95 void SamplingHeapProfiler::SampledAllocation::OnWeakCallback( 95 SamplingHeapProfiler::CollectStack(int max_frames) {
96 const WeakCallbackInfo<SampledAllocation>& data) { 96 std::vector<SamplingHeapProfiler::FunctionInfo*> stack_;
97 SampledAllocation* sample = data.GetParameter(); 97 StackTraceFrameIterator it(isolate_);
98 sample->sampling_heap_profiler_->samples_.erase(sample);
99 delete sample;
100 }
101
102
103 SamplingHeapProfiler::FunctionInfo::FunctionInfo(SharedFunctionInfo* shared,
104 StringsStorage* names)
105 : name_(names->GetFunctionName(shared->DebugName())),
106 script_name_(""),
107 script_id_(v8::UnboundScript::kNoScriptId),
108 start_position_(shared->start_position()) {
109 if (shared->script()->IsScript()) {
110 Script* script = Script::cast(shared->script());
111 script_id_ = script->id();
112 if (script->name()->IsName()) {
113 Name* name = Name::cast(script->name());
114 script_name_ = names->GetName(name);
115 }
116 }
117 }
118
119
120 SamplingHeapProfiler::SampledAllocation::SampledAllocation(
121 SamplingHeapProfiler* sampling_heap_profiler, Isolate* isolate,
122 Local<Value> local, size_t size, int max_frames)
123 : sampling_heap_profiler_(sampling_heap_profiler),
124 global_(reinterpret_cast<v8::Isolate*>(isolate), local),
125 size_(size) {
126 global_.SetWeak(this, OnWeakCallback, WeakCallbackType::kParameter);
127
128 StackTraceFrameIterator it(isolate);
129 int frames_captured = 0; 98 int frames_captured = 0;
130 while (!it.done() && frames_captured < max_frames) { 99 while (!it.done() && frames_captured < max_frames) {
131 JavaScriptFrame* frame = it.frame(); 100 JavaScriptFrame* frame = it.frame();
132 SharedFunctionInfo* shared = frame->function()->shared(); 101 SharedFunctionInfo* shared = frame->function()->shared();
133 stack_.push_back(new FunctionInfo(shared, sampling_heap_profiler->names())); 102 stack_.push_back(new FunctionInfo(shared, this->names()));
134 103
135 frames_captured++; 104 frames_captured++;
136 it.Advance(); 105 it.Advance();
137 } 106 }
138 107
139 if (frames_captured == 0) { 108 if (frames_captured == 0) {
140 const char* name = nullptr; 109 const char* name = nullptr;
141 switch (isolate->current_vm_state()) { 110 switch (isolate_->current_vm_state()) {
142 case GC: 111 case GC:
143 name = "(GC)"; 112 name = "(GC)";
144 break; 113 break;
145 case COMPILER: 114 case COMPILER:
146 name = "(COMPILER)"; 115 name = "(COMPILER)";
147 break; 116 break;
148 case OTHER: 117 case OTHER:
149 name = "(V8 API)"; 118 name = "(V8 API)";
150 break; 119 break;
151 case EXTERNAL: 120 case EXTERNAL:
152 name = "(EXTERNAL)"; 121 name = "(EXTERNAL)";
153 break; 122 break;
154 case IDLE: 123 case IDLE:
155 name = "(IDLE)"; 124 name = "(IDLE)";
156 break; 125 break;
157 case JS: 126 case JS:
158 name = "(JS)"; 127 name = "(JS)";
159 break; 128 break;
160 } 129 }
161 stack_.push_back(new FunctionInfo(name)); 130 stack_.push_back(new FunctionInfo(name));
162 } 131 }
132 return stack_;
163 } 133 }
164 134
165 v8::AllocationProfile::Node* SamplingHeapProfiler::AllocateNode( 135 void SamplingHeapProfiler::OnWeakCallback(
166 AllocationProfile* profile, const std::map<int, Script*>& scripts, 136 const WeakCallbackInfo<SamplingHeapProfiler::Sample>& data) {
ofrobots 2016/02/14 23:57:42 You might be able to drop the SHP:: prefix in the
mattloring 2016/02/16 05:28:39 Done.
167 FunctionInfo* function_info) { 137 SamplingHeapProfiler::Sample* sample = data.GetParameter();
168 DCHECK(function_info->get_name()); 138 SamplingHeapProfiler::AllocationNode* node = sample->owner;
ofrobots 2016/02/14 23:57:42 Drop the SHP:: prefix.
mattloring 2016/02/16 05:28:40 Done.
169 DCHECK(function_info->get_script_name()); 139 node->allocations_[sample->size]--;
170 140 delete sample->global;
171 int line = v8::AllocationProfile::kNoLineNumberInfo; 141 delete sample;
172 int column = v8::AllocationProfile::kNoColumnNumberInfo;
173
174 if (function_info->get_script_id() != v8::UnboundScript::kNoScriptId) {
175 // Cannot use std::map<T>::at because it is not available on android.
176 auto non_const_scripts = const_cast<std::map<int, Script*>&>(scripts);
177 Handle<Script> script(non_const_scripts[function_info->get_script_id()]);
178
179 line =
180 1 + Script::GetLineNumber(script, function_info->get_start_position());
181 column = 1 + Script::GetColumnNumber(script,
182 function_info->get_start_position());
183 }
184
185 profile->nodes().push_back(v8::AllocationProfile::Node(
186 {ToApiHandle<v8::String>(isolate_->factory()->InternalizeUtf8String(
187 function_info->get_name())),
188 ToApiHandle<v8::String>(isolate_->factory()->InternalizeUtf8String(
189 function_info->get_script_name())),
190 function_info->get_script_id(), function_info->get_start_position(),
191 line, column, std::vector<v8::AllocationProfile::Node*>(),
192 std::vector<v8::AllocationProfile::Allocation>()}));
193
194 return &profile->nodes().back();
195 } 142 }
196 143
197 v8::AllocationProfile::Node* SamplingHeapProfiler::FindOrAddChildNode( 144 SamplingHeapProfiler::FunctionInfo::FunctionInfo(SharedFunctionInfo* shared,
198 AllocationProfile* profile, const std::map<int, Script*>& scripts, 145 StringsStorage* names)
199 v8::AllocationProfile::Node* parent, FunctionInfo* function_info) { 146 : name_(names->GetFunctionName(shared->DebugName())),
200 for (v8::AllocationProfile::Node* child : parent->children) { 147 script_name_(""),
ofrobots 2016/02/14 23:57:42 Do we ever use this field any more? Drop it if you
mattloring 2016/02/16 15:10:54 Done.
201 if (child->script_id == function_info->get_script_id() && 148 script_id_(v8::UnboundScript::kNoScriptId),
202 child->start_position == function_info->get_start_position()) 149 start_position_(shared->start_position()) {
150 if (shared->script()->IsScript()) {
151 Script* script = Script::cast(shared->script());
152 script_id_ = script->id();
153 if (script->name()->IsName()) {
154 Name* name = Name::cast(script->name());
155 script_name_ = names->GetName(name);
156 }
157 }
158 }
159
160 SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::FindOrAddChildNode(
161 SamplingHeapProfiler::AllocationNode* parent, FunctionInfo* function_info) {
162 for (SamplingHeapProfiler::AllocationNode* child : parent->children_) {
ofrobots 2016/02/14 23:57:42 drop the prefix.
mattloring 2016/02/16 05:28:39 Done.
163 if (child->script_id_ == function_info->get_script_id() &&
164 child->script_position_ == function_info->get_start_position())
203 return child; 165 return child;
204 } 166 }
205 v8::AllocationProfile::Node* child = 167 SamplingHeapProfiler::AllocationNode* child =
ofrobots 2016/02/14 23:57:42 Drop the SamplingHeapProfiler prefix.
mattloring 2016/02/16 05:28:40 Done.
206 AllocateNode(profile, scripts, function_info); 168 new AllocationNode(function_info);
207 parent->children.push_back(child); 169 parent->children_.push_back(child);
208 return child; 170 return child;
209 } 171 }
210 172
211 v8::AllocationProfile::Node* SamplingHeapProfiler::AddStack( 173 SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::AddStack(
212 AllocationProfile* profile, const std::map<int, Script*>& scripts,
213 const std::vector<FunctionInfo*>& stack) { 174 const std::vector<FunctionInfo*>& stack) {
214 v8::AllocationProfile::Node* node = profile->GetRootNode(); 175 SamplingHeapProfiler::AllocationNode* node = profile_root_;
ofrobots 2016/02/14 23:57:42 drop the prefix.
mattloring 2016/02/16 05:28:39 Done.
215 176
216 // We need to process the stack in reverse order as the top of the stack is 177 // We need to process the stack in reverse order as the top of the stack is
217 // the first element in the list. 178 // the first element in the list.
218 for (auto it = stack.rbegin(); it != stack.rend(); ++it) { 179 for (auto it = stack.rbegin(); it != stack.rend(); ++it) {
219 FunctionInfo* function_info = *it; 180 FunctionInfo* function_info = *it;
220 node = FindOrAddChildNode(profile, scripts, node, function_info); 181 node = FindOrAddChildNode(node, function_info);
221 } 182 }
222 return node; 183 return node;
223 } 184 }
224 185
186 v8::AllocationProfile::Node* SamplingHeapProfiler::GenerateProfile(
187 AllocationProfile* profile, SamplingHeapProfiler::AllocationNode* node,
188 const std::map<int, Script*>& scripts) {
189 Local<v8::String> script_name =
190 ToApiHandle<v8::String>(isolate_->factory()->InternalizeUtf8String(""));
191 int line = v8::AllocationProfile::kNoLineNumberInfo;
192 int column = v8::AllocationProfile::kNoColumnNumberInfo;
193 std::vector<v8::AllocationProfile::Allocation> allocations;
ofrobots 2016/02/14 23:57:42 In a follow-on CL, it would be good to make the V8
mattloring 2016/02/16 05:28:40 Yup, this change was in the original version of th
194 if (node->script_id_ != v8::UnboundScript::kNoScriptId) {
195 auto non_const_scripts = const_cast<std::map<int, Script*>&>(scripts);
ofrobots 2016/02/14 23:57:42 You dropped the necessary comment explaining why t
196 Script* script = non_const_scripts[node->script_id_];
197 if (script->name()->IsName()) {
198 Name* name = Name::cast(script->name());
199 script_name = ToApiHandle<v8::String>(
200 isolate_->factory()->InternalizeUtf8String(names_->GetName(name)));
201 }
202 Handle<Script> script_handle(script);
203
204 line = 1 + Script::GetLineNumber(script_handle, node->script_position_);
205 column = 1 + Script::GetColumnNumber(script_handle, node->script_position_);
206 for (auto alloc : node->allocations_) {
207 allocations.push_back({alloc.first, alloc.second});
208 }
209 }
210
211 profile->nodes().push_back(v8::AllocationProfile::Node(
212 {ToApiHandle<v8::String>(
213 isolate_->factory()->InternalizeUtf8String(node->name_)),
214 script_name, node->script_id_, node->script_position_, line, column,
215 std::vector<v8::AllocationProfile::Node*>(), allocations}));
216 v8::AllocationProfile::Node* current = &profile->nodes().back();
217 for (auto child : node->children_) {
218 current->children.push_back(GenerateProfile(profile, child, scripts));
219 }
220 return current;
221 }
225 222
226 v8::AllocationProfile* SamplingHeapProfiler::GetAllocationProfile() { 223 v8::AllocationProfile* SamplingHeapProfiler::GetAllocationProfile() {
227 // To resolve positions to line/column numbers, we will need to look up 224 // To resolve positions to line/column numbers, we will need to look up
228 // scripts. Build a map to allow fast mapping from script id to script. 225 // scripts. Build a map to allow fast mapping from script id to script.
229 std::map<int, Script*> scripts; 226 std::map<int, Script*> scripts;
230 { 227 {
231 Script::Iterator iterator(isolate_); 228 Script::Iterator iterator(isolate_);
232 Script* script; 229 Script* script;
233 while ((script = iterator.Next())) { 230 while ((script = iterator.Next())) {
234 scripts[script->id()] = script; 231 scripts[script->id()] = script;
235 } 232 }
236 } 233 }
237 234
238 auto profile = new v8::internal::AllocationProfile(); 235 auto profile = new v8::internal::AllocationProfile();
239 236
240 // Create the root node. 237 GenerateProfile(profile, profile_root_, scripts);
241 FunctionInfo function_info("(root)");
242 AllocateNode(profile, scripts, &function_info);
243
244 for (SampledAllocation* allocation : samples_) {
245 v8::AllocationProfile::Node* node =
246 AddStack(profile, scripts, allocation->get_stack());
247 node->allocations.push_back({allocation->get_size(), 1});
248 }
249 238
250 return profile; 239 return profile;
251 } 240 }
252 241
253 242
254 } // namespace internal 243 } // namespace internal
255 } // namespace v8 244 } // namespace v8
OLDNEW
« src/profiler/sampling-heap-profiler.h ('K') | « src/profiler/sampling-heap-profiler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698