LCOV - code coverage report
Current view: top level - src/profiler - allocation-tracker.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 132 157 84.1 %
Date: 2019-01-20 Functions: 20 28 71.4 %

          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         300 : AllocationTraceNode::~AllocationTraceNode() {
      26         865 :   for (AllocationTraceNode* node : children_) delete node;
      27         300 : }
      28             : 
      29             : 
      30           0 : AllocationTraceNode* AllocationTraceNode::FindChild(
      31             :     unsigned function_info_index) {
      32      416021 :   for (AllocationTraceNode* node : children_) {
      33      207878 :     if (node->function_info_index() == function_info_index) return node;
      34             :   }
      35             :   return nullptr;
      36             : }
      37             : 
      38             : 
      39      129177 : AllocationTraceNode* AllocationTraceNode::FindOrAddChild(
      40             :     unsigned function_info_index) {
      41      129177 :   AllocationTraceNode* child = FindChild(function_info_index);
      42      129177 :   if (child == nullptr) {
      43         530 :     child = new AllocationTraceNode(tree_, function_info_index);
      44         265 :     children_.push_back(child);
      45             :   }
      46      129177 :   return child;
      47             : }
      48             : 
      49             : 
      50           0 : void AllocationTraceNode::AddAllocation(unsigned size) {
      51      115711 :   total_size_ += size;
      52      115711 :   ++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         810 :   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      115711 : AllocationTraceNode* AllocationTraceTree::AddPathFromEnd(
      79      360599 :     const Vector<unsigned>& path) {
      80      115711 :   AllocationTraceNode* node = root();
      81      489776 :   for (unsigned* entry = path.start() + path.length() - 1;
      82      244888 :        entry != path.start() - 1;
      83             :        --entry) {
      84      129177 :     node = node->FindOrAddChild(*entry);
      85             :   }
      86      115711 :   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      146516 : void AddressToTraceMap::AddRange(Address start, int size,
     107             :                                  unsigned trace_node_id) {
     108      146516 :   Address end = start + size;
     109      146516 :   RemoveRange(start, end);
     110             : 
     111             :   RangeStack new_range(start, trace_node_id);
     112      146516 :   ranges_.insert(RangeMap::value_type(end, new_range));
     113      146516 : }
     114             : 
     115             : 
     116       33285 : unsigned AddressToTraceMap::GetTraceNodeId(Address addr) {
     117             :   RangeMap::const_iterator it = ranges_.upper_bound(addr);
     118       64055 :   if (it == ranges_.end()) return 0;
     119       30850 :   if (it->second.start <= addr) {
     120       30840 :     return it->second.trace_node_id;
     121             :   }
     122             :   return 0;
     123             : }
     124             : 
     125             : 
     126       30770 : void AddressToTraceMap::MoveObject(Address from, Address to, int size) {
     127             :   unsigned trace_node_id = GetTraceNodeId(from);
     128       61540 :   if (trace_node_id == 0) return;
     129       30770 :   RemoveRange(from, from + size);
     130       30770 :   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             :     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      177286 : void AddressToTraceMap::RemoveRange(Address start, Address end) {
     150             :   RangeMap::iterator it = ranges_.upper_bound(start);
     151      354572 :   if (it == ranges_.end()) return;
     152             : 
     153             :   RangeStack prev_range(0, 0);
     154             : 
     155             :   RangeMap::iterator to_remove_begin = it;
     156      131926 :   if (it->second.start < start) {
     157          10 :     prev_range = it->second;
     158             :   }
     159       31904 :   do {
     160      163815 :     if (it->first > end) {
     161      131911 :       if (it->second.start < end) {
     162        2782 :         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      131926 :   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          35 : AllocationTracker::~AllocationTracker() {
     188          80 :   for (UnresolvedLocation* location : unresolved_locations_) delete location;
     189         360 :   for (FunctionInfo* info : function_info_list_) delete info;
     190          35 : }
     191             : 
     192             : 
     193          30 : void AllocationTracker::PrepareForSerialization() {
     194         245 :   for (UnresolvedLocation* location : unresolved_locations_) {
     195         185 :     location->Resolve();
     196         370 :     delete location;
     197             :   }
     198             :   unresolved_locations_.clear();
     199          30 :   unresolved_locations_.shrink_to_fit();
     200          30 : }
     201             : 
     202             : 
     203      115711 : void AllocationTracker::AllocationEvent(Address addr, int size) {
     204             :   DisallowHeapAllocation no_allocation;
     205      115711 :   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      115711 :   heap->CreateFillerObjectAt(addr, size, ClearRecordedSlots::kNo);
     210             : 
     211       56189 :   Isolate* isolate = heap->isolate();
     212             :   int length = 0;
     213      115711 :   JavaScriptFrameIterator it(isolate);
     214      350224 :   while (!it.done() && length < kMaxAllocationTraceLength) {
     215             :     JavaScriptFrame* frame = it.frame();
     216      118802 :     SharedFunctionInfo shared = frame->function()->shared();
     217             :     SnapshotObjectId id = ids_->FindOrAddEntry(
     218      237604 :         shared->address(), shared->Size(), false);
     219      118802 :     allocation_trace_buffer_[length++] = AddFunctionInfo(shared, id);
     220      118802 :     it.Advance();
     221             :   }
     222      115711 :   if (length == 0) {
     223       56189 :     unsigned index = functionInfoIndexForVMState(isolate->current_vm_state());
     224       56189 :     if (index != 0) {
     225       10375 :       allocation_trace_buffer_[length++] = index;
     226             :     }
     227             :   }
     228      115711 :   AllocationTraceNode* top_node = trace_tree_.AddPathFromEnd(
     229      231422 :       Vector<unsigned>(allocation_trace_buffer_, length));
     230      115711 :   top_node->AddAllocation(size);
     231             : 
     232      115711 :   address_to_trace_.AddRange(addr, size, top_node->id());
     233      115711 : }
     234             : 
     235             : 
     236             : static uint32_t SnapshotObjectIdHash(SnapshotObjectId id) {
     237             :   return ComputeUnseededHash(static_cast<uint32_t>(id));
     238             : }
     239             : 
     240      118802 : unsigned AllocationTracker::AddFunctionInfo(SharedFunctionInfo shared,
     241             :                                             SnapshotObjectId id) {
     242             :   base::HashMap::Entry* entry = id_to_function_info_index_.LookupOrInsert(
     243      237604 :       reinterpret_cast<void*>(id), SnapshotObjectIdHash(id));
     244      118802 :   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         380 :       Script script = Script::cast(shared->script());
     250         380 :       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             :       unresolved_locations_.push_back(
     258         380 :           new UnresolvedLocation(script, shared->StartPosition(), info));
     259             :     }
     260         440 :     entry->value = reinterpret_cast<void*>(function_info_list_.size());
     261         220 :     function_info_list_.push_back(info);
     262             :   }
     263      118802 :   return static_cast<unsigned>(reinterpret_cast<intptr_t>((entry->value)));
     264             : }
     265             : 
     266       56189 : unsigned AllocationTracker::functionInfoIndexForVMState(StateTag state) {
     267       56189 :   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          70 :         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         380 :   script_ = script->GetIsolate()->global_handles()->Create(script);
     283             :   GlobalHandles::MakeWeak(script_.location(), this, &HandleWeakScript,
     284         190 :                           v8::WeakCallbackType::kParameter);
     285         190 : }
     286             : 
     287           0 : 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         370 :   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           0 :     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      183867 : }  // namespace v8

Generated by: LCOV version 1.10