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/heap/heap-inl.h"
10 #include "src/profiler/allocation-tracker.h"
11 #include "src/profiler/heap-snapshot-generator-inl.h"
12 #include "src/profiler/sampling-heap-profiler.h"
13
14 namespace v8 {
15 namespace internal {
16
HeapProfiler(Heap * heap)17 HeapProfiler::HeapProfiler(Heap* heap)
18 : ids_(new HeapObjectsMap(heap)),
19 names_(new StringsStorage(heap)),
20 is_tracking_object_moves_(false),
21 get_retainer_infos_callback_(nullptr) {}
22
DeleteHeapSnapshot(HeapSnapshot ** snapshot_ptr)23 static void DeleteHeapSnapshot(HeapSnapshot** snapshot_ptr) {
24 delete *snapshot_ptr;
25 }
26
27
~HeapProfiler()28 HeapProfiler::~HeapProfiler() {
29 snapshots_.Iterate(DeleteHeapSnapshot);
30 snapshots_.Clear();
31 }
32
33
DeleteAllSnapshots()34 void HeapProfiler::DeleteAllSnapshots() {
35 snapshots_.Iterate(DeleteHeapSnapshot);
36 snapshots_.Clear();
37 names_.reset(new StringsStorage(heap()));
38 }
39
40
RemoveSnapshot(HeapSnapshot * snapshot)41 void HeapProfiler::RemoveSnapshot(HeapSnapshot* snapshot) {
42 snapshots_.RemoveElement(snapshot);
43 }
44
45
DefineWrapperClass(uint16_t class_id,v8::HeapProfiler::WrapperInfoCallback callback)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
ExecuteWrapperClassCallback(uint16_t class_id,Object ** wrapper)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
SetGetRetainerInfosCallback(v8::HeapProfiler::GetRetainerInfosCallback callback)64 void HeapProfiler::SetGetRetainerInfosCallback(
65 v8::HeapProfiler::GetRetainerInfosCallback callback) {
66 get_retainer_infos_callback_ = callback;
67 }
68
GetRetainerInfos(Isolate * isolate)69 v8::HeapProfiler::RetainerInfos HeapProfiler::GetRetainerInfos(
70 Isolate* isolate) {
71 v8::HeapProfiler::RetainerInfos infos;
72 if (get_retainer_infos_callback_ != nullptr)
73 infos =
74 get_retainer_infos_callback_(reinterpret_cast<v8::Isolate*>(isolate));
75 return infos;
76 }
77
TakeSnapshot(v8::ActivityControl * control,v8::HeapProfiler::ObjectNameResolver * resolver)78 HeapSnapshot* HeapProfiler::TakeSnapshot(
79 v8::ActivityControl* control,
80 v8::HeapProfiler::ObjectNameResolver* resolver) {
81 HeapSnapshot* result = new HeapSnapshot(this);
82 {
83 HeapSnapshotGenerator generator(result, control, resolver, heap());
84 if (!generator.GenerateSnapshot()) {
85 delete result;
86 result = NULL;
87 } else {
88 snapshots_.Add(result);
89 }
90 }
91 ids_->RemoveDeadEntries();
92 is_tracking_object_moves_ = true;
93
94 heap()->isolate()->debug()->feature_tracker()->Track(
95 DebugFeatureTracker::kHeapSnapshot);
96
97 return result;
98 }
99
StartSamplingHeapProfiler(uint64_t sample_interval,int stack_depth,v8::HeapProfiler::SamplingFlags flags)100 bool HeapProfiler::StartSamplingHeapProfiler(
101 uint64_t sample_interval, int stack_depth,
102 v8::HeapProfiler::SamplingFlags flags) {
103 if (sampling_heap_profiler_.get()) {
104 return false;
105 }
106 sampling_heap_profiler_.reset(new SamplingHeapProfiler(
107 heap(), names_.get(), sample_interval, stack_depth, flags));
108 return true;
109 }
110
111
StopSamplingHeapProfiler()112 void HeapProfiler::StopSamplingHeapProfiler() {
113 sampling_heap_profiler_.reset();
114 }
115
116
GetAllocationProfile()117 v8::AllocationProfile* HeapProfiler::GetAllocationProfile() {
118 if (sampling_heap_profiler_.get()) {
119 return sampling_heap_profiler_->GetAllocationProfile();
120 } else {
121 return nullptr;
122 }
123 }
124
125
StartHeapObjectsTracking(bool track_allocations)126 void HeapProfiler::StartHeapObjectsTracking(bool track_allocations) {
127 ids_->UpdateHeapObjectsMap();
128 is_tracking_object_moves_ = true;
129 DCHECK(!is_tracking_allocations());
130 if (track_allocations) {
131 allocation_tracker_.reset(new AllocationTracker(ids_.get(), names_.get()));
132 heap()->DisableInlineAllocation();
133 heap()->isolate()->debug()->feature_tracker()->Track(
134 DebugFeatureTracker::kAllocationTracking);
135 }
136 }
137
138
PushHeapObjectsStats(OutputStream * stream,int64_t * timestamp_us)139 SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream,
140 int64_t* timestamp_us) {
141 return ids_->PushHeapObjectsStats(stream, timestamp_us);
142 }
143
144
StopHeapObjectsTracking()145 void HeapProfiler::StopHeapObjectsTracking() {
146 ids_->StopHeapObjectsTracking();
147 if (is_tracking_allocations()) {
148 allocation_tracker_.reset();
149 heap()->EnableInlineAllocation();
150 }
151 }
152
153
GetMemorySizeUsedByProfiler()154 size_t HeapProfiler::GetMemorySizeUsedByProfiler() {
155 size_t size = sizeof(*this);
156 size += names_->GetUsedMemorySize();
157 size += ids_->GetUsedMemorySize();
158 size += GetMemoryUsedByList(snapshots_);
159 for (int i = 0; i < snapshots_.length(); ++i) {
160 size += snapshots_[i]->RawSnapshotSize();
161 }
162 return size;
163 }
164
165
GetSnapshotsCount()166 int HeapProfiler::GetSnapshotsCount() {
167 return snapshots_.length();
168 }
169
170
GetSnapshot(int index)171 HeapSnapshot* HeapProfiler::GetSnapshot(int index) {
172 return snapshots_.at(index);
173 }
174
175
GetSnapshotObjectId(Handle<Object> obj)176 SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) {
177 if (!obj->IsHeapObject())
178 return v8::HeapProfiler::kUnknownObjectId;
179 return ids_->FindEntry(HeapObject::cast(*obj)->address());
180 }
181
182
ObjectMoveEvent(Address from,Address to,int size)183 void HeapProfiler::ObjectMoveEvent(Address from, Address to, int size) {
184 base::LockGuard<base::Mutex> guard(&profiler_mutex_);
185 bool known_object = ids_->MoveObject(from, to, size);
186 if (!known_object && allocation_tracker_) {
187 allocation_tracker_->address_to_trace()->MoveObject(from, to, size);
188 }
189 }
190
191
AllocationEvent(Address addr,int size)192 void HeapProfiler::AllocationEvent(Address addr, int size) {
193 DisallowHeapAllocation no_allocation;
194 if (allocation_tracker_) {
195 allocation_tracker_->AllocationEvent(addr, size);
196 }
197 }
198
199
UpdateObjectSizeEvent(Address addr,int size)200 void HeapProfiler::UpdateObjectSizeEvent(Address addr, int size) {
201 ids_->UpdateObjectSize(addr, size);
202 }
203
204
SetRetainedObjectInfo(UniqueId id,RetainedObjectInfo * info)205 void HeapProfiler::SetRetainedObjectInfo(UniqueId id,
206 RetainedObjectInfo* info) {
207 // TODO(yurus, marja): Don't route this information through GlobalHandles.
208 heap()->isolate()->global_handles()->SetRetainedObjectInfo(id, info);
209 }
210
211
FindHeapObjectById(SnapshotObjectId id)212 Handle<HeapObject> HeapProfiler::FindHeapObjectById(SnapshotObjectId id) {
213 HeapObject* object = NULL;
214 HeapIterator iterator(heap(), HeapIterator::kFilterUnreachable);
215 // Make sure that object with the given id is still reachable.
216 for (HeapObject* obj = iterator.next();
217 obj != NULL;
218 obj = iterator.next()) {
219 if (ids_->FindEntry(obj->address()) == id) {
220 DCHECK(object == NULL);
221 object = obj;
222 // Can't break -- kFilterUnreachable requires full heap traversal.
223 }
224 }
225 return object != NULL ? Handle<HeapObject>(object) : Handle<HeapObject>();
226 }
227
228
ClearHeapObjectMap()229 void HeapProfiler::ClearHeapObjectMap() {
230 ids_.reset(new HeapObjectsMap(heap()));
231 if (!is_tracking_allocations()) is_tracking_object_moves_ = false;
232 }
233
234
heap() const235 Heap* HeapProfiler::heap() const { return ids_->heap(); }
236
237
238 } // namespace internal
239 } // namespace v8
240