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 54999 : HeapProfiler::HeapProfiler(Heap* heap)
18 54999 : : ids_(new HeapObjectsMap(heap)),
19 54999 : names_(new StringsStorage(heap)),
20 : is_tracking_object_moves_(false),
21 164997 : get_retainer_infos_callback_(nullptr) {}
22 :
23 309 : static void DeleteHeapSnapshot(HeapSnapshot* snapshot_ptr) {
24 309 : delete snapshot_ptr;
25 309 : }
26 :
27 :
28 106730 : HeapProfiler::~HeapProfiler() {
29 : std::for_each(snapshots_.begin(), snapshots_.end(), &DeleteHeapSnapshot);
30 53365 : }
31 :
32 :
33 55 : void HeapProfiler::DeleteAllSnapshots() {
34 : std::for_each(snapshots_.begin(), snapshots_.end(), &DeleteHeapSnapshot);
35 : snapshots_.clear();
36 55 : names_.reset(new StringsStorage(heap()));
37 55 : }
38 :
39 :
40 5 : void HeapProfiler::RemoveSnapshot(HeapSnapshot* snapshot) {
41 5 : snapshots_.erase(std::find(snapshots_.begin(), snapshots_.end(), snapshot));
42 5 : }
43 :
44 :
45 10 : void HeapProfiler::DefineWrapperClass(
46 : uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback) {
47 : DCHECK_NE(class_id, v8::HeapProfiler::kPersistentHandleNoClassId);
48 30 : if (wrapper_callbacks_.size() <= class_id) {
49 : wrapper_callbacks_.insert(wrapper_callbacks_.end(),
50 10 : class_id - wrapper_callbacks_.size() + 1,
51 30 : nullptr);
52 : }
53 10 : wrapper_callbacks_[class_id] = callback;
54 10 : }
55 :
56 :
57 15 : v8::RetainedObjectInfo* HeapProfiler::ExecuteWrapperClassCallback(
58 : uint16_t class_id, Object** wrapper) {
59 30 : if (wrapper_callbacks_.size() <= class_id) return nullptr;
60 : return wrapper_callbacks_[class_id](
61 15 : 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 319 : v8::HeapProfiler::RetainerInfos HeapProfiler::GetRetainerInfos(
70 : Isolate* isolate) {
71 : v8::HeapProfiler::RetainerInfos infos;
72 319 : if (get_retainer_infos_callback_ != nullptr)
73 0 : infos =
74 : get_retainer_infos_callback_(reinterpret_cast<v8::Isolate*>(isolate));
75 319 : return infos;
76 : }
77 :
78 319 : HeapSnapshot* HeapProfiler::TakeSnapshot(
79 : v8::ActivityControl* control,
80 : v8::HeapProfiler::ObjectNameResolver* resolver) {
81 319 : HeapSnapshot* result = new HeapSnapshot(this);
82 : {
83 319 : HeapSnapshotGenerator generator(result, control, resolver, heap());
84 319 : if (!generator.GenerateSnapshot()) {
85 5 : delete result;
86 5 : result = nullptr;
87 : } else {
88 314 : snapshots_.push_back(result);
89 319 : }
90 : }
91 319 : ids_->RemoveDeadEntries();
92 319 : is_tracking_object_moves_ = true;
93 :
94 : heap()->isolate()->debug()->feature_tracker()->Track(
95 319 : DebugFeatureTracker::kHeapSnapshot);
96 :
97 319 : return result;
98 : }
99 :
100 28 : bool HeapProfiler::StartSamplingHeapProfiler(
101 : uint64_t sample_interval, int stack_depth,
102 : v8::HeapProfiler::SamplingFlags flags) {
103 28 : if (sampling_heap_profiler_.get()) {
104 : return false;
105 : }
106 : sampling_heap_profiler_.reset(new SamplingHeapProfiler(
107 28 : heap(), names_.get(), sample_interval, stack_depth, flags));
108 : return true;
109 : }
110 :
111 :
112 28 : void HeapProfiler::StopSamplingHeapProfiler() {
113 : sampling_heap_profiler_.reset();
114 28 : }
115 :
116 :
117 31 : v8::AllocationProfile* HeapProfiler::GetAllocationProfile() {
118 31 : if (sampling_heap_profiler_.get()) {
119 23 : return sampling_heap_profiler_->GetAllocationProfile();
120 : } else {
121 : return nullptr;
122 : }
123 : }
124 :
125 :
126 40 : void HeapProfiler::StartHeapObjectsTracking(bool track_allocations) {
127 40 : ids_->UpdateHeapObjectsMap();
128 40 : is_tracking_object_moves_ = true;
129 : DCHECK(!is_tracking_allocations());
130 40 : if (track_allocations) {
131 30 : allocation_tracker_.reset(new AllocationTracker(ids_.get(), names_.get()));
132 30 : heap()->DisableInlineAllocation();
133 : heap()->isolate()->debug()->feature_tracker()->Track(
134 30 : DebugFeatureTracker::kAllocationTracking);
135 : }
136 40 : }
137 :
138 55 : SnapshotObjectId HeapProfiler::PushHeapObjectsStats(OutputStream* stream,
139 : int64_t* timestamp_us) {
140 55 : return ids_->PushHeapObjectsStats(stream, timestamp_us);
141 : }
142 :
143 3446 : void HeapProfiler::StopHeapObjectsTracking() {
144 3446 : ids_->StopHeapObjectsTracking();
145 3446 : if (is_tracking_allocations()) {
146 : allocation_tracker_.reset();
147 30 : heap()->EnableInlineAllocation();
148 : }
149 3446 : }
150 :
151 150 : int HeapProfiler::GetSnapshotsCount() {
152 300 : return static_cast<int>(snapshots_.size());
153 : }
154 :
155 30 : HeapSnapshot* HeapProfiler::GetSnapshot(int index) {
156 60 : return snapshots_.at(index);
157 : }
158 :
159 155 : SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) {
160 155 : if (!obj->IsHeapObject())
161 : return v8::HeapProfiler::kUnknownObjectId;
162 310 : return ids_->FindEntry(HeapObject::cast(*obj)->address());
163 : }
164 :
165 103772 : void HeapProfiler::ObjectMoveEvent(Address from, Address to, int size) {
166 103772 : base::LockGuard<base::Mutex> guard(&profiler_mutex_);
167 103772 : bool known_object = ids_->MoveObject(from, to, size);
168 205869 : if (!known_object && allocation_tracker_) {
169 0 : allocation_tracker_->address_to_trace()->MoveObject(from, to, size);
170 : }
171 103772 : }
172 :
173 13279 : void HeapProfiler::AllocationEvent(Address addr, int size) {
174 : DisallowHeapAllocation no_allocation;
175 13279 : if (allocation_tracker_) {
176 13279 : allocation_tracker_->AllocationEvent(addr, size);
177 : }
178 13279 : }
179 :
180 :
181 0 : void HeapProfiler::UpdateObjectSizeEvent(Address addr, int size) {
182 0 : ids_->UpdateObjectSize(addr, size);
183 0 : }
184 :
185 140 : Handle<HeapObject> HeapProfiler::FindHeapObjectById(SnapshotObjectId id) {
186 : HeapObject* object = nullptr;
187 140 : HeapIterator iterator(heap(), HeapIterator::kFilterUnreachable);
188 : // Make sure that object with the given id is still reachable.
189 1083298 : for (HeapObject* obj = iterator.next(); obj != nullptr;
190 : obj = iterator.next()) {
191 2166316 : if (ids_->FindEntry(obj->address()) == id) {
192 : DCHECK_NULL(object);
193 : object = obj;
194 : // Can't break -- kFilterUnreachable requires full heap traversal.
195 : }
196 : }
197 280 : return object != nullptr ? Handle<HeapObject>(object) : Handle<HeapObject>();
198 : }
199 :
200 :
201 3411 : void HeapProfiler::ClearHeapObjectMap() {
202 3411 : ids_.reset(new HeapObjectsMap(heap()));
203 3411 : if (!is_tracking_allocations()) is_tracking_object_moves_ = false;
204 3411 : }
205 :
206 :
207 12022351 : Heap* HeapProfiler::heap() const { return ids_->heap(); }
208 :
209 65 : void HeapProfiler::QueryObjects(Handle<Context> context,
210 : debug::QueryObjectPredicate* predicate,
211 : PersistentValueVector<v8::Object>* objects) {
212 : // We should return accurate information about live objects, so we need to
213 : // collect all garbage first.
214 : heap()->CollectAllAvailableGarbage(
215 65 : GarbageCollectionReason::kLowMemoryNotification);
216 : heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
217 65 : GarbageCollectionReason::kHeapProfiler);
218 65 : HeapIterator heap_iterator(heap());
219 : HeapObject* heap_obj;
220 1000113 : while ((heap_obj = heap_iterator.next()) != nullptr) {
221 2221831 : if (!heap_obj->IsJSObject() || heap_obj->IsExternal()) continue;
222 : v8::Local<v8::Object> v8_obj(
223 221575 : Utils::ToLocal(handle(JSObject::cast(heap_obj))));
224 221575 : if (!predicate->Filter(v8_obj)) continue;
225 85 : objects->Append(v8_obj);
226 65 : }
227 65 : }
228 :
229 : } // namespace internal
230 : } // namespace v8
|