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