LCOV - code coverage report
Current view: top level - src/profiler - heap-profiler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 105 121 86.8 %
Date: 2019-01-20 Functions: 26 31 83.9 %

          Line data    Source code
       1             : // Copyright 2009-2010 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/heap-profiler.h"
       6             : 
       7             : #include "src/api-inl.h"
       8             : #include "src/debug/debug.h"
       9             : #include "src/heap/heap-inl.h"
      10             : #include "src/profiler/allocation-tracker.h"
      11             : #include "src/profiler/heap-snapshot-generator-inl.h"
      12             : #include "src/profiler/sampling-heap-profiler.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17       62883 : HeapProfiler::HeapProfiler(Heap* heap)
      18       62883 :     : ids_(new HeapObjectsMap(heap)),
      19             :       names_(new StringsStorage()),
      20      251532 :       is_tracking_object_moves_(false) {}
      21             : 
      22             : HeapProfiler::~HeapProfiler() = default;
      23             : 
      24          70 : void HeapProfiler::DeleteAllSnapshots() {
      25             :   snapshots_.clear();
      26          70 :   MaybeClearStringsStorage();
      27          70 : }
      28             : 
      29         164 : void HeapProfiler::MaybeClearStringsStorage() {
      30         487 :   if (snapshots_.empty() && !sampling_heap_profiler_ && !allocation_tracker_) {
      31         154 :     names_.reset(new StringsStorage());
      32             :   }
      33         164 : }
      34             : 
      35           5 : void HeapProfiler::RemoveSnapshot(HeapSnapshot* snapshot) {
      36             :   snapshots_.erase(
      37             :       std::find_if(snapshots_.begin(), snapshots_.end(),
      38             :                    [&](const std::unique_ptr<HeapSnapshot>& entry) {
      39           5 :                      return entry.get() == snapshot;
      40           5 :                    }));
      41           5 : }
      42             : 
      43             : 
      44           0 : void HeapProfiler::DefineWrapperClass(
      45             :     uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback) {
      46             :   DCHECK_NE(class_id, v8::HeapProfiler::kPersistentHandleNoClassId);
      47           0 :   if (wrapper_callbacks_.size() <= class_id) {
      48             :     wrapper_callbacks_.insert(wrapper_callbacks_.end(),
      49           0 :                               class_id - wrapper_callbacks_.size() + 1,
      50           0 :                               nullptr);
      51             :   }
      52           0 :   wrapper_callbacks_[class_id] = callback;
      53           0 : }
      54             : 
      55           0 : v8::RetainedObjectInfo* HeapProfiler::ExecuteWrapperClassCallback(
      56             :     uint16_t class_id, Handle<Object> wrapper) {
      57           0 :   if (wrapper_callbacks_.size() <= class_id) return nullptr;
      58           0 :   return wrapper_callbacks_[class_id](class_id, Utils::ToLocal(wrapper));
      59             : }
      60             : 
      61           0 : void HeapProfiler::SetGetRetainerInfosCallback(
      62             :     v8::HeapProfiler::GetRetainerInfosCallback callback) {
      63           0 :   get_retainer_infos_callback_ = callback;
      64           0 : }
      65             : 
      66         364 : v8::HeapProfiler::RetainerInfos HeapProfiler::GetRetainerInfos(
      67             :     Isolate* isolate) {
      68             :   v8::HeapProfiler::RetainerInfos infos;
      69         364 :   if (get_retainer_infos_callback_ != nullptr)
      70           0 :     infos =
      71             :         get_retainer_infos_callback_(reinterpret_cast<v8::Isolate*>(isolate));
      72         364 :   return infos;
      73             : }
      74             : 
      75          35 : void HeapProfiler::AddBuildEmbedderGraphCallback(
      76             :     v8::HeapProfiler::BuildEmbedderGraphCallback callback, void* data) {
      77          70 :   build_embedder_graph_callbacks_.push_back({callback, data});
      78          35 : }
      79             : 
      80           5 : void HeapProfiler::RemoveBuildEmbedderGraphCallback(
      81             :     v8::HeapProfiler::BuildEmbedderGraphCallback callback, void* data) {
      82             :   auto it = std::find(build_embedder_graph_callbacks_.begin(),
      83             :                       build_embedder_graph_callbacks_.end(),
      84          10 :                       std::make_pair(callback, data));
      85           5 :   if (it != build_embedder_graph_callbacks_.end())
      86           5 :     build_embedder_graph_callbacks_.erase(it);
      87           5 : }
      88             : 
      89          35 : void HeapProfiler::BuildEmbedderGraph(Isolate* isolate,
      90             :                                       v8::EmbedderGraph* graph) {
      91         110 :   for (const auto& cb : build_embedder_graph_callbacks_) {
      92          40 :     cb.first(reinterpret_cast<v8::Isolate*>(isolate), graph, cb.second);
      93             :   }
      94          35 : }
      95             : 
      96         399 : HeapSnapshot* HeapProfiler::TakeSnapshot(
      97             :     v8::ActivityControl* control,
      98             :     v8::HeapProfiler::ObjectNameResolver* resolver) {
      99         399 :   HeapSnapshot* result = new HeapSnapshot(this);
     100             :   {
     101         399 :     HeapSnapshotGenerator generator(result, control, resolver, heap());
     102         399 :     if (!generator.GenerateSnapshot()) {
     103           5 :       delete result;
     104           5 :       result = nullptr;
     105             :     } else {
     106         394 :       snapshots_.emplace_back(result);
     107         399 :     }
     108             :   }
     109         399 :   ids_->RemoveDeadEntries();
     110         399 :   is_tracking_object_moves_ = true;
     111             : 
     112             :   heap()->isolate()->debug()->feature_tracker()->Track(
     113         399 :       DebugFeatureTracker::kHeapSnapshot);
     114             : 
     115         399 :   return result;
     116             : }
     117             : 
     118          59 : bool HeapProfiler::StartSamplingHeapProfiler(
     119             :     uint64_t sample_interval, int stack_depth,
     120             :     v8::HeapProfiler::SamplingFlags flags) {
     121          59 :   if (sampling_heap_profiler_.get()) {
     122             :     return false;
     123             :   }
     124             :   sampling_heap_profiler_.reset(new SamplingHeapProfiler(
     125          59 :       heap(), names_.get(), sample_interval, stack_depth, flags));
     126             :   return true;
     127             : }
     128             : 
     129             : 
     130          59 : void HeapProfiler::StopSamplingHeapProfiler() {
     131             :   sampling_heap_profiler_.reset();
     132          59 :   MaybeClearStringsStorage();
     133          59 : }
     134             : 
     135             : 
     136          77 : v8::AllocationProfile* HeapProfiler::GetAllocationProfile() {
     137          77 :   if (sampling_heap_profiler_.get()) {
     138          64 :     return sampling_heap_profiler_->GetAllocationProfile();
     139             :   } else {
     140             :     return nullptr;
     141             :   }
     142             : }
     143             : 
     144             : 
     145          45 : void HeapProfiler::StartHeapObjectsTracking(bool track_allocations) {
     146          45 :   ids_->UpdateHeapObjectsMap();
     147          45 :   is_tracking_object_moves_ = true;
     148             :   DCHECK(!allocation_tracker_);
     149          45 :   if (track_allocations) {
     150          35 :     allocation_tracker_.reset(new AllocationTracker(ids_.get(), names_.get()));
     151          70 :     heap()->AddHeapObjectAllocationTracker(this);
     152             :     heap()->isolate()->debug()->feature_tracker()->Track(
     153          35 :         DebugFeatureTracker::kAllocationTracking);
     154             :   }
     155          45 : }
     156             : 
     157          55 : SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream,
     158             :                                                     int64_t* timestamp_us) {
     159          55 :   return ids_->PushHeapObjectsStats(stream, timestamp_us);
     160             : }
     161             : 
     162        3879 : void HeapProfiler::StopHeapObjectsTracking() {
     163        3879 :   ids_->StopHeapObjectsTracking();
     164        3879 :   if (allocation_tracker_) {
     165             :     allocation_tracker_.reset();
     166          35 :     MaybeClearStringsStorage();
     167          70 :     heap()->RemoveHeapObjectAllocationTracker(this);
     168             :   }
     169        3879 : }
     170             : 
     171         155 : int HeapProfiler::GetSnapshotsCount() {
     172         310 :   return static_cast<int>(snapshots_.size());
     173             : }
     174             : 
     175          30 : HeapSnapshot* HeapProfiler::GetSnapshot(int index) {
     176          60 :   return snapshots_.at(index).get();
     177             : }
     178             : 
     179         155 : SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) {
     180         310 :   if (!obj->IsHeapObject())
     181             :     return v8::HeapProfiler::kUnknownObjectId;
     182         155 :   return ids_->FindEntry(HeapObject::cast(*obj)->address());
     183             : }
     184             : 
     185      171205 : void HeapProfiler::ObjectMoveEvent(Address from, Address to, int size) {
     186      171205 :   base::MutexGuard guard(&profiler_mutex_);
     187      171205 :   bool known_object = ids_->MoveObject(from, to, size);
     188      340409 :   if (!known_object && allocation_tracker_) {
     189       30770 :     allocation_tracker_->address_to_trace()->MoveObject(from, to, size);
     190             :   }
     191      171205 : }
     192             : 
     193      115711 : void HeapProfiler::AllocationEvent(Address addr, int size) {
     194             :   DisallowHeapAllocation no_allocation;
     195      115711 :   if (allocation_tracker_) {
     196      115711 :     allocation_tracker_->AllocationEvent(addr, size);
     197             :   }
     198      115711 : }
     199             : 
     200             : 
     201           0 : void HeapProfiler::UpdateObjectSizeEvent(Address addr, int size) {
     202           0 :   ids_->UpdateObjectSize(addr, size);
     203           0 : }
     204             : 
     205         140 : Handle<HeapObject> HeapProfiler::FindHeapObjectById(SnapshotObjectId id) {
     206             :   HeapObject object;
     207         140 :   HeapIterator iterator(heap(), HeapIterator::kFilterUnreachable);
     208             :   // Make sure that object with the given id is still reachable.
     209      910197 :   for (HeapObject obj = iterator.next(); !obj.is_null();
     210             :        obj = iterator.next()) {
     211      910057 :     if (ids_->FindEntry(obj->address()) == id) {
     212             :       DCHECK(object.is_null());
     213             :       object = obj;
     214             :       // Can't break -- kFilterUnreachable requires full heap traversal.
     215             :     }
     216             :   }
     217             :   return !object.is_null() ? Handle<HeapObject>(object, isolate())
     218         280 :                            : Handle<HeapObject>();
     219             : }
     220             : 
     221             : 
     222        3839 : void HeapProfiler::ClearHeapObjectMap() {
     223        3839 :   ids_.reset(new HeapObjectsMap(heap()));
     224        3839 :   if (!allocation_tracker_) is_tracking_object_moves_ = false;
     225        3839 : }
     226             : 
     227             : 
     228     6620066 : Heap* HeapProfiler::heap() const { return ids_->heap(); }
     229             : 
     230    12018110 : Isolate* HeapProfiler::isolate() const { return heap()->isolate(); }
     231             : 
     232          85 : void HeapProfiler::QueryObjects(Handle<Context> context,
     233             :                                 debug::QueryObjectPredicate* predicate,
     234             :                                 PersistentValueVector<v8::Object>* objects) {
     235             :   // We should return accurate information about live objects, so we need to
     236             :   // collect all garbage first.
     237          85 :   heap()->CollectAllAvailableGarbage(GarbageCollectionReason::kHeapProfiler);
     238          85 :   HeapIterator heap_iterator(heap());
     239     2330258 :   for (HeapObject heap_obj = heap_iterator.next(); !heap_obj.is_null();
     240             :        heap_obj = heap_iterator.next()) {
     241     2633088 :     if (!heap_obj->IsJSObject() || heap_obj->IsExternal(isolate())) continue;
     242             :     v8::Local<v8::Object> v8_obj(
     243      302715 :         Utils::ToLocal(handle(JSObject::cast(heap_obj), isolate())));
     244      302715 :     if (!predicate->Filter(v8_obj)) continue;
     245         100 :     objects->Append(v8_obj);
     246          85 :   }
     247          85 : }
     248             : 
     249             : }  // namespace internal
     250      183867 : }  // namespace v8

Generated by: LCOV version 1.10