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