| 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 |