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