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

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

Issue 247001: Heap profiler: aggregate retainers count of equivalent clusters. (Closed)
Patch Set: 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') | test/cctest/test-heap-profiler.cc » ('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 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 const StringStream& retainers) { 155 const StringStream& retainers) {
156 HeapStringAllocator allocator; 156 HeapStringAllocator allocator;
157 StringStream stream(&allocator); 157 StringStream stream(&allocator);
158 cluster.Print(&stream); 158 cluster.Print(&stream);
159 LOG(HeapSampleJSRetainersEvent( 159 LOG(HeapSampleJSRetainersEvent(
160 *(stream.ToCString()), *(retainers.ToCString()))); 160 *(stream.ToCString()), *(retainers.ToCString())));
161 } 161 }
162 }; 162 };
163 163
164 164
165 class RetainerTreePrinter BASE_EMBEDDED { 165 // Visitor for printing a cluster tree.
166 class ClusterTreePrinter BASE_EMBEDDED {
166 public: 167 public:
167 explicit RetainerTreePrinter(StringStream* stream) : stream_(stream) {} 168 explicit ClusterTreePrinter(StringStream* stream) : stream_(stream) {}
168 void Call(const JSObjectsCluster& cluster, 169 void Call(const JSObjectsCluster& cluster,
169 const NumberAndSizeInfo& number_and_size) { 170 const NumberAndSizeInfo& number_and_size) {
170 Print(stream_, cluster, number_and_size); 171 Print(stream_, cluster, number_and_size);
171 } 172 }
172 static void Print(StringStream* stream, 173 static void Print(StringStream* stream,
173 const JSObjectsCluster& cluster, 174 const JSObjectsCluster& cluster,
174 const NumberAndSizeInfo& numNNber_and_size); 175 const NumberAndSizeInfo& number_and_size);
175 176
176 private: 177 private:
177 StringStream* stream_; 178 StringStream* stream_;
178 }; 179 };
179 180
180 181
181 void RetainerTreePrinter::Print(StringStream* stream, 182 void ClusterTreePrinter::Print(StringStream* stream,
182 const JSObjectsCluster& cluster, 183 const JSObjectsCluster& cluster,
183 const NumberAndSizeInfo& number_and_size) { 184 const NumberAndSizeInfo& number_and_size) {
184 stream->Put(','); 185 stream->Put(',');
185 cluster.Print(stream); 186 cluster.Print(stream);
186 stream->Add(";%d", number_and_size.number()); 187 stream->Add(";%d", number_and_size.number());
187 } 188 }
188 189
189 190
191 // Visitor for printing a retainer tree.
192 class SimpleRetainerTreePrinter BASE_EMBEDDED {
193 public:
194 explicit SimpleRetainerTreePrinter(RetainerHeapProfile::Printer* printer)
195 : printer_(printer) {}
196 void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
197
198 private:
199 RetainerHeapProfile::Printer* printer_;
200 };
201
202
203 void SimpleRetainerTreePrinter::Call(const JSObjectsCluster& cluster,
204 JSObjectsClusterTree* tree) {
205 HeapStringAllocator allocator;
206 StringStream stream(&allocator);
207 ClusterTreePrinter retainers_printer(&stream);
208 tree->ForEach(&retainers_printer);
209 printer_->PrintRetainers(cluster, stream);
210 }
211
212
213 // Visitor for aggregating references count of equivalent clusters.
214 class RetainersAggregator BASE_EMBEDDED {
215 public:
216 RetainersAggregator(ClustersCoarser* coarser, JSObjectsClusterTree* dest_tree)
217 : coarser_(coarser), dest_tree_(dest_tree) {}
218 void Call(const JSObjectsCluster& cluster,
219 const NumberAndSizeInfo& number_and_size);
220
221 private:
222 ClustersCoarser* coarser_;
223 JSObjectsClusterTree* dest_tree_;
224 };
225
226
227 void RetainersAggregator::Call(const JSObjectsCluster& cluster,
228 const NumberAndSizeInfo& number_and_size) {
229 JSObjectsCluster eq = coarser_->GetCoarseEquivalent(cluster);
230 if (eq.is_null()) eq = cluster;
231 JSObjectsClusterTree::Locator loc;
232 dest_tree_->Insert(eq, &loc);
233 NumberAndSizeInfo aggregated_number = loc.value();
234 aggregated_number.increment_number(number_and_size.number());
235 loc.set_value(aggregated_number);
236 }
237
238
239 // Visitor for printing retainers tree. Aggregates equivalent retainer clusters.
240 class AggregatingRetainerTreePrinter BASE_EMBEDDED {
241 public:
242 AggregatingRetainerTreePrinter(ClustersCoarser* coarser,
243 RetainerHeapProfile::Printer* printer)
244 : coarser_(coarser), printer_(printer) {}
245 void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
246
247 private:
248 ClustersCoarser* coarser_;
249 RetainerHeapProfile::Printer* printer_;
250 };
251
252
253 void AggregatingRetainerTreePrinter::Call(const JSObjectsCluster& cluster,
254 JSObjectsClusterTree* tree) {
255 if (!coarser_->GetCoarseEquivalent(cluster).is_null()) return;
256 JSObjectsClusterTree dest_tree_;
257 RetainersAggregator retainers_aggregator(coarser_, &dest_tree_);
258 tree->ForEach(&retainers_aggregator);
259 HeapStringAllocator allocator;
260 StringStream stream(&allocator);
261 ClusterTreePrinter retainers_printer(&stream);
262 dest_tree_.ForEach(&retainers_printer);
263 printer_->PrintRetainers(cluster, stream);
264 }
265
266
267 // A helper class for building a retainers tree, that aggregates
268 // all equivalent clusters.
269 class RetainerTreeAggregator BASE_EMBEDDED {
270 public:
271 explicit RetainerTreeAggregator(ClustersCoarser* coarser)
272 : coarser_(coarser) {}
273 void Process(JSObjectsRetainerTree* input_tree) {
274 input_tree->ForEach(this);
275 }
276 void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
277 JSObjectsRetainerTree& output_tree() { return output_tree_; }
278
279 private:
280 ClustersCoarser* coarser_;
281 JSObjectsRetainerTree output_tree_;
282 };
283
284
285 void RetainerTreeAggregator::Call(const JSObjectsCluster& cluster,
286 JSObjectsClusterTree* tree) {
287 JSObjectsCluster eq = coarser_->GetCoarseEquivalent(cluster);
288 if (eq.is_null()) return;
289 JSObjectsRetainerTree::Locator loc;
290 if (output_tree_.Insert(eq, &loc)) {
291 loc.set_value(new JSObjectsClusterTree());
292 }
293 RetainersAggregator retainers_aggregator(coarser_, loc.value());
294 tree->ForEach(&retainers_aggregator);
295 }
296
190 } // namespace 297 } // namespace
191 298
192 299
193 const JSObjectsClusterTreeConfig::Key JSObjectsClusterTreeConfig::kNoKey; 300 const JSObjectsClusterTreeConfig::Key JSObjectsClusterTreeConfig::kNoKey;
194 const JSObjectsClusterTreeConfig::Value JSObjectsClusterTreeConfig::kNoValue; 301 const JSObjectsClusterTreeConfig::Value JSObjectsClusterTreeConfig::kNoValue;
195 302
196 303
197 ConstructorHeapProfile::ConstructorHeapProfile() 304 ConstructorHeapProfile::ConstructorHeapProfile()
198 : zscope_(DELETE_ON_EXIT) { 305 : zscope_(DELETE_ON_EXIT) {
199 } 306 }
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 JSObjectsCluster ClustersCoarser::GetCoarseEquivalent( 456 JSObjectsCluster ClustersCoarser::GetCoarseEquivalent(
350 const JSObjectsCluster& cluster) { 457 const JSObjectsCluster& cluster) {
351 if (!cluster.can_be_coarsed()) return JSObjectsCluster(); 458 if (!cluster.can_be_coarsed()) return JSObjectsCluster();
352 EqualityTree::Locator loc; 459 EqualityTree::Locator loc;
353 return eq_tree_.Find(cluster, &loc) ? loc.value() : JSObjectsCluster(); 460 return eq_tree_.Find(cluster, &loc) ? loc.value() : JSObjectsCluster();
354 } 461 }
355 462
356 463
357 bool ClustersCoarser::HasAnEquivalent(const JSObjectsCluster& cluster) { 464 bool ClustersCoarser::HasAnEquivalent(const JSObjectsCluster& cluster) {
358 // Return true for coarsible clusters that have a non-identical equivalent. 465 // Return true for coarsible clusters that have a non-identical equivalent.
359 return cluster.can_be_coarsed() && 466 if (!cluster.can_be_coarsed()) return false;
360 JSObjectsCluster::Compare(cluster, GetCoarseEquivalent(cluster)) != 0; 467 JSObjectsCluster eq = GetCoarseEquivalent(cluster);
468 return !eq.is_null() && JSObjectsCluster::Compare(cluster, eq) != 0;
361 } 469 }
362 470
363 471
364 int ClustersCoarser::FillEqualityTree() { 472 int ClustersCoarser::FillEqualityTree() {
365 int eq_clusters_count = 0; 473 int eq_clusters_count = 0;
366 int eq_to = 0; 474 int eq_to = 0;
367 bool first_added = false; 475 bool first_added = false;
368 for (int i = 1; i < sim_list_.length(); ++i) { 476 for (int i = 1; i < sim_list_.length(); ++i) {
369 if (ClusterBackRefs::Compare(sim_list_[i], sim_list_[eq_to]) == 0) { 477 if (ClusterBackRefs::Compare(sim_list_[i], sim_list_[eq_to]) == 0) {
370 EqualityTree::Locator loc; 478 EqualityTree::Locator loc;
(...skipping 17 matching lines...) Expand all
388 496
389 497
390 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoKey; 498 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoKey;
391 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoValue; 499 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoValue;
392 const JSObjectsRetainerTreeConfig::Key JSObjectsRetainerTreeConfig::kNoKey; 500 const JSObjectsRetainerTreeConfig::Key JSObjectsRetainerTreeConfig::kNoKey;
393 const JSObjectsRetainerTreeConfig::Value JSObjectsRetainerTreeConfig::kNoValue = 501 const JSObjectsRetainerTreeConfig::Value JSObjectsRetainerTreeConfig::kNoValue =
394 NULL; 502 NULL;
395 503
396 504
397 RetainerHeapProfile::RetainerHeapProfile() 505 RetainerHeapProfile::RetainerHeapProfile()
398 : zscope_(DELETE_ON_EXIT), 506 : zscope_(DELETE_ON_EXIT) {
399 coarse_cluster_tree_(NULL),
400 current_printer_(NULL),
401 current_stream_(NULL) {
402 JSObjectsCluster roots(JSObjectsCluster::ROOTS); 507 JSObjectsCluster roots(JSObjectsCluster::ROOTS);
403 ReferencesExtractor extractor(roots, this); 508 ReferencesExtractor extractor(roots, this);
404 Heap::IterateRoots(&extractor); 509 Heap::IterateRoots(&extractor);
405 } 510 }
406 511
407 512
408 void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster, 513 void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster,
409 HeapObject* ref) { 514 HeapObject* ref) {
410 JSObjectsCluster ref_cluster = Clusterizer::Clusterize(ref); 515 JSObjectsCluster ref_cluster = Clusterizer::Clusterize(ref);
411 JSObjectsRetainerTree::Locator ref_loc; 516 JSObjectsRetainerTree::Locator ref_loc;
(...skipping 14 matching lines...) Expand all
426 JSObjectsCluster global_prop(JSObjectsCluster::GLOBAL_PROPERTY); 531 JSObjectsCluster global_prop(JSObjectsCluster::GLOBAL_PROPERTY);
427 ReferencesExtractor extractor(global_prop, this); 532 ReferencesExtractor extractor(global_prop, this);
428 obj->Iterate(&extractor); 533 obj->Iterate(&extractor);
429 } 534 }
430 } 535 }
431 536
432 537
433 void RetainerHeapProfile::DebugPrintStats( 538 void RetainerHeapProfile::DebugPrintStats(
434 RetainerHeapProfile::Printer* printer) { 539 RetainerHeapProfile::Printer* printer) {
435 coarser_.Process(&retainers_tree_); 540 coarser_.Process(&retainers_tree_);
436 ASSERT(current_printer_ == NULL); 541 // Print clusters that have no equivalents, aggregating their retainers.
437 current_printer_ = printer; 542 AggregatingRetainerTreePrinter agg_printer(&coarser_, printer);
438 retainers_tree_.ForEach(this); 543 retainers_tree_.ForEach(&agg_printer);
439 current_printer_ = NULL; 544 // Now aggregate clusters that have equivalents...
545 RetainerTreeAggregator aggregator(&coarser_);
546 aggregator.Process(&retainers_tree_);
547 // ...and print them.
548 SimpleRetainerTreePrinter s_printer(printer);
549 aggregator.output_tree().ForEach(&s_printer);
440 } 550 }
441 551
442 552
443 void RetainerHeapProfile::PrintStats() { 553 void RetainerHeapProfile::PrintStats() {
444 RetainersPrinter printer; 554 RetainersPrinter printer;
445 DebugPrintStats(&printer); 555 DebugPrintStats(&printer);
446 } 556 }
447 557
448 558
449 void RetainerHeapProfile::Call(const JSObjectsCluster& cluster,
450 JSObjectsClusterTree* tree) {
451 // First level of retainer graph.
452 if (coarser_.HasAnEquivalent(cluster)) return;
453 ASSERT(current_stream_ == NULL);
454 HeapStringAllocator allocator;
455 StringStream stream(&allocator);
456 current_stream_ = &stream;
457 ASSERT(coarse_cluster_tree_ == NULL);
458 coarse_cluster_tree_ = new JSObjectsClusterTree();
459 tree->ForEach(this);
460 // Print aggregated counts and sizes.
461 RetainerTreePrinter printer(current_stream_);
462 coarse_cluster_tree_->ForEach(&printer);
463 coarse_cluster_tree_ = NULL;
464 current_printer_->PrintRetainers(cluster, stream);
465 current_stream_ = NULL;
466 }
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);
476 } else {
477 // Aggregate counts and sizes for equivalent clusters.
478 JSObjectsClusterTree::Locator loc;
479 coarse_cluster_tree_->Insert(eq, &loc);
480 NumberAndSizeInfo eq_number_and_size = loc.value();
481 eq_number_and_size.increment_number(number_and_size.number());
482 loc.set_value(eq_number_and_size);
483 }
484 }
485
486
487 // 559 //
488 // HeapProfiler class implementation. 560 // HeapProfiler class implementation.
489 // 561 //
490 void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) { 562 void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) {
491 InstanceType type = obj->map()->instance_type(); 563 InstanceType type = obj->map()->instance_type();
492 ASSERT(0 <= type && type <= LAST_TYPE); 564 ASSERT(0 <= type && type <= LAST_TYPE);
493 info[type].increment_number(1); 565 info[type].increment_number(1);
494 info[type].increment_bytes(obj->Size()); 566 info[type].increment_bytes(obj->Size());
495 } 567 }
496 568
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 js_retainer_profile.PrintStats(); 610 js_retainer_profile.PrintStats();
539 611
540 LOG(HeapSampleEndEvent("Heap", "allocated")); 612 LOG(HeapSampleEndEvent("Heap", "allocated"));
541 } 613 }
542 614
543 615
544 #endif // ENABLE_LOGGING_AND_PROFILING 616 #endif // ENABLE_LOGGING_AND_PROFILING
545 617
546 618
547 } } // namespace v8::internal 619 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/heap-profiler.h ('k') | test/cctest/test-heap-profiler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698