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/profiler/allocation-tracker.h"
     10 #include "src/profiler/heap-snapshot-generator-inl.h"
     11 #include "src/profiler/sampling-heap-profiler.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 HeapProfiler::HeapProfiler(Heap* heap)
     17     : ids_(new HeapObjectsMap(heap)),
     18       names_(new StringsStorage(heap)),
     19       is_tracking_object_moves_(false) {
     20 }
     21 
     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 
     65 HeapSnapshot* HeapProfiler::TakeSnapshot(
     66     v8::ActivityControl* control,
     67     v8::HeapProfiler::ObjectNameResolver* resolver) {
     68   HeapSnapshot* result = new HeapSnapshot(this);
     69   {
     70     HeapSnapshotGenerator generator(result, control, resolver, heap());
     71     if (!generator.GenerateSnapshot()) {
     72       delete result;
     73       result = NULL;
     74     } else {
     75       snapshots_.Add(result);
     76     }
     77   }
     78   ids_->RemoveDeadEntries();
     79   is_tracking_object_moves_ = true;
     80 
     81   heap()->isolate()->debug()->feature_tracker()->Track(
     82       DebugFeatureTracker::kHeapSnapshot);
     83 
     84   return result;
     85 }
     86 
     87 bool HeapProfiler::StartSamplingHeapProfiler(
     88     uint64_t sample_interval, int stack_depth,
     89     v8::HeapProfiler::SamplingFlags flags) {
     90   if (sampling_heap_profiler_.get()) {
     91     return false;
     92   }
     93   sampling_heap_profiler_.Reset(new SamplingHeapProfiler(
     94       heap(), names_.get(), sample_interval, stack_depth, flags));
     95   return true;
     96 }
     97 
     98 
     99 void HeapProfiler::StopSamplingHeapProfiler() {
    100   sampling_heap_profiler_.Reset(nullptr);
    101 }
    102 
    103 
    104 v8::AllocationProfile* HeapProfiler::GetAllocationProfile() {
    105   if (sampling_heap_profiler_.get()) {
    106     return sampling_heap_profiler_->GetAllocationProfile();
    107   } else {
    108     return nullptr;
    109   }
    110 }
    111 
    112 
    113 void HeapProfiler::StartHeapObjectsTracking(bool track_allocations) {
    114   ids_->UpdateHeapObjectsMap();
    115   is_tracking_object_moves_ = true;
    116   DCHECK(!is_tracking_allocations());
    117   if (track_allocations) {
    118     allocation_tracker_.Reset(new AllocationTracker(ids_.get(), names_.get()));
    119     heap()->DisableInlineAllocation();
    120     heap()->isolate()->debug()->feature_tracker()->Track(
    121         DebugFeatureTracker::kAllocationTracking);
    122   }
    123 }
    124 
    125 
    126 SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream,
    127                                                     int64_t* timestamp_us) {
    128   return ids_->PushHeapObjectsStats(stream, timestamp_us);
    129 }
    130 
    131 
    132 void HeapProfiler::StopHeapObjectsTracking() {
    133   ids_->StopHeapObjectsTracking();
    134   if (is_tracking_allocations()) {
    135     allocation_tracker_.Reset(NULL);
    136     heap()->EnableInlineAllocation();
    137   }
    138 }
    139 
    140 
    141 size_t HeapProfiler::GetMemorySizeUsedByProfiler() {
    142   size_t size = sizeof(*this);
    143   size += names_->GetUsedMemorySize();
    144   size += ids_->GetUsedMemorySize();
    145   size += GetMemoryUsedByList(snapshots_);
    146   for (int i = 0; i < snapshots_.length(); ++i) {
    147     size += snapshots_[i]->RawSnapshotSize();
    148   }
    149   return size;
    150 }
    151 
    152 
    153 int HeapProfiler::GetSnapshotsCount() {
    154   return snapshots_.length();
    155 }
    156 
    157 
    158 HeapSnapshot* HeapProfiler::GetSnapshot(int index) {
    159   return snapshots_.at(index);
    160 }
    161 
    162 
    163 SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) {
    164   if (!obj->IsHeapObject())
    165     return v8::HeapProfiler::kUnknownObjectId;
    166   return ids_->FindEntry(HeapObject::cast(*obj)->address());
    167 }
    168 
    169 
    170 void HeapProfiler::ObjectMoveEvent(Address from, Address to, int size) {
    171   base::LockGuard<base::Mutex> guard(&profiler_mutex_);
    172   bool known_object = ids_->MoveObject(from, to, size);
    173   if (!known_object && !allocation_tracker_.is_empty()) {
    174     allocation_tracker_->address_to_trace()->MoveObject(from, to, size);
    175   }
    176 }
    177 
    178 
    179 void HeapProfiler::AllocationEvent(Address addr, int size) {
    180   DisallowHeapAllocation no_allocation;
    181   if (!allocation_tracker_.is_empty()) {
    182     allocation_tracker_->AllocationEvent(addr, size);
    183   }
    184 }
    185 
    186 
    187 void HeapProfiler::UpdateObjectSizeEvent(Address addr, int size) {
    188   ids_->UpdateObjectSize(addr, size);
    189 }
    190 
    191 
    192 void HeapProfiler::SetRetainedObjectInfo(UniqueId id,
    193                                          RetainedObjectInfo* info) {
    194   // TODO(yurus, marja): Don't route this information through GlobalHandles.
    195   heap()->isolate()->global_handles()->SetRetainedObjectInfo(id, info);
    196 }
    197 
    198 
    199 Handle<HeapObject> HeapProfiler::FindHeapObjectById(SnapshotObjectId id) {
    200   HeapObject* object = NULL;
    201   HeapIterator iterator(heap(), HeapIterator::kFilterUnreachable);
    202   // Make sure that object with the given id is still reachable.
    203   for (HeapObject* obj = iterator.next();
    204        obj != NULL;
    205        obj = iterator.next()) {
    206     if (ids_->FindEntry(obj->address()) == id) {
    207       DCHECK(object == NULL);
    208       object = obj;
    209       // Can't break -- kFilterUnreachable requires full heap traversal.
    210     }
    211   }
    212   return object != NULL ? Handle<HeapObject>(object) : Handle<HeapObject>();
    213 }
    214 
    215 
    216 void HeapProfiler::ClearHeapObjectMap() {
    217   ids_.Reset(new HeapObjectsMap(heap()));
    218   if (!is_tracking_allocations()) is_tracking_object_moves_ = false;
    219 }
    220 
    221 
    222 Heap* HeapProfiler::heap() const { return ids_->heap(); }
    223 
    224 
    225 }  // namespace internal
    226 }  // namespace v8
    227