OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |