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