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-inl.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 62883 : HeapProfiler::HeapProfiler(Heap* heap)
18 62883 : : ids_(new HeapObjectsMap(heap)),
19 : names_(new StringsStorage()),
20 251532 : is_tracking_object_moves_(false) {}
21 :
22 : HeapProfiler::~HeapProfiler() = default;
23 :
24 70 : void HeapProfiler::DeleteAllSnapshots() {
25 : snapshots_.clear();
26 70 : MaybeClearStringsStorage();
27 70 : }
28 :
29 164 : void HeapProfiler::MaybeClearStringsStorage() {
30 487 : if (snapshots_.empty() && !sampling_heap_profiler_ && !allocation_tracker_) {
31 154 : names_.reset(new StringsStorage());
32 : }
33 164 : }
34 :
35 5 : void HeapProfiler::RemoveSnapshot(HeapSnapshot* snapshot) {
36 : snapshots_.erase(
37 : std::find_if(snapshots_.begin(), snapshots_.end(),
38 : [&](const std::unique_ptr<HeapSnapshot>& entry) {
39 5 : return entry.get() == snapshot;
40 5 : }));
41 5 : }
42 :
43 :
44 0 : void HeapProfiler::DefineWrapperClass(
45 : uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback) {
46 : DCHECK_NE(class_id, v8::HeapProfiler::kPersistentHandleNoClassId);
47 0 : if (wrapper_callbacks_.size() <= class_id) {
48 : wrapper_callbacks_.insert(wrapper_callbacks_.end(),
49 0 : class_id - wrapper_callbacks_.size() + 1,
50 0 : nullptr);
51 : }
52 0 : wrapper_callbacks_[class_id] = callback;
53 0 : }
54 :
55 0 : v8::RetainedObjectInfo* HeapProfiler::ExecuteWrapperClassCallback(
56 : uint16_t class_id, Handle<Object> wrapper) {
57 0 : if (wrapper_callbacks_.size() <= class_id) return nullptr;
58 0 : return wrapper_callbacks_[class_id](class_id, Utils::ToLocal(wrapper));
59 : }
60 :
61 0 : void HeapProfiler::SetGetRetainerInfosCallback(
62 : v8::HeapProfiler::GetRetainerInfosCallback callback) {
63 0 : get_retainer_infos_callback_ = callback;
64 0 : }
65 :
66 364 : v8::HeapProfiler::RetainerInfos HeapProfiler::GetRetainerInfos(
67 : Isolate* isolate) {
68 : v8::HeapProfiler::RetainerInfos infos;
69 364 : if (get_retainer_infos_callback_ != nullptr)
70 0 : infos =
71 : get_retainer_infos_callback_(reinterpret_cast<v8::Isolate*>(isolate));
72 364 : return infos;
73 : }
74 :
75 35 : void HeapProfiler::AddBuildEmbedderGraphCallback(
76 : v8::HeapProfiler::BuildEmbedderGraphCallback callback, void* data) {
77 70 : build_embedder_graph_callbacks_.push_back({callback, data});
78 35 : }
79 :
80 5 : void HeapProfiler::RemoveBuildEmbedderGraphCallback(
81 : v8::HeapProfiler::BuildEmbedderGraphCallback callback, void* data) {
82 : auto it = std::find(build_embedder_graph_callbacks_.begin(),
83 : build_embedder_graph_callbacks_.end(),
84 10 : std::make_pair(callback, data));
85 5 : if (it != build_embedder_graph_callbacks_.end())
86 5 : build_embedder_graph_callbacks_.erase(it);
87 5 : }
88 :
89 35 : void HeapProfiler::BuildEmbedderGraph(Isolate* isolate,
90 : v8::EmbedderGraph* graph) {
91 110 : for (const auto& cb : build_embedder_graph_callbacks_) {
92 40 : cb.first(reinterpret_cast<v8::Isolate*>(isolate), graph, cb.second);
93 : }
94 35 : }
95 :
96 399 : HeapSnapshot* HeapProfiler::TakeSnapshot(
97 : v8::ActivityControl* control,
98 : v8::HeapProfiler::ObjectNameResolver* resolver) {
99 399 : HeapSnapshot* result = new HeapSnapshot(this);
100 : {
101 399 : HeapSnapshotGenerator generator(result, control, resolver, heap());
102 399 : if (!generator.GenerateSnapshot()) {
103 5 : delete result;
104 5 : result = nullptr;
105 : } else {
106 394 : snapshots_.emplace_back(result);
107 399 : }
108 : }
109 399 : ids_->RemoveDeadEntries();
110 399 : is_tracking_object_moves_ = true;
111 :
112 : heap()->isolate()->debug()->feature_tracker()->Track(
113 399 : DebugFeatureTracker::kHeapSnapshot);
114 :
115 399 : return result;
116 : }
117 :
118 59 : bool HeapProfiler::StartSamplingHeapProfiler(
119 : uint64_t sample_interval, int stack_depth,
120 : v8::HeapProfiler::SamplingFlags flags) {
121 59 : if (sampling_heap_profiler_.get()) {
122 : return false;
123 : }
124 : sampling_heap_profiler_.reset(new SamplingHeapProfiler(
125 59 : heap(), names_.get(), sample_interval, stack_depth, flags));
126 : return true;
127 : }
128 :
129 :
130 59 : void HeapProfiler::StopSamplingHeapProfiler() {
131 : sampling_heap_profiler_.reset();
132 59 : MaybeClearStringsStorage();
133 59 : }
134 :
135 :
136 77 : v8::AllocationProfile* HeapProfiler::GetAllocationProfile() {
137 77 : if (sampling_heap_profiler_.get()) {
138 64 : return sampling_heap_profiler_->GetAllocationProfile();
139 : } else {
140 : return nullptr;
141 : }
142 : }
143 :
144 :
145 45 : void HeapProfiler::StartHeapObjectsTracking(bool track_allocations) {
146 45 : ids_->UpdateHeapObjectsMap();
147 45 : is_tracking_object_moves_ = true;
148 : DCHECK(!allocation_tracker_);
149 45 : if (track_allocations) {
150 35 : allocation_tracker_.reset(new AllocationTracker(ids_.get(), names_.get()));
151 70 : heap()->AddHeapObjectAllocationTracker(this);
152 : heap()->isolate()->debug()->feature_tracker()->Track(
153 35 : DebugFeatureTracker::kAllocationTracking);
154 : }
155 45 : }
156 :
157 55 : SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream,
158 : int64_t* timestamp_us) {
159 55 : return ids_->PushHeapObjectsStats(stream, timestamp_us);
160 : }
161 :
162 3879 : void HeapProfiler::StopHeapObjectsTracking() {
163 3879 : ids_->StopHeapObjectsTracking();
164 3879 : if (allocation_tracker_) {
165 : allocation_tracker_.reset();
166 35 : MaybeClearStringsStorage();
167 70 : heap()->RemoveHeapObjectAllocationTracker(this);
168 : }
169 3879 : }
170 :
171 155 : int HeapProfiler::GetSnapshotsCount() {
172 310 : return static_cast<int>(snapshots_.size());
173 : }
174 :
175 30 : HeapSnapshot* HeapProfiler::GetSnapshot(int index) {
176 60 : return snapshots_.at(index).get();
177 : }
178 :
179 155 : SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) {
180 310 : if (!obj->IsHeapObject())
181 : return v8::HeapProfiler::kUnknownObjectId;
182 155 : return ids_->FindEntry(HeapObject::cast(*obj)->address());
183 : }
184 :
185 171205 : void HeapProfiler::ObjectMoveEvent(Address from, Address to, int size) {
186 171205 : base::MutexGuard guard(&profiler_mutex_);
187 171205 : bool known_object = ids_->MoveObject(from, to, size);
188 340409 : if (!known_object && allocation_tracker_) {
189 30770 : allocation_tracker_->address_to_trace()->MoveObject(from, to, size);
190 : }
191 171205 : }
192 :
193 115711 : void HeapProfiler::AllocationEvent(Address addr, int size) {
194 : DisallowHeapAllocation no_allocation;
195 115711 : if (allocation_tracker_) {
196 115711 : allocation_tracker_->AllocationEvent(addr, size);
197 : }
198 115711 : }
199 :
200 :
201 0 : void HeapProfiler::UpdateObjectSizeEvent(Address addr, int size) {
202 0 : ids_->UpdateObjectSize(addr, size);
203 0 : }
204 :
205 140 : Handle<HeapObject> HeapProfiler::FindHeapObjectById(SnapshotObjectId id) {
206 : HeapObject object;
207 140 : HeapIterator iterator(heap(), HeapIterator::kFilterUnreachable);
208 : // Make sure that object with the given id is still reachable.
209 910197 : for (HeapObject obj = iterator.next(); !obj.is_null();
210 : obj = iterator.next()) {
211 910057 : if (ids_->FindEntry(obj->address()) == id) {
212 : DCHECK(object.is_null());
213 : object = obj;
214 : // Can't break -- kFilterUnreachable requires full heap traversal.
215 : }
216 : }
217 : return !object.is_null() ? Handle<HeapObject>(object, isolate())
218 280 : : Handle<HeapObject>();
219 : }
220 :
221 :
222 3839 : void HeapProfiler::ClearHeapObjectMap() {
223 3839 : ids_.reset(new HeapObjectsMap(heap()));
224 3839 : if (!allocation_tracker_) is_tracking_object_moves_ = false;
225 3839 : }
226 :
227 :
228 6620066 : Heap* HeapProfiler::heap() const { return ids_->heap(); }
229 :
230 12018110 : Isolate* HeapProfiler::isolate() const { return heap()->isolate(); }
231 :
232 85 : void HeapProfiler::QueryObjects(Handle<Context> context,
233 : debug::QueryObjectPredicate* predicate,
234 : PersistentValueVector<v8::Object>* objects) {
235 : // We should return accurate information about live objects, so we need to
236 : // collect all garbage first.
237 85 : heap()->CollectAllAvailableGarbage(GarbageCollectionReason::kHeapProfiler);
238 85 : HeapIterator heap_iterator(heap());
239 2330258 : for (HeapObject heap_obj = heap_iterator.next(); !heap_obj.is_null();
240 : heap_obj = heap_iterator.next()) {
241 2633088 : if (!heap_obj->IsJSObject() || heap_obj->IsExternal(isolate())) continue;
242 : v8::Local<v8::Object> v8_obj(
243 302715 : Utils::ToLocal(handle(JSObject::cast(heap_obj), isolate())));
244 302715 : if (!predicate->Filter(v8_obj)) continue;
245 100 : objects->Append(v8_obj);
246 85 : }
247 85 : }
248 :
249 : } // namespace internal
250 183867 : } // namespace v8
|