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 |