Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(230)

Side by Side Diff: src/heap-profiler.cc

Issue 209028: Heap profiler: count the number of back references for objects. (Closed)
Patch Set: Comments addressed Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/heap-profiler.h ('k') | src/log.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 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 19 matching lines...) Expand all
30 #include "heap-profiler.h" 30 #include "heap-profiler.h"
31 #include "string-stream.h" 31 #include "string-stream.h"
32 32
33 namespace v8 { 33 namespace v8 {
34 namespace internal { 34 namespace internal {
35 35
36 36
37 #ifdef ENABLE_LOGGING_AND_PROFILING 37 #ifdef ENABLE_LOGGING_AND_PROFILING
38 namespace { 38 namespace {
39 39
40 // JSStatsHelper provides service functions for examining 40 // Clusterizer is a set of helper functions for converting
41 // JS objects allocated on heap. It is run during garbage 41 // object references into clusters.
42 // collection cycle, thus it doesn't need to use handles. 42 class Clusterizer : public AllStatic {
43 class JSStatsHelper {
44 public: 43 public:
44 static JSObjectsCluster Clusterize(HeapObject* obj) {
45 return Clusterize(obj, true);
46 }
47 static void InsertIntoTree(JSObjectsClusterTree* tree,
48 HeapObject* obj, bool fine_grain);
49 static void InsertReferenceIntoTree(JSObjectsClusterTree* tree,
50 const JSObjectsCluster& cluster) {
51 InsertIntoTree(tree, cluster, 0);
52 }
53
54 private:
55 static JSObjectsCluster Clusterize(HeapObject* obj, bool fine_grain);
45 static int CalculateNetworkSize(JSObject* obj); 56 static int CalculateNetworkSize(JSObject* obj);
46 private: 57 static int GetObjectSize(HeapObject* obj) {
47 DISALLOW_IMPLICIT_CONSTRUCTORS(JSStatsHelper); 58 return obj->IsJSObject() ?
59 CalculateNetworkSize(JSObject::cast(obj)) : obj->Size();
60 }
61 static void InsertIntoTree(JSObjectsClusterTree* tree,
62 const JSObjectsCluster& cluster, int size);
48 }; 63 };
49 64
50 65
51 int JSStatsHelper::CalculateNetworkSize(JSObject* obj) { 66 JSObjectsCluster Clusterizer::Clusterize(HeapObject* obj, bool fine_grain) {
67 if (obj->IsJSObject()) {
68 JSObject* js_obj = JSObject::cast(obj);
69 String* constructor = JSObject::cast(js_obj)->constructor_name();
70 // Differentiate Object and Array instances.
71 if (fine_grain && (constructor == Heap::Object_symbol() ||
72 constructor == Heap::Array_symbol())) {
73 return JSObjectsCluster(constructor, obj);
74 } else {
75 return JSObjectsCluster(constructor);
76 }
77 } else if (obj->IsString()) {
78 return JSObjectsCluster(Heap::String_symbol());
79 }
80 return JSObjectsCluster();
81 }
82
83
84 void Clusterizer::InsertIntoTree(JSObjectsClusterTree* tree,
85 HeapObject* obj, bool fine_grain) {
86 JSObjectsCluster cluster = Clusterize(obj, fine_grain);
87 if (cluster.is_null()) return;
88 InsertIntoTree(tree, cluster, GetObjectSize(obj));
89 }
90
91
92 void Clusterizer::InsertIntoTree(JSObjectsClusterTree* tree,
93 const JSObjectsCluster& cluster, int size) {
94 JSObjectsClusterTree::Locator loc;
95 tree->Insert(cluster, &loc);
96 NumberAndSizeInfo number_and_size = loc.value();
97 number_and_size.increment_number(1);
98 number_and_size.increment_bytes(size);
99 loc.set_value(number_and_size);
100 }
101
102
103 int Clusterizer::CalculateNetworkSize(JSObject* obj) {
52 int size = obj->Size(); 104 int size = obj->Size();
53 // If 'properties' and 'elements' are non-empty (thus, non-shared), 105 // If 'properties' and 'elements' are non-empty (thus, non-shared),
54 // take their size into account. 106 // take their size into account.
55 if (FixedArray::cast(obj->properties())->length() != 0) { 107 if (FixedArray::cast(obj->properties())->length() != 0) {
56 size += obj->properties()->Size(); 108 size += obj->properties()->Size();
57 } 109 }
58 if (FixedArray::cast(obj->elements())->length() != 0) { 110 if (FixedArray::cast(obj->elements())->length() != 0) {
59 size += obj->elements()->Size(); 111 size += obj->elements()->Size();
60 } 112 }
61 return size; 113 return size;
62 } 114 }
63 115
64 116
65 // A helper class for recording back references. 117 // A helper class for recording back references.
66 class ReferencesExtractor : public ObjectVisitor { 118 class ReferencesExtractor : public ObjectVisitor {
67 public: 119 public:
68 ReferencesExtractor( 120 ReferencesExtractor(const JSObjectsCluster& cluster,
69 const JSObjectsCluster& cluster, RetainerHeapProfile* profile) 121 RetainerHeapProfile* profile)
70 : cluster_(cluster), 122 : cluster_(cluster),
71 profile_(profile), 123 profile_(profile),
72 inside_array_(false) { 124 inside_array_(false) {
73 } 125 }
74 126
75 void VisitPointer(Object** o) { 127 void VisitPointer(Object** o) {
76 if ((*o)->IsJSObject() || (*o)->IsString()) { 128 if ((*o)->IsJSObject() || (*o)->IsString()) {
77 profile_->StoreReference(cluster_, *o); 129 profile_->StoreReference(cluster_, HeapObject::cast(*o));
78 } else if ((*o)->IsFixedArray() && !inside_array_) { 130 } else if ((*o)->IsFixedArray() && !inside_array_) {
79 // Traverse one level deep for data members that are fixed arrays. 131 // Traverse one level deep for data members that are fixed arrays.
80 // This covers the case of 'elements' and 'properties' of JSObject, 132 // This covers the case of 'elements' and 'properties' of JSObject,
81 // and function contexts. 133 // and function contexts.
82 inside_array_ = true; 134 inside_array_ = true;
83 FixedArray::cast(*o)->Iterate(this); 135 FixedArray::cast(*o)->Iterate(this);
84 inside_array_ = false; 136 inside_array_ = false;
85 } 137 }
86 } 138 }
87 139
88 void VisitPointers(Object** start, Object** end) { 140 void VisitPointers(Object** start, Object** end) {
89 for (Object** p = start; p < end; p++) VisitPointer(p); 141 for (Object** p = start; p < end; p++) VisitPointer(p);
90 } 142 }
91 143
92 private: 144 private:
93 const JSObjectsCluster& cluster_; 145 const JSObjectsCluster& cluster_;
94 RetainerHeapProfile* profile_; 146 RetainerHeapProfile* profile_;
95 bool inside_array_; 147 bool inside_array_;
96 }; 148 };
97 149
98 150
99 // A printer interface implementation for the Retainers profile. 151 // A printer interface implementation for the Retainers profile.
100 class RetainersPrinter : public RetainerHeapProfile::Printer { 152 class RetainersPrinter : public RetainerHeapProfile::Printer {
101 public: 153 public:
102 void PrintRetainers(const StringStream& retainers) { 154 void PrintRetainers(const JSObjectsCluster& cluster,
103 LOG(HeapSampleJSRetainersEvent(*(retainers.ToCString()))); 155 const StringStream& retainers) {
156 HeapStringAllocator allocator;
157 StringStream stream(&allocator);
158 cluster.Print(&stream);
159 LOG(HeapSampleJSRetainersEvent(
160 *(stream.ToCString()), *(retainers.ToCString())));
104 } 161 }
105 }; 162 };
106 163
164
165 class RetainerTreePrinter BASE_EMBEDDED {
166 public:
167 explicit RetainerTreePrinter(StringStream* stream) : stream_(stream) {}
168 void Call(const JSObjectsCluster& cluster,
169 const NumberAndSizeInfo& number_and_size) {
170 Print(stream_, cluster, number_and_size);
171 }
172 static void Print(StringStream* stream,
173 const JSObjectsCluster& cluster,
174 const NumberAndSizeInfo& numNNber_and_size);
175
176 private:
177 StringStream* stream_;
178 };
179
180
181 void RetainerTreePrinter::Print(StringStream* stream,
182 const JSObjectsCluster& cluster,
183 const NumberAndSizeInfo& number_and_size) {
184 stream->Put(',');
185 cluster.Print(stream);
186 stream->Add(";%d", number_and_size.number());
187 }
188
189
107 } // namespace 190 } // namespace
108 191
109 192
110 const ConstructorHeapProfile::TreeConfig::Key 193 const JSObjectsClusterTreeConfig::Key JSObjectsClusterTreeConfig::kNoKey;
111 ConstructorHeapProfile::TreeConfig::kNoKey = NULL; 194 const JSObjectsClusterTreeConfig::Value JSObjectsClusterTreeConfig::kNoValue;
112 const ConstructorHeapProfile::TreeConfig::Value
113 ConstructorHeapProfile::TreeConfig::kNoValue;
114 195
115 196
116 ConstructorHeapProfile::ConstructorHeapProfile() 197 ConstructorHeapProfile::ConstructorHeapProfile()
117 : zscope_(DELETE_ON_EXIT) { 198 : zscope_(DELETE_ON_EXIT) {
118 } 199 }
119 200
120 201
121 void ConstructorHeapProfile::Call(String* name, 202 void ConstructorHeapProfile::Call(const JSObjectsCluster& cluster,
122 const NumberAndSizeInfo& number_and_size) { 203 const NumberAndSizeInfo& number_and_size) {
123 ASSERT(name != NULL); 204 HeapStringAllocator allocator;
124 SmartPointer<char> s_name( 205 StringStream stream(&allocator);
125 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)); 206 cluster.Print(&stream);
126 LOG(HeapSampleJSConstructorEvent(*s_name, 207 LOG(HeapSampleJSConstructorEvent(*(stream.ToCString()),
127 number_and_size.number(), 208 number_and_size.number(),
128 number_and_size.bytes())); 209 number_and_size.bytes()));
129 } 210 }
130 211
131 212
132 void ConstructorHeapProfile::CollectStats(HeapObject* obj) { 213 void ConstructorHeapProfile::CollectStats(HeapObject* obj) {
133 String* constructor = NULL; 214 Clusterizer::InsertIntoTree(&js_objects_info_tree_, obj, false);
134 int size;
135 if (obj->IsString()) {
136 constructor = Heap::String_symbol();
137 size = obj->Size();
138 } else if (obj->IsJSObject()) {
139 JSObject* js_obj = JSObject::cast(obj);
140 constructor = js_obj->constructor_name();
141 size = JSStatsHelper::CalculateNetworkSize(js_obj);
142 } else {
143 return;
144 }
145
146 JSObjectsInfoTree::Locator loc;
147 if (!js_objects_info_tree_.Find(constructor, &loc)) {
148 js_objects_info_tree_.Insert(constructor, &loc);
149 }
150 NumberAndSizeInfo number_and_size = loc.value();
151 number_and_size.increment_number(1);
152 number_and_size.increment_bytes(size);
153 loc.set_value(number_and_size);
154 } 215 }
155 216
156 217
157 void ConstructorHeapProfile::PrintStats() { 218 void ConstructorHeapProfile::PrintStats() {
158 js_objects_info_tree_.ForEach(this); 219 js_objects_info_tree_.ForEach(this);
159 } 220 }
160 221
161 222
162 void JSObjectsCluster::Print(StringStream* accumulator) const { 223 void JSObjectsCluster::Print(StringStream* accumulator) const {
163 ASSERT(!is_null()); 224 ASSERT(!is_null());
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 } 285 }
225 286
226 287
227 ClustersCoarser::ClustersCoarser() 288 ClustersCoarser::ClustersCoarser()
228 : zscope_(DELETE_ON_EXIT), 289 : zscope_(DELETE_ON_EXIT),
229 sim_list_(ClustersCoarser::kInitialSimilarityListCapacity), 290 sim_list_(ClustersCoarser::kInitialSimilarityListCapacity),
230 current_pair_(NULL) { 291 current_pair_(NULL) {
231 } 292 }
232 293
233 294
234 void ClustersCoarser::Call( 295 void ClustersCoarser::Call(const JSObjectsCluster& cluster,
235 const JSObjectsCluster& cluster, JSObjectsClusterTree* tree) { 296 JSObjectsClusterTree* tree) {
236 if (tree != NULL) { 297 if (!cluster.can_be_coarsed()) return;
237 // First level of retainer graph. 298 ClusterBackRefs pair(cluster);
238 if (!cluster.can_be_coarsed()) return; 299 ASSERT(current_pair_ == NULL);
239 ClusterBackRefs pair(cluster); 300 current_pair_ = &pair;
240 ASSERT(current_pair_ == NULL); 301 current_set_ = new JSObjectsRetainerTree();
241 current_pair_ = &pair; 302 tree->ForEach(this);
242 current_set_ = new JSObjectsClusterTree(); 303 sim_list_.Add(pair);
243 tree->ForEach(this); 304 current_pair_ = NULL;
244 sim_list_.Add(pair); 305 current_set_ = NULL;
245 current_pair_ = NULL; 306 }
246 current_set_ = NULL; 307
308
309 void ClustersCoarser::Call(const JSObjectsCluster& cluster,
310 const NumberAndSizeInfo& number_and_size) {
311 ASSERT(current_pair_ != NULL);
312 ASSERT(current_set_ != NULL);
313 JSObjectsCluster eq = GetCoarseEquivalent(cluster);
314 JSObjectsRetainerTree::Locator loc;
315 if (!eq.is_null()) {
316 if (current_set_->Find(eq, &loc)) return;
317 current_pair_->refs.Add(eq);
318 current_set_->Insert(eq, &loc);
247 } else { 319 } else {
248 // Second level of retainer graph. 320 current_pair_->refs.Add(cluster);
249 ASSERT(current_pair_ != NULL);
250 ASSERT(current_set_ != NULL);
251 JSObjectsCluster eq = GetCoarseEquivalent(cluster);
252 JSObjectsClusterTree::Locator loc;
253 if (!eq.is_null()) {
254 if (current_set_->Find(eq, &loc)) return;
255 current_pair_->refs.Add(eq);
256 current_set_->Insert(eq, &loc);
257 } else {
258 current_pair_->refs.Add(cluster);
259 }
260 } 321 }
261 } 322 }
262 323
263 324
264 void ClustersCoarser::Process(JSObjectsClusterTree* tree) { 325 void ClustersCoarser::Process(JSObjectsRetainerTree* tree) {
265 int last_eq_clusters = -1; 326 int last_eq_clusters = -1;
266 for (int i = 0; i < kMaxPassesCount; ++i) { 327 for (int i = 0; i < kMaxPassesCount; ++i) {
267 sim_list_.Clear(); 328 sim_list_.Clear();
268 const int curr_eq_clusters = DoProcess(tree); 329 const int curr_eq_clusters = DoProcess(tree);
269 // If no new cluster equivalents discovered, abort processing. 330 // If no new cluster equivalents discovered, abort processing.
270 if (last_eq_clusters == curr_eq_clusters) break; 331 if (last_eq_clusters == curr_eq_clusters) break;
271 last_eq_clusters = curr_eq_clusters; 332 last_eq_clusters = curr_eq_clusters;
272 } 333 }
273 } 334 }
274 335
275 336
276 int ClustersCoarser::DoProcess(JSObjectsClusterTree* tree) { 337 int ClustersCoarser::DoProcess(JSObjectsRetainerTree* tree) {
277 tree->ForEach(this); 338 tree->ForEach(this);
278 // To sort similarity list properly, references list of a cluster is 339 // To sort similarity list properly, references list of a cluster is
279 // required to be sorted, thus 'O1 <- A, B' and 'O2 <- B, A' would 340 // required to be sorted, thus 'O1 <- A, B' and 'O2 <- B, A' would
280 // be considered equivalent. But we don't sort them explicitly 341 // be considered equivalent. But we don't sort them explicitly
281 // because we know that they come from a splay tree traversal, so 342 // because we know that they come from a splay tree traversal, so
282 // they are already sorted. 343 // they are already sorted.
283 sim_list_.Sort(ClusterBackRefsCmp); 344 sim_list_.Sort(ClusterBackRefsCmp);
284 return FillEqualityTree(); 345 return FillEqualityTree();
285 } 346 }
286 347
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 eq_to = i; 382 eq_to = i;
322 first_added = false; 383 first_added = false;
323 } 384 }
324 } 385 }
325 return eq_clusters_count; 386 return eq_clusters_count;
326 } 387 }
327 388
328 389
329 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoKey; 390 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoKey;
330 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoValue; 391 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoValue;
331 const JSObjectsClusterTreeConfig::Key JSObjectsClusterTreeConfig::kNoKey; 392 const JSObjectsRetainerTreeConfig::Key JSObjectsRetainerTreeConfig::kNoKey;
332 const JSObjectsClusterTreeConfig::Value JSObjectsClusterTreeConfig::kNoValue = 393 const JSObjectsRetainerTreeConfig::Value JSObjectsRetainerTreeConfig::kNoValue =
333 NULL; 394 NULL;
334 395
335 396
336 RetainerHeapProfile::RetainerHeapProfile() 397 RetainerHeapProfile::RetainerHeapProfile()
337 : zscope_(DELETE_ON_EXIT), 398 : zscope_(DELETE_ON_EXIT),
338 coarse_cluster_tree_(NULL), 399 coarse_cluster_tree_(NULL),
339 retainers_printed_(0),
340 current_printer_(NULL), 400 current_printer_(NULL),
341 current_stream_(NULL) { 401 current_stream_(NULL) {
342 JSObjectsCluster roots(JSObjectsCluster::ROOTS); 402 JSObjectsCluster roots(JSObjectsCluster::ROOTS);
343 ReferencesExtractor extractor( 403 ReferencesExtractor extractor(roots, this);
344 roots, this);
345 Heap::IterateRoots(&extractor); 404 Heap::IterateRoots(&extractor);
346 } 405 }
347 406
348 407
349 JSObjectsCluster RetainerHeapProfile::Clusterize(Object* obj) { 408 void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster,
350 if (obj->IsJSObject()) { 409 HeapObject* ref) {
351 String* constructor = JSObject::cast(obj)->constructor_name(); 410 JSObjectsCluster ref_cluster = Clusterizer::Clusterize(ref);
352 // Differentiate Object and Array instances. 411 JSObjectsRetainerTree::Locator ref_loc;
353 if (constructor == Heap::Object_symbol() ||
354 constructor == Heap::Array_symbol()) {
355 return JSObjectsCluster(constructor, obj);
356 } else {
357 return JSObjectsCluster(constructor);
358 }
359 } else if (obj->IsString()) {
360 return JSObjectsCluster(Heap::String_symbol());
361 } else {
362 UNREACHABLE();
363 return JSObjectsCluster();
364 }
365 }
366
367
368 void RetainerHeapProfile::StoreReference(
369 const JSObjectsCluster& cluster,
370 Object* ref) {
371 JSObjectsCluster ref_cluster = Clusterize(ref);
372 JSObjectsClusterTree::Locator ref_loc;
373 if (retainers_tree_.Insert(ref_cluster, &ref_loc)) { 412 if (retainers_tree_.Insert(ref_cluster, &ref_loc)) {
374 ref_loc.set_value(new JSObjectsClusterTree()); 413 ref_loc.set_value(new JSObjectsClusterTree());
375 } 414 }
376 JSObjectsClusterTree* referenced_by = ref_loc.value(); 415 JSObjectsClusterTree* referenced_by = ref_loc.value();
377 JSObjectsClusterTree::Locator obj_loc; 416 Clusterizer::InsertReferenceIntoTree(referenced_by, cluster);
378 referenced_by->Insert(cluster, &obj_loc);
379 } 417 }
380 418
381 419
382 void RetainerHeapProfile::CollectStats(HeapObject* obj) { 420 void RetainerHeapProfile::CollectStats(HeapObject* obj) {
383 if (obj->IsJSObject()) { 421 if (obj->IsJSObject()) {
384 const JSObjectsCluster cluster = Clusterize(JSObject::cast(obj)); 422 const JSObjectsCluster cluster = Clusterizer::Clusterize(obj);
385 ReferencesExtractor extractor(cluster, this); 423 ReferencesExtractor extractor(cluster, this);
386 obj->Iterate(&extractor); 424 obj->Iterate(&extractor);
387 } else if (obj->IsJSGlobalPropertyCell()) { 425 } else if (obj->IsJSGlobalPropertyCell()) {
388 JSObjectsCluster global_prop(JSObjectsCluster::GLOBAL_PROPERTY); 426 JSObjectsCluster global_prop(JSObjectsCluster::GLOBAL_PROPERTY);
389 ReferencesExtractor extractor(global_prop, this); 427 ReferencesExtractor extractor(global_prop, this);
390 obj->Iterate(&extractor); 428 obj->Iterate(&extractor);
391 } 429 }
392 } 430 }
393 431
394 432
395 void RetainerHeapProfile::DebugPrintStats( 433 void RetainerHeapProfile::DebugPrintStats(
396 RetainerHeapProfile::Printer* printer) { 434 RetainerHeapProfile::Printer* printer) {
397 coarser_.Process(&retainers_tree_); 435 coarser_.Process(&retainers_tree_);
398 ASSERT(current_printer_ == NULL); 436 ASSERT(current_printer_ == NULL);
399 current_printer_ = printer; 437 current_printer_ = printer;
400 retainers_tree_.ForEach(this); 438 retainers_tree_.ForEach(this);
401 current_printer_ = NULL; 439 current_printer_ = NULL;
402 } 440 }
403 441
404 442
405 void RetainerHeapProfile::PrintStats() { 443 void RetainerHeapProfile::PrintStats() {
406 RetainersPrinter printer; 444 RetainersPrinter printer;
407 DebugPrintStats(&printer); 445 DebugPrintStats(&printer);
408 } 446 }
409 447
410 448
411 void RetainerHeapProfile::Call( 449 void RetainerHeapProfile::Call(const JSObjectsCluster& cluster,
412 const JSObjectsCluster& cluster, 450 JSObjectsClusterTree* tree) {
413 JSObjectsClusterTree* tree) { 451 // First level of retainer graph.
414 ASSERT(current_printer_ != NULL); 452 if (coarser_.HasAnEquivalent(cluster)) return;
415 if (tree != NULL) { 453 ASSERT(current_stream_ == NULL);
416 // First level of retainer graph. 454 HeapStringAllocator allocator;
417 if (coarser_.HasAnEquivalent(cluster)) return; 455 StringStream stream(&allocator);
418 ASSERT(current_stream_ == NULL); 456 current_stream_ = &stream;
419 HeapStringAllocator allocator; 457 ASSERT(coarse_cluster_tree_ == NULL);
420 StringStream stream(&allocator); 458 coarse_cluster_tree_ = new JSObjectsClusterTree();
421 current_stream_ = &stream; 459 tree->ForEach(this);
422 cluster.Print(current_stream_); 460 // Print aggregated counts and sizes.
423 ASSERT(coarse_cluster_tree_ == NULL); 461 RetainerTreePrinter printer(current_stream_);
424 coarse_cluster_tree_ = new JSObjectsClusterTree(); 462 coarse_cluster_tree_->ForEach(&printer);
425 retainers_printed_ = 0; 463 coarse_cluster_tree_ = NULL;
426 tree->ForEach(this); 464 current_printer_->PrintRetainers(cluster, stream);
427 coarse_cluster_tree_ = NULL; 465 current_stream_ = NULL;
428 current_printer_->PrintRetainers(stream); 466 }
429 current_stream_ = NULL; 467
468
469 void RetainerHeapProfile::Call(const JSObjectsCluster& cluster,
470 const NumberAndSizeInfo& number_and_size) {
471 ASSERT(coarse_cluster_tree_ != NULL);
472 ASSERT(current_stream_ != NULL);
473 JSObjectsCluster eq = coarser_.GetCoarseEquivalent(cluster);
474 if (eq.is_null()) {
475 RetainerTreePrinter::Print(current_stream_, cluster, number_and_size);
430 } else { 476 } else {
431 // Second level of retainer graph. 477 // Aggregate counts and sizes for equivalent clusters.
432 ASSERT(coarse_cluster_tree_ != NULL); 478 JSObjectsClusterTree::Locator loc;
433 ASSERT(current_stream_ != NULL); 479 coarse_cluster_tree_->Insert(eq, &loc);
434 if (retainers_printed_ >= kMaxRetainersToPrint) { 480 NumberAndSizeInfo eq_number_and_size = loc.value();
435 if (retainers_printed_ == kMaxRetainersToPrint) { 481 eq_number_and_size.increment_number(number_and_size.number());
436 // TODO(mnaganov): Print the exact count. 482 loc.set_value(eq_number_and_size);
437 current_stream_->Add(",...");
438 ++retainers_printed_; // avoid printing ellipsis next time.
439 }
440 return;
441 }
442 JSObjectsCluster eq = coarser_.GetCoarseEquivalent(cluster);
443 if (eq.is_null()) {
444 current_stream_->Put(',');
445 cluster.Print(current_stream_);
446 ++retainers_printed_;
447 } else {
448 JSObjectsClusterTree::Locator loc;
449 if (coarse_cluster_tree_->Insert(eq, &loc)) {
450 current_stream_->Put(',');
451 eq.Print(current_stream_);
452 ++retainers_printed_;
453 }
454 }
455 } 483 }
456 } 484 }
457 485
458 486
459 // 487 //
460 // HeapProfiler class implementation. 488 // HeapProfiler class implementation.
461 // 489 //
462 void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) { 490 void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) {
463 InstanceType type = obj->map()->instance_type(); 491 InstanceType type = obj->map()->instance_type();
464 ASSERT(0 <= type && type <= LAST_TYPE); 492 ASSERT(0 <= type && type <= LAST_TYPE);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
510 js_retainer_profile.PrintStats(); 538 js_retainer_profile.PrintStats();
511 539
512 LOG(HeapSampleEndEvent("Heap", "allocated")); 540 LOG(HeapSampleEndEvent("Heap", "allocated"));
513 } 541 }
514 542
515 543
516 #endif // ENABLE_LOGGING_AND_PROFILING 544 #endif // ENABLE_LOGGING_AND_PROFILING
517 545
518 546
519 } } // namespace v8::internal 547 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/heap-profiler.h ('k') | src/log.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698