Line data Source code
1 : // Copyright 2013 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 : #include "src/profiler/allocation-tracker.h"
6 :
7 : #include "src/frames-inl.h"
8 : #include "src/objects-inl.h"
9 : #include "src/profiler/heap-snapshot-generator-inl.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 :
14 0 : AllocationTraceNode::AllocationTraceNode(
15 : AllocationTraceTree* tree, unsigned function_info_index)
16 : : tree_(tree),
17 : function_info_index_(function_info_index),
18 : total_size_(0),
19 : allocation_count_(0),
20 660 : id_(tree->next_node_id()) {
21 0 : }
22 :
23 :
24 330 : AllocationTraceNode::~AllocationTraceNode() {
25 960 : for (AllocationTraceNode* node : children_) delete node;
26 330 : }
27 :
28 :
29 0 : AllocationTraceNode* AllocationTraceNode::FindChild(
30 : unsigned function_info_index) {
31 159464 : for (AllocationTraceNode* node : children_) {
32 79582 : if (node->function_info_index() == function_info_index) return node;
33 : }
34 : return nullptr;
35 : }
36 :
37 :
38 46167 : AllocationTraceNode* AllocationTraceNode::FindOrAddChild(
39 : unsigned function_info_index) {
40 46167 : AllocationTraceNode* child = FindChild(function_info_index);
41 46167 : if (child == nullptr) {
42 600 : child = new AllocationTraceNode(tree_, function_info_index);
43 300 : children_.push_back(child);
44 : }
45 46167 : return child;
46 : }
47 :
48 :
49 0 : void AllocationTraceNode::AddAllocation(unsigned size) {
50 13279 : total_size_ += size;
51 13279 : ++allocation_count_;
52 0 : }
53 :
54 :
55 330 : void AllocationTraceNode::Print(int indent, AllocationTracker* tracker) {
56 330 : base::OS::Print("%10u %10u %*c", total_size_, allocation_count_, indent, ' ');
57 330 : if (tracker != nullptr) {
58 : AllocationTracker::FunctionInfo* info =
59 660 : tracker->function_info_list()[function_info_index_];
60 330 : base::OS::Print("%s #%u", info->name, id_);
61 : } else {
62 0 : base::OS::Print("%u #%u", function_info_index_, id_);
63 : }
64 330 : base::OS::Print("\n");
65 330 : indent += 2;
66 960 : for (AllocationTraceNode* node : children_) {
67 300 : node->Print(indent, tracker);
68 : }
69 330 : }
70 :
71 :
72 0 : AllocationTraceTree::AllocationTraceTree()
73 : : next_node_id_(1),
74 30 : root_(this, 0) {
75 0 : }
76 :
77 :
78 30 : AllocationTraceTree::~AllocationTraceTree() {
79 0 : }
80 :
81 :
82 13279 : AllocationTraceNode* AllocationTraceTree::AddPathFromEnd(
83 72725 : const Vector<unsigned>& path) {
84 13279 : AllocationTraceNode* node = root();
85 118892 : for (unsigned* entry = path.start() + path.length() - 1;
86 59446 : entry != path.start() - 1;
87 : --entry) {
88 46167 : node = node->FindOrAddChild(*entry);
89 : }
90 13279 : return node;
91 : }
92 :
93 :
94 30 : void AllocationTraceTree::Print(AllocationTracker* tracker) {
95 30 : base::OS::Print("[AllocationTraceTree:]\n");
96 30 : base::OS::Print("Total size | Allocation count | Function id | id\n");
97 30 : root()->Print(0, tracker);
98 30 : }
99 :
100 0 : AllocationTracker::FunctionInfo::FunctionInfo()
101 : : name(""),
102 : function_id(0),
103 : script_name(""),
104 : script_id(0),
105 : line(-1),
106 320 : column(-1) {
107 0 : }
108 :
109 :
110 13314 : void AddressToTraceMap::AddRange(Address start, int size,
111 : unsigned trace_node_id) {
112 13314 : Address end = start + size;
113 13314 : RemoveRange(start, end);
114 :
115 : RangeStack new_range(start, trace_node_id);
116 13314 : ranges_.insert(RangeMap::value_type(end, new_range));
117 13314 : }
118 :
119 :
120 100 : unsigned AddressToTraceMap::GetTraceNodeId(Address addr) {
121 : RangeMap::const_iterator it = ranges_.upper_bound(addr);
122 100 : if (it == ranges_.end()) return 0;
123 80 : if (it->second.start <= addr) {
124 70 : return it->second.trace_node_id;
125 : }
126 : return 0;
127 : }
128 :
129 :
130 0 : void AddressToTraceMap::MoveObject(Address from, Address to, int size) {
131 : unsigned trace_node_id = GetTraceNodeId(from);
132 0 : if (trace_node_id == 0) return;
133 0 : RemoveRange(from, from + size);
134 0 : AddRange(to, size, trace_node_id);
135 : }
136 :
137 :
138 5 : void AddressToTraceMap::Clear() {
139 : ranges_.clear();
140 5 : }
141 :
142 :
143 0 : void AddressToTraceMap::Print() {
144 0 : PrintF("[AddressToTraceMap (%" PRIuS "): \n", ranges_.size());
145 0 : for (RangeMap::iterator it = ranges_.begin(); it != ranges_.end(); ++it) {
146 : PrintF("[%p - %p] => %u\n", static_cast<void*>(it->second.start),
147 0 : static_cast<void*>(it->first), it->second.trace_node_id);
148 : }
149 0 : PrintF("]\n");
150 0 : }
151 :
152 :
153 13314 : void AddressToTraceMap::RemoveRange(Address start, Address end) {
154 : RangeMap::iterator it = ranges_.upper_bound(start);
155 26628 : if (it == ranges_.end()) return;
156 :
157 : RangeStack prev_range(0, 0);
158 :
159 : RangeMap::iterator to_remove_begin = it;
160 12016 : if (it->second.start < start) {
161 10 : prev_range = it->second;
162 : }
163 50 : do {
164 12061 : if (it->first > end) {
165 12011 : if (it->second.start < end) {
166 5 : it->second.start = end;
167 : }
168 : break;
169 : }
170 : ++it;
171 : } while (it != ranges_.end());
172 :
173 : ranges_.erase(to_remove_begin, it);
174 :
175 12016 : if (prev_range.start != 0) {
176 10 : ranges_.insert(RangeMap::value_type(start, prev_range));
177 : }
178 : }
179 :
180 30 : AllocationTracker::AllocationTracker(HeapObjectsMap* ids, StringsStorage* names)
181 : : ids_(ids),
182 : names_(names),
183 : id_to_function_info_index_(),
184 60 : info_index_for_other_state_(0) {
185 60 : FunctionInfo* info = new FunctionInfo();
186 30 : info->name = "(root)";
187 30 : function_info_list_.push_back(info);
188 30 : }
189 :
190 :
191 30 : AllocationTracker::~AllocationTracker() {
192 60 : for (UnresolvedLocation* location : unresolved_locations_) delete location;
193 380 : for (FunctionInfo* info : function_info_list_) delete info;
194 30 : }
195 :
196 :
197 30 : void AllocationTracker::PrepareForSerialization() {
198 305 : for (UnresolvedLocation* location : unresolved_locations_) {
199 245 : location->Resolve();
200 490 : delete location;
201 : }
202 : unresolved_locations_.clear();
203 30 : unresolved_locations_.shrink_to_fit();
204 30 : }
205 :
206 :
207 13279 : void AllocationTracker::AllocationEvent(Address addr, int size) {
208 : DisallowHeapAllocation no_allocation;
209 13279 : Heap* heap = ids_->heap();
210 :
211 : // Mark the new block as FreeSpace to make sure the heap is iterable
212 : // while we are capturing stack trace.
213 13279 : heap->CreateFillerObjectAt(addr, size, ClearRecordedSlots::kNo);
214 :
215 912 : Isolate* isolate = heap->isolate();
216 : int length = 0;
217 13279 : JavaScriptFrameIterator it(isolate);
218 72470 : while (!it.done() && length < kMaxAllocationTraceLength) {
219 : JavaScriptFrame* frame = it.frame();
220 45912 : SharedFunctionInfo* shared = frame->function()->shared();
221 : SnapshotObjectId id = ids_->FindOrAddEntry(
222 45912 : shared->address(), shared->Size(), false);
223 45912 : allocation_trace_buffer_[length++] = AddFunctionInfo(shared, id);
224 45912 : it.Advance();
225 : }
226 13279 : if (length == 0) {
227 912 : unsigned index = functionInfoIndexForVMState(isolate->current_vm_state());
228 912 : if (index != 0) {
229 255 : allocation_trace_buffer_[length++] = index;
230 : }
231 : }
232 13279 : AllocationTraceNode* top_node = trace_tree_.AddPathFromEnd(
233 26558 : Vector<unsigned>(allocation_trace_buffer_, length));
234 13279 : top_node->AddAllocation(size);
235 :
236 13279 : address_to_trace_.AddRange(addr, size, top_node->id());
237 13279 : }
238 :
239 :
240 : static uint32_t SnapshotObjectIdHash(SnapshotObjectId id) {
241 : return ComputeIntegerHash(static_cast<uint32_t>(id));
242 : }
243 :
244 :
245 45912 : unsigned AllocationTracker::AddFunctionInfo(SharedFunctionInfo* shared,
246 : SnapshotObjectId id) {
247 : base::HashMap::Entry* entry = id_to_function_info_index_.LookupOrInsert(
248 91824 : reinterpret_cast<void*>(id), SnapshotObjectIdHash(id));
249 45912 : if (entry->value == nullptr) {
250 520 : FunctionInfo* info = new FunctionInfo();
251 260 : info->name = names_->GetFunctionName(shared->DebugName());
252 260 : info->function_id = id;
253 260 : if (shared->script()->IsScript()) {
254 : Script* script = Script::cast(shared->script());
255 245 : if (script->name()->IsName()) {
256 : Name* name = Name::cast(script->name());
257 60 : info->script_name = names_->GetName(name);
258 : }
259 490 : info->script_id = script->id();
260 : // Converting start offset into line and column may cause heap
261 : // allocations so we postpone them until snapshot serialization.
262 : unresolved_locations_.push_back(
263 490 : new UnresolvedLocation(script, shared->start_position(), info));
264 : }
265 520 : entry->value = reinterpret_cast<void*>(function_info_list_.size());
266 260 : function_info_list_.push_back(info);
267 : }
268 45912 : return static_cast<unsigned>(reinterpret_cast<intptr_t>((entry->value)));
269 : }
270 :
271 :
272 912 : unsigned AllocationTracker::functionInfoIndexForVMState(StateTag state) {
273 912 : if (state != OTHER) return 0;
274 255 : if (info_index_for_other_state_ == 0) {
275 60 : FunctionInfo* info = new FunctionInfo();
276 30 : info->name = "(V8 API)";
277 : info_index_for_other_state_ =
278 60 : static_cast<unsigned>(function_info_list_.size());
279 30 : function_info_list_.push_back(info);
280 : }
281 255 : return info_index_for_other_state_;
282 : }
283 :
284 :
285 245 : AllocationTracker::UnresolvedLocation::UnresolvedLocation(
286 : Script* script, int start, FunctionInfo* info)
287 : : start_position_(start),
288 245 : info_(info) {
289 490 : script_ = script->GetIsolate()->global_handles()->Create(script);
290 : GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()), this,
291 245 : &HandleWeakScript, v8::WeakCallbackType::kParameter);
292 245 : }
293 :
294 :
295 0 : AllocationTracker::UnresolvedLocation::~UnresolvedLocation() {
296 245 : if (!script_.is_null()) {
297 245 : GlobalHandles::Destroy(reinterpret_cast<Object**>(script_.location()));
298 : }
299 0 : }
300 :
301 :
302 245 : void AllocationTracker::UnresolvedLocation::Resolve() {
303 490 : if (script_.is_null()) return;
304 : HandleScope scope(script_->GetIsolate());
305 245 : info_->line = Script::GetLineNumber(script_, start_position_);
306 245 : info_->column = Script::GetColumnNumber(script_, start_position_);
307 : }
308 :
309 0 : void AllocationTracker::UnresolvedLocation::HandleWeakScript(
310 0 : const v8::WeakCallbackInfo<void>& data) {
311 : UnresolvedLocation* loc =
312 : reinterpret_cast<UnresolvedLocation*>(data.GetParameter());
313 0 : GlobalHandles::Destroy(reinterpret_cast<Object**>(loc->script_.location()));
314 0 : loc->script_ = Handle<Script>::null();
315 0 : }
316 :
317 :
318 : } // namespace internal
319 : } // namespace v8
|