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.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(heap)),
     20       is_tracking_object_moves_(false),
     21       get_retainer_infos_callback_(nullptr) {}
     22 
     23 static void DeleteHeapSnapshot(HeapSnapshot** snapshot_ptr) {
     24   delete *snapshot_ptr;
     25 }
     26 
     27 
     28 HeapProfiler::~HeapProfiler() {
     29   snapshots_.Iterate(DeleteHeapSnapshot);
     30   snapshots_.Clear();
     31 }
     32 
     33 
     34 void HeapProfiler::DeleteAllSnapshots() {
     35   snapshots_.Iterate(DeleteHeapSnapshot);
     36   snapshots_.Clear();
     37   names_.reset(new StringsStorage(heap()));
     38 }
     39 
     40 
     41 void HeapProfiler::RemoveSnapshot(HeapSnapshot* snapshot) {
     42   snapshots_.RemoveElement(snapshot);
     43 }
     44 
     45 
     46 void HeapProfiler::DefineWrapperClass(
     47     uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback) {
     48   DCHECK(class_id != v8::HeapProfiler::kPersistentHandleNoClassId);
     49   if (wrapper_callbacks_.length() <= class_id) {
     50     wrapper_callbacks_.AddBlock(
     51         NULL, class_id - wrapper_callbacks_.length() + 1);
     52   }
     53   wrapper_callbacks_[class_id] = callback;
     54 }
     55 
     56 
     57 v8::RetainedObjectInfo* HeapProfiler::ExecuteWrapperClassCallback(
     58     uint16_t class_id, Object** wrapper) {
     59   if (wrapper_callbacks_.length() <= class_id) return NULL;
     60   return wrapper_callbacks_[class_id](
     61       class_id, Utils::ToLocal(Handle<Object>(wrapper)));
     62 }
     63 
     64 void HeapProfiler::SetGetRetainerInfosCallback(
     65     v8::HeapProfiler::GetRetainerInfosCallback callback) {
     66   get_retainer_infos_callback_ = callback;
     67 }
     68 
     69 v8::HeapProfiler::RetainerInfos HeapProfiler::GetRetainerInfos(
     70     Isolate* isolate) {
     71   v8::HeapProfiler::RetainerInfos infos;
     72   if (get_retainer_infos_callback_ != nullptr)
     73     infos =
     74         get_retainer_infos_callback_(reinterpret_cast<v8::Isolate*>(isolate));
     75   return infos;
     76 }
     77 
     78 HeapSnapshot* HeapProfiler::TakeSnapshot(
     79     v8::ActivityControl* control,
     80     v8::HeapProfiler::ObjectNameResolver* resolver) {
     81   HeapSnapshot* result = new HeapSnapshot(this);
     82   {
     83     HeapSnapshotGenerator generator(result, control, resolver, heap());
     84     if (!generator.GenerateSnapshot()) {
     85       delete result;
     86       result = NULL;
     87     } else {
     88       snapshots_.Add(result);
     89     }
     90   }
     91   ids_->RemoveDeadEntries();
     92   is_tracking_object_moves_ = true;
     93 
     94   heap()->isolate()->debug()->feature_tracker()->Track(
     95       DebugFeatureTracker::kHeapSnapshot);
     96 
     97   return result;
     98 }
     99 
    100 bool HeapProfiler::StartSamplingHeapProfiler(
    101     uint64_t sample_interval, int stack_depth,
    102     v8::HeapProfiler::SamplingFlags flags) {
    103   if (sampling_heap_profiler_.get()) {
    104     return false;
    105   }
    106   sampling_heap_profiler_.reset(new SamplingHeapProfiler(
    107       heap(), names_.get(), sample_interval, stack_depth, flags));
    108   return true;
    109 }
    110 
    111 
    112 void HeapProfiler::StopSamplingHeapProfiler() {
    113   sampling_heap_profiler_.reset();
    114 }
    115 
    116 
    117 v8::AllocationProfile* HeapProfiler::GetAllocationProfile() {
    118   if (sampling_heap_profiler_.get()) {
    119     return sampling_heap_profiler_->GetAllocationProfile();
    120   } else {
    121     return nullptr;
    122   }
    123 }
    124 
    125 
    126 void HeapProfiler::StartHeapObjectsTracking(bool track_allocations) {
    127   ids_->UpdateHeapObjectsMap();
    128   is_tracking_object_moves_ = true;
    129   DCHECK(!is_tracking_allocations());
    130   if (track_allocations) {
    131     allocation_tracker_.reset(new AllocationTracker(ids_.get(), names_.get()));
    132     heap()->DisableInlineAllocation();
    133     heap()->isolate()->debug()->feature_tracker()->Track(
    134         DebugFeatureTracker::kAllocationTracking);
    135   }
    136 }
    137 
    138 
    139 SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream,
    140                                                     int64_t* timestamp_us) {
    141   return ids_->PushHeapObjectsStats(stream, timestamp_us);
    142 }
    143 
    144 
    145 void HeapProfiler::StopHeapObjectsTracking() {
    146   ids_->StopHeapObjectsTracking();
    147   if (is_tracking_allocations()) {
    148     allocation_tracker_.reset();
    149     heap()->EnableInlineAllocation();
    150   }
    151 }
    152 
    153 
    154 size_t HeapProfiler::GetMemorySizeUsedByProfiler() {
    155   size_t size = sizeof(*this);
    156   size += names_->GetUsedMemorySize();
    157   size += ids_->GetUsedMemorySize();
    158   size += GetMemoryUsedByList(snapshots_);
    159   for (int i = 0; i < snapshots_.length(); ++i) {
    160     size += snapshots_[i]->RawSnapshotSize();
    161   }
    162   return size;
    163 }
    164 
    165 
    166 int HeapProfiler::GetSnapshotsCount() {
    167   return snapshots_.length();
    168 }
    169 
    170 
    171 HeapSnapshot* HeapProfiler::GetSnapshot(int index) {
    172   return snapshots_.at(index);
    173 }
    174 
    175 
    176 SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) {
    177   if (!obj->IsHeapObject())
    178     return v8::HeapProfiler::kUnknownObjectId;
    179   return ids_->FindEntry(HeapObject::cast(*obj)->address());
    180 }
    181 
    182 
    183 void HeapProfiler::ObjectMoveEvent(Address from, Address to, int size) {
    184   base::LockGuard<base::Mutex> guard(&profiler_mutex_);
    185   bool known_object = ids_->MoveObject(from, to, size);
    186   if (!known_object && allocation_tracker_) {
    187     allocation_tracker_->address_to_trace()->MoveObject(from, to, size);
    188   }
    189 }
    190 
    191 
    192 void HeapProfiler::AllocationEvent(Address addr, int size) {
    193   DisallowHeapAllocation no_allocation;
    194   if (allocation_tracker_) {
    195     allocation_tracker_->AllocationEvent(addr, size);
    196   }
    197 }
    198 
    199 
    200 void HeapProfiler::UpdateObjectSizeEvent(Address addr, int size) {
    201   ids_->UpdateObjectSize(addr, size);
    202 }
    203 
    204 
    205 void HeapProfiler::SetRetainedObjectInfo(UniqueId id,
    206                                          RetainedObjectInfo* info) {
    207   // TODO(yurus, marja): Don't route this information through GlobalHandles.
    208   heap()->isolate()->global_handles()->SetRetainedObjectInfo(id, info);
    209 }
    210 
    211 
    212 Handle<HeapObject> HeapProfiler::FindHeapObjectById(SnapshotObjectId id) {
    213   HeapObject* object = NULL;
    214   HeapIterator iterator(heap(), HeapIterator::kFilterUnreachable);
    215   // Make sure that object with the given id is still reachable.
    216   for (HeapObject* obj = iterator.next();
    217        obj != NULL;
    218        obj = iterator.next()) {
    219     if (ids_->FindEntry(obj->address()) == id) {
    220       DCHECK(object == NULL);
    221       object = obj;
    222       // Can't break -- kFilterUnreachable requires full heap traversal.
    223     }
    224   }
    225   return object != NULL ? Handle<HeapObject>(object) : Handle<HeapObject>();
    226 }
    227 
    228 
    229 void HeapProfiler::ClearHeapObjectMap() {
    230   ids_.reset(new HeapObjectsMap(heap()));
    231   if (!is_tracking_allocations()) is_tracking_object_moves_ = false;
    232 }
    233 
    234 
    235 Heap* HeapProfiler::heap() const { return ids_->heap(); }
    236 
    237 
    238 }  // namespace internal
    239 }  // namespace v8
    240