OLD | NEW |
1 // Copyright 2009-2010 the V8 project authors. All rights reserved. | 1 // Copyright 2009-2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 10 matching lines...) Expand all Loading... |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #ifndef V8_HEAP_PROFILER_H_ | 28 #ifndef V8_HEAP_PROFILER_H_ |
29 #define V8_HEAP_PROFILER_H_ | 29 #define V8_HEAP_PROFILER_H_ |
30 | 30 |
31 #include "allocation.h" | |
32 #include "isolate.h" | 31 #include "isolate.h" |
33 #include "zone-inl.h" | |
34 | 32 |
35 namespace v8 { | 33 namespace v8 { |
36 namespace internal { | 34 namespace internal { |
37 | 35 |
38 #ifdef ENABLE_LOGGING_AND_PROFILING | 36 #ifdef ENABLE_LOGGING_AND_PROFILING |
39 | 37 |
40 class HeapSnapshot; | 38 class HeapSnapshot; |
41 class HeapSnapshotsCollection; | 39 class HeapSnapshotsCollection; |
42 | 40 |
43 #define HEAP_PROFILE(heap, call) \ | 41 #define HEAP_PROFILE(heap, call) \ |
(...skipping 30 matching lines...) Expand all Loading... |
74 | 72 |
75 void DefineWrapperClass( | 73 void DefineWrapperClass( |
76 uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback); | 74 uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback); |
77 | 75 |
78 v8::RetainedObjectInfo* ExecuteWrapperClassCallback(uint16_t class_id, | 76 v8::RetainedObjectInfo* ExecuteWrapperClassCallback(uint16_t class_id, |
79 Object** wrapper); | 77 Object** wrapper); |
80 INLINE(bool is_profiling()) { | 78 INLINE(bool is_profiling()) { |
81 return snapshots_->is_tracking_objects(); | 79 return snapshots_->is_tracking_objects(); |
82 } | 80 } |
83 | 81 |
84 // Obsolete interface. | |
85 // Write a single heap sample to the log file. | |
86 static void WriteSample(); | |
87 | |
88 private: | 82 private: |
89 HeapProfiler(); | 83 HeapProfiler(); |
90 ~HeapProfiler(); | 84 ~HeapProfiler(); |
91 HeapSnapshot* TakeSnapshotImpl(const char* name, | 85 HeapSnapshot* TakeSnapshotImpl(const char* name, |
92 int type, | 86 int type, |
93 v8::ActivityControl* control); | 87 v8::ActivityControl* control); |
94 HeapSnapshot* TakeSnapshotImpl(String* name, | 88 HeapSnapshot* TakeSnapshotImpl(String* name, |
95 int type, | 89 int type, |
96 v8::ActivityControl* control); | 90 v8::ActivityControl* control); |
97 void ResetSnapshots(); | 91 void ResetSnapshots(); |
98 | 92 |
99 HeapSnapshotsCollection* snapshots_; | 93 HeapSnapshotsCollection* snapshots_; |
100 unsigned next_snapshot_uid_; | 94 unsigned next_snapshot_uid_; |
101 List<v8::HeapProfiler::WrapperInfoCallback> wrapper_callbacks_; | 95 List<v8::HeapProfiler::WrapperInfoCallback> wrapper_callbacks_; |
102 | 96 |
103 #endif // ENABLE_LOGGING_AND_PROFILING | 97 #endif // ENABLE_LOGGING_AND_PROFILING |
104 }; | 98 }; |
105 | 99 |
106 | |
107 #ifdef ENABLE_LOGGING_AND_PROFILING | |
108 | |
109 // JSObjectsCluster describes a group of JS objects that are | |
110 // considered equivalent in terms of a particular profile. | |
111 class JSObjectsCluster BASE_EMBEDDED { | |
112 public: | |
113 // These special cases are used in retainer profile. | |
114 enum SpecialCase { | |
115 ROOTS = 1, | |
116 GLOBAL_PROPERTY = 2, | |
117 CODE = 3, | |
118 SELF = 100 // This case is used in ClustersCoarser only. | |
119 }; | |
120 | |
121 JSObjectsCluster() : constructor_(NULL), instance_(NULL) {} | |
122 explicit JSObjectsCluster(String* constructor) | |
123 : constructor_(constructor), instance_(NULL) {} | |
124 explicit JSObjectsCluster(SpecialCase special) | |
125 : constructor_(FromSpecialCase(special)), instance_(NULL) {} | |
126 JSObjectsCluster(String* constructor, Object* instance) | |
127 : constructor_(constructor), instance_(instance) {} | |
128 | |
129 static int CompareConstructors(const JSObjectsCluster& a, | |
130 const JSObjectsCluster& b) { | |
131 // Strings are unique, so it is sufficient to compare their pointers. | |
132 return a.constructor_ == b.constructor_ ? 0 | |
133 : (a.constructor_ < b.constructor_ ? -1 : 1); | |
134 } | |
135 static int Compare(const JSObjectsCluster& a, const JSObjectsCluster& b) { | |
136 // Strings are unique, so it is sufficient to compare their pointers. | |
137 const int cons_cmp = CompareConstructors(a, b); | |
138 return cons_cmp == 0 ? | |
139 (a.instance_ == b.instance_ ? 0 : (a.instance_ < b.instance_ ? -1 : 1)) | |
140 : cons_cmp; | |
141 } | |
142 static int Compare(const JSObjectsCluster* a, const JSObjectsCluster* b) { | |
143 return Compare(*a, *b); | |
144 } | |
145 | |
146 bool is_null() const { return constructor_ == NULL; } | |
147 bool can_be_coarsed() const { return instance_ != NULL; } | |
148 String* constructor() const { return constructor_; } | |
149 Object* instance() const { return instance_; } | |
150 | |
151 const char* GetSpecialCaseName() const; | |
152 void Print(StringStream* accumulator) const; | |
153 // Allows null clusters to be printed. | |
154 void DebugPrint(StringStream* accumulator) const; | |
155 | |
156 private: | |
157 static String* FromSpecialCase(SpecialCase special) { | |
158 // We use symbols that are illegal JS identifiers to identify special cases. | |
159 // Their actual value is irrelevant for us. | |
160 switch (special) { | |
161 case ROOTS: return HEAP->result_symbol(); | |
162 case GLOBAL_PROPERTY: return HEAP->catch_var_symbol(); | |
163 case CODE: return HEAP->code_symbol(); | |
164 case SELF: return HEAP->this_symbol(); | |
165 default: | |
166 UNREACHABLE(); | |
167 return NULL; | |
168 } | |
169 } | |
170 | |
171 String* constructor_; | |
172 Object* instance_; | |
173 }; | |
174 | |
175 | |
176 struct JSObjectsClusterTreeConfig { | |
177 typedef JSObjectsCluster Key; | |
178 typedef NumberAndSizeInfo Value; | |
179 static const Key kNoKey; | |
180 static const Value kNoValue; | |
181 static int Compare(const Key& a, const Key& b) { | |
182 return Key::Compare(a, b); | |
183 } | |
184 }; | |
185 typedef ZoneSplayTree<JSObjectsClusterTreeConfig> JSObjectsClusterTree; | |
186 | |
187 | |
188 // ConstructorHeapProfile is responsible for gathering and logging | |
189 // "constructor profile" of JS objects allocated on heap. | |
190 // It is run during garbage collection cycle, thus it doesn't need | |
191 // to use handles. | |
192 class ConstructorHeapProfile BASE_EMBEDDED { | |
193 public: | |
194 ConstructorHeapProfile(); | |
195 virtual ~ConstructorHeapProfile() {} | |
196 void CollectStats(HeapObject* obj); | |
197 void PrintStats(); | |
198 | |
199 template<class Callback> | |
200 void ForEach(Callback* callback) { js_objects_info_tree_.ForEach(callback); } | |
201 // Used by ZoneSplayTree::ForEach. Made virtual to allow overriding in tests. | |
202 virtual void Call(const JSObjectsCluster& cluster, | |
203 const NumberAndSizeInfo& number_and_size); | |
204 | |
205 private: | |
206 ZoneScope zscope_; | |
207 JSObjectsClusterTree js_objects_info_tree_; | |
208 }; | |
209 | |
210 | |
211 // JSObjectsRetainerTree is used to represent retainer graphs using | |
212 // adjacency list form: | |
213 // | |
214 // Cluster -> (Cluster -> NumberAndSizeInfo) | |
215 // | |
216 // Subordinate splay trees are stored by pointer. They are zone-allocated, | |
217 // so it isn't needed to manage their lifetime. | |
218 // | |
219 struct JSObjectsRetainerTreeConfig { | |
220 typedef JSObjectsCluster Key; | |
221 typedef JSObjectsClusterTree* Value; | |
222 static const Key kNoKey; | |
223 static const Value kNoValue; | |
224 static int Compare(const Key& a, const Key& b) { | |
225 return Key::Compare(a, b); | |
226 } | |
227 }; | |
228 typedef ZoneSplayTree<JSObjectsRetainerTreeConfig> JSObjectsRetainerTree; | |
229 | |
230 | |
231 class ClustersCoarser BASE_EMBEDDED { | |
232 public: | |
233 ClustersCoarser(); | |
234 | |
235 // Processes a given retainer graph. | |
236 void Process(JSObjectsRetainerTree* tree); | |
237 | |
238 // Returns an equivalent cluster (can be the cluster itself). | |
239 // If the given cluster doesn't have an equivalent, returns null cluster. | |
240 JSObjectsCluster GetCoarseEquivalent(const JSObjectsCluster& cluster); | |
241 // Returns whether a cluster can be substitued with an equivalent and thus, | |
242 // skipped in some cases. | |
243 bool HasAnEquivalent(const JSObjectsCluster& cluster); | |
244 | |
245 // Used by JSObjectsRetainerTree::ForEach. | |
246 void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree); | |
247 void Call(const JSObjectsCluster& cluster, | |
248 const NumberAndSizeInfo& number_and_size); | |
249 | |
250 private: | |
251 // Stores a list of back references for a cluster. | |
252 struct ClusterBackRefs { | |
253 explicit ClusterBackRefs(const JSObjectsCluster& cluster_); | |
254 ClusterBackRefs(const ClusterBackRefs& src); | |
255 ClusterBackRefs& operator=(const ClusterBackRefs& src); | |
256 | |
257 static int Compare(const ClusterBackRefs& a, const ClusterBackRefs& b); | |
258 void SortRefs() { refs.Sort(JSObjectsCluster::Compare); } | |
259 static void SortRefsIterator(ClusterBackRefs* ref) { ref->SortRefs(); } | |
260 | |
261 JSObjectsCluster cluster; | |
262 ZoneList<JSObjectsCluster> refs; | |
263 }; | |
264 typedef ZoneList<ClusterBackRefs> SimilarityList; | |
265 | |
266 // A tree for storing a list of equivalents for a cluster. | |
267 struct ClusterEqualityConfig { | |
268 typedef JSObjectsCluster Key; | |
269 typedef JSObjectsCluster Value; | |
270 static const Key kNoKey; | |
271 static const Value kNoValue; | |
272 static int Compare(const Key& a, const Key& b) { | |
273 return Key::Compare(a, b); | |
274 } | |
275 }; | |
276 typedef ZoneSplayTree<ClusterEqualityConfig> EqualityTree; | |
277 | |
278 static int ClusterBackRefsCmp(const ClusterBackRefs* a, | |
279 const ClusterBackRefs* b) { | |
280 return ClusterBackRefs::Compare(*a, *b); | |
281 } | |
282 int DoProcess(JSObjectsRetainerTree* tree); | |
283 int FillEqualityTree(); | |
284 | |
285 static const int kInitialBackrefsListCapacity = 2; | |
286 static const int kInitialSimilarityListCapacity = 2000; | |
287 // Number of passes for finding equivalents. Limits the length of paths | |
288 // that can be considered equivalent. | |
289 static const int kMaxPassesCount = 10; | |
290 | |
291 ZoneScope zscope_; | |
292 SimilarityList sim_list_; | |
293 EqualityTree eq_tree_; | |
294 ClusterBackRefs* current_pair_; | |
295 JSObjectsRetainerTree* current_set_; | |
296 const JSObjectsCluster* self_; | |
297 }; | |
298 | |
299 | |
300 // RetainerHeapProfile is responsible for gathering and logging | |
301 // "retainer profile" of JS objects allocated on heap. | |
302 // It is run during garbage collection cycle, thus it doesn't need | |
303 // to use handles. | |
304 class RetainerTreeAggregator; | |
305 | |
306 class RetainerHeapProfile BASE_EMBEDDED { | |
307 public: | |
308 class Printer { | |
309 public: | |
310 virtual ~Printer() {} | |
311 virtual void PrintRetainers(const JSObjectsCluster& cluster, | |
312 const StringStream& retainers) = 0; | |
313 }; | |
314 | |
315 RetainerHeapProfile(); | |
316 ~RetainerHeapProfile(); | |
317 | |
318 RetainerTreeAggregator* aggregator() { return aggregator_; } | |
319 ClustersCoarser* coarser() { return &coarser_; } | |
320 JSObjectsRetainerTree* retainers_tree() { return &retainers_tree_; } | |
321 | |
322 void CollectStats(HeapObject* obj); | |
323 void CoarseAndAggregate(); | |
324 void PrintStats(); | |
325 void DebugPrintStats(Printer* printer); | |
326 void StoreReference(const JSObjectsCluster& cluster, HeapObject* ref); | |
327 | |
328 private: | |
329 ZoneScope zscope_; | |
330 JSObjectsRetainerTree retainers_tree_; | |
331 ClustersCoarser coarser_; | |
332 RetainerTreeAggregator* aggregator_; | |
333 }; | |
334 | |
335 | |
336 class AggregatedHeapSnapshot { | |
337 public: | |
338 AggregatedHeapSnapshot(); | |
339 ~AggregatedHeapSnapshot(); | |
340 | |
341 HistogramInfo* info() { return info_; } | |
342 ConstructorHeapProfile* js_cons_profile() { return &js_cons_profile_; } | |
343 RetainerHeapProfile* js_retainer_profile() { return &js_retainer_profile_; } | |
344 | |
345 private: | |
346 HistogramInfo* info_; | |
347 ConstructorHeapProfile js_cons_profile_; | |
348 RetainerHeapProfile js_retainer_profile_; | |
349 }; | |
350 | |
351 | |
352 class HeapEntriesMap; | |
353 class HeapEntriesAllocator; | |
354 | |
355 class AggregatedHeapSnapshotGenerator { | |
356 public: | |
357 explicit AggregatedHeapSnapshotGenerator(AggregatedHeapSnapshot* snapshot); | |
358 void GenerateSnapshot(); | |
359 void FillHeapSnapshot(HeapSnapshot* snapshot); | |
360 | |
361 static const int kAllStringsType = LAST_TYPE + 1; | |
362 | |
363 private: | |
364 void CalculateStringsStats(); | |
365 void CollectStats(HeapObject* obj); | |
366 template<class Iterator> | |
367 void IterateRetainers( | |
368 HeapEntriesAllocator* allocator, HeapEntriesMap* entries_map); | |
369 | |
370 AggregatedHeapSnapshot* agg_snapshot_; | |
371 }; | |
372 | |
373 | |
374 class ProducerHeapProfile { | |
375 public: | |
376 void Setup(); | |
377 void RecordJSObjectAllocation(Object* obj) { | |
378 if (FLAG_log_producers) DoRecordJSObjectAllocation(obj); | |
379 } | |
380 | |
381 private: | |
382 ProducerHeapProfile() : can_log_(false) { } | |
383 | |
384 void DoRecordJSObjectAllocation(Object* obj); | |
385 Isolate* isolate_; | |
386 bool can_log_; | |
387 | |
388 friend class Isolate; | |
389 | |
390 DISALLOW_COPY_AND_ASSIGN(ProducerHeapProfile); | |
391 }; | |
392 | |
393 #endif // ENABLE_LOGGING_AND_PROFILING | |
394 | |
395 } } // namespace v8::internal | 100 } } // namespace v8::internal |
396 | 101 |
397 #endif // V8_HEAP_PROFILER_H_ | 102 #endif // V8_HEAP_PROFILER_H_ |
OLD | NEW |