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