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