5 #include "src/profiler/allocation-tracker.h" 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" 15 AllocationTraceNode::AllocationTraceNode(
16 AllocationTraceTree* tree,
unsigned function_info_index)
18 function_info_index_(function_info_index),
21 id_(tree->next_node_id()) {
25 AllocationTraceNode::~AllocationTraceNode() {
26 for (AllocationTraceNode* node : children_)
delete node;
30 AllocationTraceNode* AllocationTraceNode::FindChild(
31 unsigned function_info_index) {
32 for (AllocationTraceNode* node : children_) {
33 if (node->function_info_index() == function_info_index)
return node;
39 AllocationTraceNode* AllocationTraceNode::FindOrAddChild(
40 unsigned function_info_index) {
41 AllocationTraceNode* child = FindChild(function_info_index);
42 if (child ==
nullptr) {
43 child =
new AllocationTraceNode(tree_, function_info_index);
44 children_.push_back(child);
50 void AllocationTraceNode::AddAllocation(
unsigned size) {
56 void AllocationTraceNode::Print(
int indent, AllocationTracker* tracker) {
57 base::OS::Print(
"%10u %10u %*c", total_size_, allocation_count_, indent,
' ');
58 if (tracker !=
nullptr) {
59 AllocationTracker::FunctionInfo* info =
60 tracker->function_info_list()[function_info_index_];
61 base::OS::Print(
"%s #%u", info->name, id_);
63 base::OS::Print(
"%u #%u", function_info_index_, id_);
65 base::OS::Print(
"\n");
67 for (AllocationTraceNode* node : children_) {
68 node->Print(indent, tracker);
73 AllocationTraceTree::AllocationTraceTree()
78 AllocationTraceNode* AllocationTraceTree::AddPathFromEnd(
79 const Vector<unsigned>& path) {
80 AllocationTraceNode* node = root();
81 for (
unsigned* entry = path.start() + path.length() - 1;
82 entry != path.start() - 1;
84 node = node->FindOrAddChild(*entry);
90 void AllocationTraceTree::Print(AllocationTracker* tracker) {
91 base::OS::Print(
"[AllocationTraceTree:]\n");
92 base::OS::Print(
"Total size | Allocation count | Function id | id\n");
93 root()->Print(0, tracker);
96 AllocationTracker::FunctionInfo::FunctionInfo()
106 void AddressToTraceMap::AddRange(Address start,
int size,
107 unsigned trace_node_id) {
108 Address end = start + size;
109 RemoveRange(start, end);
111 RangeStack new_range(start, trace_node_id);
112 ranges_.insert(RangeMap::value_type(end, new_range));
116 unsigned AddressToTraceMap::GetTraceNodeId(Address addr) {
117 RangeMap::const_iterator it = ranges_.upper_bound(addr);
118 if (it == ranges_.end())
return 0;
119 if (it->second.start <= addr) {
120 return it->second.trace_node_id;
126 void AddressToTraceMap::MoveObject(Address from, Address to,
int size) {
127 unsigned trace_node_id = GetTraceNodeId(from);
128 if (trace_node_id == 0)
return;
129 RemoveRange(from, from + size);
130 AddRange(to, size, trace_node_id);
134 void AddressToTraceMap::Clear() {
139 void AddressToTraceMap::Print() {
140 PrintF(
"[AddressToTraceMap (%" PRIuS
"): \n", ranges_.size());
141 for (RangeMap::iterator it = ranges_.begin(); it != ranges_.end(); ++it) {
142 PrintF(
"[%p - %p] => %u\n", reinterpret_cast<void*>(it->second.start),
143 reinterpret_cast<void*>(it->first), it->second.trace_node_id);
149 void AddressToTraceMap::RemoveRange(Address start, Address end) {
150 RangeMap::iterator it = ranges_.upper_bound(start);
151 if (it == ranges_.end())
return;
153 RangeStack prev_range(0, 0);
155 RangeMap::iterator to_remove_begin = it;
156 if (it->second.start < start) {
157 prev_range = it->second;
160 if (it->first > end) {
161 if (it->second.start < end) {
162 it->second.start = end;
167 }
while (it != ranges_.end());
169 ranges_.erase(to_remove_begin, it);
171 if (prev_range.start != 0) {
172 ranges_.insert(RangeMap::value_type(start, prev_range));
176 AllocationTracker::AllocationTracker(HeapObjectsMap* ids, StringsStorage* names)
179 id_to_function_info_index_(),
180 info_index_for_other_state_(0) {
181 FunctionInfo* info =
new FunctionInfo();
182 info->name =
"(root)";
183 function_info_list_.push_back(info);
187 AllocationTracker::~AllocationTracker() {
188 for (UnresolvedLocation* location : unresolved_locations_)
delete location;
189 for (FunctionInfo* info : function_info_list_)
delete info;
193 void AllocationTracker::PrepareForSerialization() {
194 for (UnresolvedLocation* location : unresolved_locations_) {
198 unresolved_locations_.clear();
199 unresolved_locations_.shrink_to_fit();
203 void AllocationTracker::AllocationEvent(Address addr,
int size) {
204 DisallowHeapAllocation no_allocation;
205 Heap* heap = ids_->heap();
209 heap->CreateFillerObjectAt(addr, size, ClearRecordedSlots::kNo);
211 Isolate* isolate = heap->isolate();
213 JavaScriptFrameIterator it(isolate);
214 while (!it.done() && length < kMaxAllocationTraceLength) {
215 JavaScriptFrame* frame = it.frame();
216 SharedFunctionInfo* shared = frame->function()->shared();
217 SnapshotObjectId
id = ids_->FindOrAddEntry(
218 shared->address(), shared->Size(),
false);
219 allocation_trace_buffer_[length++] = AddFunctionInfo(shared,
id);
223 unsigned index = functionInfoIndexForVMState(isolate->current_vm_state());
225 allocation_trace_buffer_[length++] = index;
228 AllocationTraceNode* top_node = trace_tree_.AddPathFromEnd(
229 Vector<unsigned>(allocation_trace_buffer_, length));
230 top_node->AddAllocation(size);
232 address_to_trace_.AddRange(addr, size, top_node->id());
236 static uint32_t SnapshotObjectIdHash(SnapshotObjectId
id) {
237 return ComputeUnseededHash(static_cast<uint32_t>(
id));
241 unsigned AllocationTracker::AddFunctionInfo(SharedFunctionInfo* shared,
242 SnapshotObjectId
id) {
243 base::HashMap::Entry* entry = id_to_function_info_index_.LookupOrInsert(
244 reinterpret_cast<void*>(
id), SnapshotObjectIdHash(
id));
245 if (entry->value ==
nullptr) {
246 FunctionInfo* info =
new FunctionInfo();
247 info->name = names_->GetName(shared->DebugName());
248 info->function_id = id;
249 if (shared->script()->IsScript()) {
250 Script* script = Script::cast(shared->script());
251 if (script->name()->IsName()) {
252 Name name = Name::cast(script->name());
253 info->script_name = names_->GetName(name);
255 info->script_id = script->id();
258 unresolved_locations_.push_back(
259 new UnresolvedLocation(script, shared->StartPosition(), info));
261 entry->value =
reinterpret_cast<void*
>(function_info_list_.size());
262 function_info_list_.push_back(info);
264 return static_cast<unsigned>(
reinterpret_cast<intptr_t
>((entry->value)));
268 unsigned AllocationTracker::functionInfoIndexForVMState(StateTag state) {
269 if (state != OTHER)
return 0;
270 if (info_index_for_other_state_ == 0) {
271 FunctionInfo* info =
new FunctionInfo();
272 info->name =
"(V8 API)";
273 info_index_for_other_state_ =
274 static_cast<unsigned>(function_info_list_.size());
275 function_info_list_.push_back(info);
277 return info_index_for_other_state_;
281 AllocationTracker::UnresolvedLocation::UnresolvedLocation(
282 Script* script,
int start, FunctionInfo* info)
283 : start_position_(start),
285 script_ = script->GetIsolate()->global_handles()->Create(script);
286 GlobalHandles::MakeWeak(script_.location(),
this, &HandleWeakScript,
287 v8::WeakCallbackType::kParameter);
291 AllocationTracker::UnresolvedLocation::~UnresolvedLocation() {
292 if (!script_.is_null()) {
293 GlobalHandles::Destroy(script_.location());
298 void AllocationTracker::UnresolvedLocation::Resolve() {
299 if (script_.is_null())
return;
300 HandleScope scope(script_->GetIsolate());
301 info_->line = Script::GetLineNumber(script_, start_position_);
302 info_->column = Script::GetColumnNumber(script_, start_position_);
305 void AllocationTracker::UnresolvedLocation::HandleWeakScript(
307 UnresolvedLocation* loc =
308 reinterpret_cast<UnresolvedLocation*
>(data.GetParameter());
309 GlobalHandles::Destroy(loc->script_.location());
310 loc->script_ = Handle<Script>::null();