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

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

Issue 1708363002: Revert of 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
« no previous file with comments | « src/profiler/sampling-heap-profiler.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 profile_root_("(root)", v8::UnboundScript::kNoScriptId, 0),
46 samples_(), 45 samples_(),
47 stack_depth_(stack_depth) { 46 stack_depth_(stack_depth) {
48 heap->new_space()->AddAllocationObserver(new_space_observer_.get()); 47 heap->new_space()->AddAllocationObserver(new_space_observer_.get());
49 AllSpaces spaces(heap); 48 AllSpaces spaces(heap);
50 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { 49 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) {
51 if (space != heap->new_space()) { 50 if (space != heap->new_space()) {
52 space->AddAllocationObserver(other_spaces_observer_.get()); 51 space->AddAllocationObserver(other_spaces_observer_.get());
53 } 52 }
54 } 53 }
55 } 54 }
56 55
57 56
58 SamplingHeapProfiler::~SamplingHeapProfiler() { 57 SamplingHeapProfiler::~SamplingHeapProfiler() {
59 heap_->new_space()->RemoveAllocationObserver(new_space_observer_.get()); 58 heap_->new_space()->RemoveAllocationObserver(new_space_observer_.get());
60 AllSpaces spaces(heap_); 59 AllSpaces spaces(heap_);
61 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) { 60 for (Space* space = spaces.next(); space != NULL; space = spaces.next()) {
62 if (space != heap_->new_space()) { 61 if (space != heap_->new_space()) {
63 space->RemoveAllocationObserver(other_spaces_observer_.get()); 62 space->RemoveAllocationObserver(other_spaces_observer_.get());
64 } 63 }
65 } 64 }
66 65
67 for (auto sample : samples_) { 66 // Clear samples and drop all the weak references we are keeping.
68 delete sample; 67 std::set<SampledAllocation*>::iterator it;
68 for (it = samples_.begin(); it != samples_.end(); ++it) {
69 delete *it;
69 } 70 }
70 std::set<Sample*> empty; 71 std::set<SampledAllocation*> empty;
71 samples_.swap(empty); 72 samples_.swap(empty);
72 } 73 }
73 74
74 75
75 void SamplingHeapProfiler::SampleObject(Address soon_object, size_t size) { 76 void SamplingHeapProfiler::SampleObject(Address soon_object, size_t size) {
76 DisallowHeapAllocation no_allocation; 77 DisallowHeapAllocation no_allocation;
77 78
78 HandleScope scope(isolate_); 79 HandleScope scope(isolate_);
79 HeapObject* heap_object = HeapObject::FromAddress(soon_object); 80 HeapObject* heap_object = HeapObject::FromAddress(soon_object);
80 Handle<Object> obj(heap_object, isolate_); 81 Handle<Object> obj(heap_object, isolate_);
81 82
82 // Mark the new block as FreeSpace to make sure the heap is iterable while we 83 // Mark the new block as FreeSpace to make sure the heap is iterable while we
83 // are taking the sample. 84 // are taking the sample.
84 heap()->CreateFillerObjectAt(soon_object, static_cast<int>(size)); 85 heap()->CreateFillerObjectAt(soon_object, static_cast<int>(size));
85 86
86 Local<v8::Value> loc = v8::Utils::ToLocal(obj); 87 Local<v8::Value> loc = v8::Utils::ToLocal(obj);
87 88
88 AllocationNode* node = AddStack(); 89 SampledAllocation* sample =
89 node->allocations_[size]++; 90 new SampledAllocation(this, isolate_, loc, size, stack_depth_);
90 Sample* sample = new Sample(size, node, loc, this);
91 samples_.insert(sample); 91 samples_.insert(sample);
92 sample->global.SetWeak(sample, OnWeakCallback, WeakCallbackType::kParameter);
93 } 92 }
94 93
95 void SamplingHeapProfiler::OnWeakCallback( 94
96 const WeakCallbackInfo<Sample>& data) { 95 void SamplingHeapProfiler::SampledAllocation::OnWeakCallback(
97 Sample* sample = data.GetParameter(); 96 const WeakCallbackInfo<SampledAllocation>& data) {
98 AllocationNode* node = sample->owner; 97 SampledAllocation* sample = data.GetParameter();
99 DCHECK(node->allocations_[sample->size] > 0); 98 sample->sampling_heap_profiler_->samples_.erase(sample);
100 node->allocations_[sample->size]--;
101 sample->profiler->samples_.erase(sample);
102 delete sample; 99 delete sample;
103 } 100 }
104 101
105 SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::FindOrAddChildNode( 102
106 AllocationNode* parent, const char* name, int script_id, 103 SamplingHeapProfiler::FunctionInfo::FunctionInfo(SharedFunctionInfo* shared,
107 int start_position) { 104 StringsStorage* names)
108 for (AllocationNode* child : parent->children_) { 105 : name_(names->GetFunctionName(shared->DebugName())),
109 if (child->script_id_ == script_id && 106 script_name_(""),
110 child->script_position_ == start_position && 107 script_id_(v8::UnboundScript::kNoScriptId),
111 strcmp(child->name_, name) == 0) { 108 start_position_(shared->start_position()) {
112 return child; 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);
113 } 115 }
114 } 116 }
115 AllocationNode* child = new AllocationNode(name, script_id, start_position);
116 parent->children_.push_back(child);
117 return child;
118 } 117 }
119 118
120 SamplingHeapProfiler::AllocationNode* SamplingHeapProfiler::AddStack() {
121 AllocationNode* node = &profile_root_;
122 119
123 std::vector<SharedFunctionInfo*> stack; 120 SamplingHeapProfiler::SampledAllocation::SampledAllocation(
124 StackTraceFrameIterator it(isolate_); 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);
125 int frames_captured = 0; 129 int frames_captured = 0;
126 while (!it.done() && frames_captured < stack_depth_) { 130 while (!it.done() && frames_captured < max_frames) {
127 JavaScriptFrame* frame = it.frame(); 131 JavaScriptFrame* frame = it.frame();
128 SharedFunctionInfo* shared = frame->function()->shared(); 132 SharedFunctionInfo* shared = frame->function()->shared();
129 stack.push_back(shared); 133 stack_.push_back(new FunctionInfo(shared, sampling_heap_profiler->names()));
130 134
131 frames_captured++; 135 frames_captured++;
132 it.Advance(); 136 it.Advance();
133 } 137 }
134 138
135 if (frames_captured == 0) { 139 if (frames_captured == 0) {
136 const char* name = nullptr; 140 const char* name = nullptr;
137 switch (isolate_->current_vm_state()) { 141 switch (isolate->current_vm_state()) {
138 case GC: 142 case GC:
139 name = "(GC)"; 143 name = "(GC)";
140 break; 144 break;
141 case COMPILER: 145 case COMPILER:
142 name = "(COMPILER)"; 146 name = "(COMPILER)";
143 break; 147 break;
144 case OTHER: 148 case OTHER:
145 name = "(V8 API)"; 149 name = "(V8 API)";
146 break; 150 break;
147 case EXTERNAL: 151 case EXTERNAL:
148 name = "(EXTERNAL)"; 152 name = "(EXTERNAL)";
149 break; 153 break;
150 case IDLE: 154 case IDLE:
151 name = "(IDLE)"; 155 name = "(IDLE)";
152 break; 156 break;
153 case JS: 157 case JS:
154 name = "(JS)"; 158 name = "(JS)";
155 break; 159 break;
156 } 160 }
157 return FindOrAddChildNode(node, name, v8::UnboundScript::kNoScriptId, 0); 161 stack_.push_back(new FunctionInfo(name));
158 } 162 }
163 }
164
165 v8::AllocationProfile::Node* SamplingHeapProfiler::AllocateNode(
166 AllocationProfile* profile, const std::map<int, Script*>& scripts,
167 FunctionInfo* function_info) {
168 DCHECK(function_info->get_name());
169 DCHECK(function_info->get_script_name());
170
171 int line = v8::AllocationProfile::kNoLineNumberInfo;
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 }
196
197 v8::AllocationProfile::Node* SamplingHeapProfiler::FindOrAddChildNode(
198 AllocationProfile* profile, const std::map<int, Script*>& scripts,
199 v8::AllocationProfile::Node* parent, FunctionInfo* function_info) {
200 for (v8::AllocationProfile::Node* child : parent->children) {
201 if (child->script_id == function_info->get_script_id() &&
202 child->start_position == function_info->get_start_position())
203 return child;
204 }
205 v8::AllocationProfile::Node* child =
206 AllocateNode(profile, scripts, function_info);
207 parent->children.push_back(child);
208 return child;
209 }
210
211 v8::AllocationProfile::Node* SamplingHeapProfiler::AddStack(
212 AllocationProfile* profile, const std::map<int, Script*>& scripts,
213 const std::vector<FunctionInfo*>& stack) {
214 v8::AllocationProfile::Node* node = profile->GetRootNode();
159 215
160 // We need to process the stack in reverse order as the top of the stack is 216 // We need to process the stack in reverse order as the top of the stack is
161 // the first element in the list. 217 // the first element in the list.
162 for (auto it = stack.rbegin(); it != stack.rend(); ++it) { 218 for (auto it = stack.rbegin(); it != stack.rend(); ++it) {
163 SharedFunctionInfo* shared = *it; 219 FunctionInfo* function_info = *it;
164 const char* name = this->names()->GetFunctionName(shared->DebugName()); 220 node = FindOrAddChildNode(profile, scripts, node, function_info);
165 int script_id = v8::UnboundScript::kNoScriptId;
166 if (shared->script()->IsScript()) {
167 Script* script = Script::cast(shared->script());
168 script_id = script->id();
169 }
170 node = FindOrAddChildNode(node, name, script_id, shared->start_position());
171 } 221 }
172 return node; 222 return node;
173 } 223 }
174 224
175 v8::AllocationProfile::Node* SamplingHeapProfiler::TranslateAllocationNode(
176 AllocationProfile* profile, SamplingHeapProfiler::AllocationNode* node,
177 const std::map<int, Script*>& scripts) {
178 Local<v8::String> script_name =
179 ToApiHandle<v8::String>(isolate_->factory()->InternalizeUtf8String(""));
180 int line = v8::AllocationProfile::kNoLineNumberInfo;
181 int column = v8::AllocationProfile::kNoColumnNumberInfo;
182 std::vector<v8::AllocationProfile::Allocation> allocations;
183 if (node->script_id_ != v8::UnboundScript::kNoScriptId) {
184 // Cannot use std::map<T>::at because it is not available on android.
185 auto non_const_scripts = const_cast<std::map<int, Script*>&>(scripts);
186 Script* script = non_const_scripts[node->script_id_];
187 if (script->name()->IsName()) {
188 Name* name = Name::cast(script->name());
189 script_name = ToApiHandle<v8::String>(
190 isolate_->factory()->InternalizeUtf8String(names_->GetName(name)));
191 }
192 Handle<Script> script_handle(script);
193
194 line = 1 + Script::GetLineNumber(script_handle, node->script_position_);
195 column = 1 + Script::GetColumnNumber(script_handle, node->script_position_);
196 for (auto alloc : node->allocations_) {
197 allocations.push_back({alloc.first, alloc.second});
198 }
199 }
200
201 profile->nodes().push_back(v8::AllocationProfile::Node(
202 {ToApiHandle<v8::String>(
203 isolate_->factory()->InternalizeUtf8String(node->name_)),
204 script_name, node->script_id_, node->script_position_, line, column,
205 std::vector<v8::AllocationProfile::Node*>(), allocations}));
206 v8::AllocationProfile::Node* current = &profile->nodes().back();
207 for (auto child : node->children_) {
208 current->children.push_back(
209 TranslateAllocationNode(profile, child, scripts));
210 }
211 return current;
212 }
213 225
214 v8::AllocationProfile* SamplingHeapProfiler::GetAllocationProfile() { 226 v8::AllocationProfile* SamplingHeapProfiler::GetAllocationProfile() {
215 // To resolve positions to line/column numbers, we will need to look up 227 // To resolve positions to line/column numbers, we will need to look up
216 // scripts. Build a map to allow fast mapping from script id to script. 228 // scripts. Build a map to allow fast mapping from script id to script.
217 std::map<int, Script*> scripts; 229 std::map<int, Script*> scripts;
218 { 230 {
219 Script::Iterator iterator(isolate_); 231 Script::Iterator iterator(isolate_);
220 Script* script; 232 Script* script;
221 while ((script = iterator.Next())) { 233 while ((script = iterator.Next())) {
222 scripts[script->id()] = script; 234 scripts[script->id()] = script;
223 } 235 }
224 } 236 }
225 237
226 auto profile = new v8::internal::AllocationProfile(); 238 auto profile = new v8::internal::AllocationProfile();
227 239
228 TranslateAllocationNode(profile, &profile_root_, scripts); 240 // Create the root node.
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 }
229 249
230 return profile; 250 return profile;
231 } 251 }
232 252
233 253
234 } // namespace internal 254 } // namespace internal
235 } // namespace v8 255 } // namespace v8
OLDNEW
« no previous file with comments | « src/profiler/sampling-heap-profiler.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698