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 13namespace v8 { 14namespace internal { 15 16HeapProfiler::HeapProfiler(Heap* heap) 17 : ids_(new HeapObjectsMap(heap)), 18 names_(new StringsStorage(heap)), 19 is_tracking_object_moves_(false) { 20} 21 22 23static void DeleteHeapSnapshot(HeapSnapshot** snapshot_ptr) { 24 delete *snapshot_ptr; 25} 26 27 28HeapProfiler::~HeapProfiler() { 29 snapshots_.Iterate(DeleteHeapSnapshot); 30 snapshots_.Clear(); 31} 32 33 34void HeapProfiler::DeleteAllSnapshots() { 35 snapshots_.Iterate(DeleteHeapSnapshot); 36 snapshots_.Clear(); 37 names_.Reset(new StringsStorage(heap())); 38} 39 40 41void HeapProfiler::RemoveSnapshot(HeapSnapshot* snapshot) { 42 snapshots_.RemoveElement(snapshot); 43} 44 45 46void 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 57v8::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 65HeapSnapshot* 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 87bool 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 99void HeapProfiler::StopSamplingHeapProfiler() { 100 sampling_heap_profiler_.Reset(nullptr); 101} 102 103 104v8::AllocationProfile* HeapProfiler::GetAllocationProfile() { 105 if (sampling_heap_profiler_.get()) { 106 return sampling_heap_profiler_->GetAllocationProfile(); 107 } else { 108 return nullptr; 109 } 110} 111 112 113void 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 126SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream, 127 int64_t* timestamp_us) { 128 return ids_->PushHeapObjectsStats(stream, timestamp_us); 129} 130 131 132void HeapProfiler::StopHeapObjectsTracking() { 133 ids_->StopHeapObjectsTracking(); 134 if (is_tracking_allocations()) { 135 allocation_tracker_.Reset(NULL); 136 heap()->EnableInlineAllocation(); 137 } 138} 139 140 141size_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 153int HeapProfiler::GetSnapshotsCount() { 154 return snapshots_.length(); 155} 156 157 158HeapSnapshot* HeapProfiler::GetSnapshot(int index) { 159 return snapshots_.at(index); 160} 161 162 163SnapshotObjectId 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 170void 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 179void 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 187void HeapProfiler::UpdateObjectSizeEvent(Address addr, int size) { 188 ids_->UpdateObjectSize(addr, size); 189} 190 191 192void 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 199Handle<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 216void HeapProfiler::ClearHeapObjectMap() { 217 ids_.Reset(new HeapObjectsMap(heap())); 218 if (!is_tracking_allocations()) is_tracking_object_moves_ = false; 219} 220 221 222Heap* HeapProfiler::heap() const { return ids_->heap(); } 223 224 225} // namespace internal 226} // namespace v8 227