LCOV - code coverage report
Current view: top level - src/profiler - allocation-tracker.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 128 156 82.1 %
Date: 2017-10-20 Functions: 17 27 63.0 %

          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

Generated by: LCOV version 1.10