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 62442 : HeapProfiler::HeapProfiler(Heap* heap)
18 62442 : : ids_(new HeapObjectsMap(heap)),
19 : names_(new StringsStorage()),
20 249768 : 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 35 : void HeapProfiler::AddBuildEmbedderGraphCallback(
44 : v8::HeapProfiler::BuildEmbedderGraphCallback callback, void* data) {
45 70 : build_embedder_graph_callbacks_.push_back({callback, data});
46 35 : }
47 :
48 5 : void HeapProfiler::RemoveBuildEmbedderGraphCallback(
49 : v8::HeapProfiler::BuildEmbedderGraphCallback callback, void* data) {
50 : auto it = std::find(build_embedder_graph_callbacks_.begin(),
51 : build_embedder_graph_callbacks_.end(),
52 10 : std::make_pair(callback, data));
53 5 : if (it != build_embedder_graph_callbacks_.end())
54 : build_embedder_graph_callbacks_.erase(it);
55 5 : }
56 :
57 35 : void HeapProfiler::BuildEmbedderGraph(Isolate* isolate,
58 : v8::EmbedderGraph* graph) {
59 75 : for (const auto& cb : build_embedder_graph_callbacks_) {
60 40 : cb.first(reinterpret_cast<v8::Isolate*>(isolate), graph, cb.second);
61 : }
62 35 : }
63 :
64 398 : HeapSnapshot* HeapProfiler::TakeSnapshot(
65 : v8::ActivityControl* control,
66 : v8::HeapProfiler::ObjectNameResolver* resolver) {
67 398 : HeapSnapshot* result = new HeapSnapshot(this);
68 : {
69 796 : HeapSnapshotGenerator generator(result, control, resolver, heap());
70 398 : if (!generator.GenerateSnapshot()) {
71 5 : delete result;
72 5 : result = nullptr;
73 : } else {
74 393 : snapshots_.emplace_back(result);
75 : }
76 : }
77 398 : ids_->RemoveDeadEntries();
78 398 : is_tracking_object_moves_ = true;
79 :
80 : heap()->isolate()->debug()->feature_tracker()->Track(
81 398 : DebugFeatureTracker::kHeapSnapshot);
82 :
83 398 : return result;
84 : }
85 :
86 59 : bool HeapProfiler::StartSamplingHeapProfiler(
87 : uint64_t sample_interval, int stack_depth,
88 : v8::HeapProfiler::SamplingFlags flags) {
89 59 : if (sampling_heap_profiler_.get()) {
90 : return false;
91 : }
92 118 : sampling_heap_profiler_.reset(new SamplingHeapProfiler(
93 118 : heap(), names_.get(), sample_interval, stack_depth, flags));
94 59 : return true;
95 : }
96 :
97 :
98 59 : void HeapProfiler::StopSamplingHeapProfiler() {
99 59 : sampling_heap_profiler_.reset();
100 59 : MaybeClearStringsStorage();
101 59 : }
102 :
103 :
104 77 : v8::AllocationProfile* HeapProfiler::GetAllocationProfile() {
105 77 : if (sampling_heap_profiler_.get()) {
106 64 : return sampling_heap_profiler_->GetAllocationProfile();
107 : } else {
108 : return nullptr;
109 : }
110 : }
111 :
112 :
113 45 : void HeapProfiler::StartHeapObjectsTracking(bool track_allocations) {
114 45 : ids_->UpdateHeapObjectsMap();
115 45 : is_tracking_object_moves_ = true;
116 : DCHECK(!allocation_tracker_);
117 45 : if (track_allocations) {
118 35 : allocation_tracker_.reset(new AllocationTracker(ids_.get(), names_.get()));
119 70 : heap()->AddHeapObjectAllocationTracker(this);
120 : heap()->isolate()->debug()->feature_tracker()->Track(
121 35 : DebugFeatureTracker::kAllocationTracking);
122 : }
123 45 : }
124 :
125 55 : SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream,
126 : int64_t* timestamp_us) {
127 55 : return ids_->PushHeapObjectsStats(stream, timestamp_us);
128 : }
129 :
130 3924 : void HeapProfiler::StopHeapObjectsTracking() {
131 3924 : ids_->StopHeapObjectsTracking();
132 3924 : if (allocation_tracker_) {
133 35 : allocation_tracker_.reset();
134 35 : MaybeClearStringsStorage();
135 70 : heap()->RemoveHeapObjectAllocationTracker(this);
136 : }
137 3924 : }
138 :
139 155 : int HeapProfiler::GetSnapshotsCount() {
140 155 : return static_cast<int>(snapshots_.size());
141 : }
142 :
143 30 : HeapSnapshot* HeapProfiler::GetSnapshot(int index) {
144 60 : return snapshots_.at(index).get();
145 : }
146 :
147 155 : SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) {
148 155 : if (!obj->IsHeapObject())
149 : return v8::HeapProfiler::kUnknownObjectId;
150 155 : return ids_->FindEntry(HeapObject::cast(*obj)->address());
151 : }
152 :
153 128379 : void HeapProfiler::ObjectMoveEvent(Address from, Address to, int size) {
154 128379 : base::MutexGuard guard(&profiler_mutex_);
155 128397 : bool known_object = ids_->MoveObject(from, to, size);
156 255029 : if (!known_object && allocation_tracker_) {
157 35222 : allocation_tracker_->address_to_trace()->MoveObject(from, to, size);
158 : }
159 128395 : }
160 :
161 115590 : void HeapProfiler::AllocationEvent(Address addr, int size) {
162 : DisallowHeapAllocation no_allocation;
163 115590 : if (allocation_tracker_) {
164 115590 : allocation_tracker_->AllocationEvent(addr, size);
165 : }
166 115590 : }
167 :
168 :
169 0 : void HeapProfiler::UpdateObjectSizeEvent(Address addr, int size) {
170 0 : ids_->UpdateObjectSize(addr, size);
171 0 : }
172 :
173 140 : Handle<HeapObject> HeapProfiler::FindHeapObjectById(SnapshotObjectId id) {
174 : HeapObject object;
175 280 : HeapIterator iterator(heap(), HeapIterator::kFilterUnreachable);
176 : // Make sure that object with the given id is still reachable.
177 919868 : for (HeapObject obj = iterator.next(); !obj.is_null();
178 : obj = iterator.next()) {
179 919728 : if (ids_->FindEntry(obj->address()) == id) {
180 : DCHECK(object.is_null());
181 : object = obj;
182 : // Can't break -- kFilterUnreachable requires full heap traversal.
183 : }
184 : }
185 : return !object.is_null() ? Handle<HeapObject>(object, isolate())
186 280 : : Handle<HeapObject>();
187 : }
188 :
189 :
190 3884 : void HeapProfiler::ClearHeapObjectMap() {
191 3884 : ids_.reset(new HeapObjectsMap(heap()));
192 3884 : if (!allocation_tracker_) is_tracking_object_moves_ = false;
193 3884 : }
194 :
195 :
196 0 : Heap* HeapProfiler::heap() const { return ids_->heap(); }
197 :
198 12011002 : Isolate* HeapProfiler::isolate() const { return heap()->isolate(); }
199 :
200 85 : void HeapProfiler::QueryObjects(Handle<Context> context,
201 : debug::QueryObjectPredicate* predicate,
202 : PersistentValueVector<v8::Object>* objects) {
203 : // We should return accurate information about live objects, so we need to
204 : // collect all garbage first.
205 85 : heap()->CollectAllAvailableGarbage(GarbageCollectionReason::kHeapProfiler);
206 170 : HeapIterator heap_iterator(heap());
207 2362626 : for (HeapObject heap_obj = heap_iterator.next(); !heap_obj.is_null();
208 : heap_obj = heap_iterator.next()) {
209 2667458 : if (!heap_obj->IsJSObject() || heap_obj->IsExternal(isolate())) continue;
210 : v8::Local<v8::Object> v8_obj(
211 304717 : Utils::ToLocal(handle(JSObject::cast(heap_obj), isolate())));
212 304717 : if (!predicate->Filter(v8_obj)) continue;
213 100 : objects->Append(v8_obj);
214 : }
215 85 : }
216 :
217 : } // namespace internal
218 122036 : } // namespace v8
|