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