| 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 19 matching lines...) Expand all Loading... |
| 219 js_objects_info_tree_.ForEach(this); | 326 js_objects_info_tree_.ForEach(this); |
| 220 } | 327 } |
| 221 | 328 |
| 222 | 329 |
| 223 void JSObjectsCluster::Print(StringStream* accumulator) const { | 330 void JSObjectsCluster::Print(StringStream* accumulator) const { |
| 224 ASSERT(!is_null()); | 331 ASSERT(!is_null()); |
| 225 if (constructor_ == FromSpecialCase(ROOTS)) { | 332 if (constructor_ == FromSpecialCase(ROOTS)) { |
| 226 accumulator->Add("(roots)"); | 333 accumulator->Add("(roots)"); |
| 227 } else if (constructor_ == FromSpecialCase(GLOBAL_PROPERTY)) { | 334 } else if (constructor_ == FromSpecialCase(GLOBAL_PROPERTY)) { |
| 228 accumulator->Add("(global property)"); | 335 accumulator->Add("(global property)"); |
| 336 } else if (constructor_ == FromSpecialCase(SELF)) { |
| 337 accumulator->Add("(self)"); |
| 229 } else { | 338 } else { |
| 230 SmartPointer<char> s_name( | 339 SmartPointer<char> s_name( |
| 231 constructor_->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)); | 340 constructor_->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)); |
| 232 accumulator->Add("%s", (*s_name)[0] != '\0' ? *s_name : "(anonymous)"); | 341 accumulator->Add("%s", (*s_name)[0] != '\0' ? *s_name : "(anonymous)"); |
| 233 if (instance_ != NULL) { | 342 if (instance_ != NULL) { |
| 234 accumulator->Add(":%p", static_cast<void*>(instance_)); | 343 accumulator->Add(":%p", static_cast<void*>(instance_)); |
| 235 } | 344 } |
| 236 } | 345 } |
| 237 } | 346 } |
| 238 | 347 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 if (a.refs.length() > b.refs.length()) return 1; | 388 if (a.refs.length() > b.refs.length()) return 1; |
| 280 for (int i = 0; i < a.refs.length(); ++i) { | 389 for (int i = 0; i < a.refs.length(); ++i) { |
| 281 int cmp = JSObjectsCluster::Compare(a.refs[i], b.refs[i]); | 390 int cmp = JSObjectsCluster::Compare(a.refs[i], b.refs[i]); |
| 282 if (cmp != 0) return cmp; | 391 if (cmp != 0) return cmp; |
| 283 } | 392 } |
| 284 return 0; | 393 return 0; |
| 285 } | 394 } |
| 286 | 395 |
| 287 | 396 |
| 288 ClustersCoarser::ClustersCoarser() | 397 ClustersCoarser::ClustersCoarser() |
| 289 : zscope_(DELETE_ON_EXIT), | 398 : zscope_(DELETE_ON_EXIT), |
| 290 sim_list_(ClustersCoarser::kInitialSimilarityListCapacity), | 399 sim_list_(ClustersCoarser::kInitialSimilarityListCapacity), |
| 291 current_pair_(NULL) { | 400 current_pair_(NULL), |
| 401 current_set_(NULL), |
| 402 self_(NULL) { |
| 292 } | 403 } |
| 293 | 404 |
| 294 | 405 |
| 295 void ClustersCoarser::Call(const JSObjectsCluster& cluster, | 406 void ClustersCoarser::Call(const JSObjectsCluster& cluster, |
| 296 JSObjectsClusterTree* tree) { | 407 JSObjectsClusterTree* tree) { |
| 297 if (!cluster.can_be_coarsed()) return; | 408 if (!cluster.can_be_coarsed()) return; |
| 298 ClusterBackRefs pair(cluster); | 409 ClusterBackRefs pair(cluster); |
| 299 ASSERT(current_pair_ == NULL); | 410 ASSERT(current_pair_ == NULL); |
| 300 current_pair_ = &pair; | 411 current_pair_ = &pair; |
| 301 current_set_ = new JSObjectsRetainerTree(); | 412 current_set_ = new JSObjectsRetainerTree(); |
| 413 self_ = &cluster; |
| 302 tree->ForEach(this); | 414 tree->ForEach(this); |
| 303 sim_list_.Add(pair); | 415 sim_list_.Add(pair); |
| 304 current_pair_ = NULL; | 416 current_pair_ = NULL; |
| 305 current_set_ = NULL; | 417 current_set_ = NULL; |
| 418 self_ = NULL; |
| 306 } | 419 } |
| 307 | 420 |
| 308 | 421 |
| 309 void ClustersCoarser::Call(const JSObjectsCluster& cluster, | 422 void ClustersCoarser::Call(const JSObjectsCluster& cluster, |
| 310 const NumberAndSizeInfo& number_and_size) { | 423 const NumberAndSizeInfo& number_and_size) { |
| 311 ASSERT(current_pair_ != NULL); | 424 ASSERT(current_pair_ != NULL); |
| 312 ASSERT(current_set_ != NULL); | 425 ASSERT(current_set_ != NULL); |
| 426 ASSERT(self_ != NULL); |
| 427 JSObjectsRetainerTree::Locator loc; |
| 428 if (JSObjectsCluster::Compare(*self_, cluster) == 0) { |
| 429 current_pair_->refs.Add(JSObjectsCluster(JSObjectsCluster::SELF)); |
| 430 return; |
| 431 } |
| 313 JSObjectsCluster eq = GetCoarseEquivalent(cluster); | 432 JSObjectsCluster eq = GetCoarseEquivalent(cluster); |
| 314 JSObjectsRetainerTree::Locator loc; | |
| 315 if (!eq.is_null()) { | 433 if (!eq.is_null()) { |
| 316 if (current_set_->Find(eq, &loc)) return; | 434 if (current_set_->Find(eq, &loc)) return; |
| 317 current_pair_->refs.Add(eq); | 435 current_pair_->refs.Add(eq); |
| 318 current_set_->Insert(eq, &loc); | 436 current_set_->Insert(eq, &loc); |
| 319 } else { | 437 } else { |
| 320 current_pair_->refs.Add(cluster); | 438 current_pair_->refs.Add(cluster); |
| 321 } | 439 } |
| 322 } | 440 } |
| 323 | 441 |
| 324 | 442 |
| 325 void ClustersCoarser::Process(JSObjectsRetainerTree* tree) { | 443 void ClustersCoarser::Process(JSObjectsRetainerTree* tree) { |
| 326 int last_eq_clusters = -1; | 444 int last_eq_clusters = -1; |
| 327 for (int i = 0; i < kMaxPassesCount; ++i) { | 445 for (int i = 0; i < kMaxPassesCount; ++i) { |
| 328 sim_list_.Clear(); | 446 sim_list_.Clear(); |
| 329 const int curr_eq_clusters = DoProcess(tree); | 447 const int curr_eq_clusters = DoProcess(tree); |
| 330 // If no new cluster equivalents discovered, abort processing. | 448 // If no new cluster equivalents discovered, abort processing. |
| 331 if (last_eq_clusters == curr_eq_clusters) break; | 449 if (last_eq_clusters == curr_eq_clusters) break; |
| 332 last_eq_clusters = curr_eq_clusters; | 450 last_eq_clusters = curr_eq_clusters; |
| 333 } | 451 } |
| 334 } | 452 } |
| 335 | 453 |
| 336 | 454 |
| 337 int ClustersCoarser::DoProcess(JSObjectsRetainerTree* tree) { | 455 int ClustersCoarser::DoProcess(JSObjectsRetainerTree* tree) { |
| 338 tree->ForEach(this); | 456 tree->ForEach(this); |
| 339 // To sort similarity list properly, references list of a cluster is | 457 sim_list_.Iterate(ClusterBackRefs::SortRefsIterator); |
| 340 // required to be sorted, thus 'O1 <- A, B' and 'O2 <- B, A' would | |
| 341 // be considered equivalent. But we don't sort them explicitly | |
| 342 // because we know that they come from a splay tree traversal, so | |
| 343 // they are already sorted. | |
| 344 sim_list_.Sort(ClusterBackRefsCmp); | 458 sim_list_.Sort(ClusterBackRefsCmp); |
| 345 return FillEqualityTree(); | 459 return FillEqualityTree(); |
| 346 } | 460 } |
| 347 | 461 |
| 348 | 462 |
| 349 JSObjectsCluster ClustersCoarser::GetCoarseEquivalent( | 463 JSObjectsCluster ClustersCoarser::GetCoarseEquivalent( |
| 350 const JSObjectsCluster& cluster) { | 464 const JSObjectsCluster& cluster) { |
| 351 if (!cluster.can_be_coarsed()) return JSObjectsCluster(); | 465 if (!cluster.can_be_coarsed()) return JSObjectsCluster(); |
| 352 EqualityTree::Locator loc; | 466 EqualityTree::Locator loc; |
| 353 return eq_tree_.Find(cluster, &loc) ? loc.value() : JSObjectsCluster(); | 467 return eq_tree_.Find(cluster, &loc) ? loc.value() : JSObjectsCluster(); |
| 354 } | 468 } |
| 355 | 469 |
| 356 | 470 |
| 357 bool ClustersCoarser::HasAnEquivalent(const JSObjectsCluster& cluster) { | 471 bool ClustersCoarser::HasAnEquivalent(const JSObjectsCluster& cluster) { |
| 358 // Return true for coarsible clusters that have a non-identical equivalent. | 472 // Return true for coarsible clusters that have a non-identical equivalent. |
| 359 return cluster.can_be_coarsed() && | 473 if (!cluster.can_be_coarsed()) return false; |
| 360 JSObjectsCluster::Compare(cluster, GetCoarseEquivalent(cluster)) != 0; | 474 JSObjectsCluster eq = GetCoarseEquivalent(cluster); |
| 475 return !eq.is_null() && JSObjectsCluster::Compare(cluster, eq) != 0; |
| 361 } | 476 } |
| 362 | 477 |
| 363 | 478 |
| 364 int ClustersCoarser::FillEqualityTree() { | 479 int ClustersCoarser::FillEqualityTree() { |
| 365 int eq_clusters_count = 0; | 480 int eq_clusters_count = 0; |
| 366 int eq_to = 0; | 481 int eq_to = 0; |
| 367 bool first_added = false; | 482 bool first_added = false; |
| 368 for (int i = 1; i < sim_list_.length(); ++i) { | 483 for (int i = 1; i < sim_list_.length(); ++i) { |
| 369 if (ClusterBackRefs::Compare(sim_list_[i], sim_list_[eq_to]) == 0) { | 484 if (ClusterBackRefs::Compare(sim_list_[i], sim_list_[eq_to]) == 0) { |
| 370 EqualityTree::Locator loc; | 485 EqualityTree::Locator loc; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 388 | 503 |
| 389 | 504 |
| 390 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoKey; | 505 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoKey; |
| 391 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoValue; | 506 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoValue; |
| 392 const JSObjectsRetainerTreeConfig::Key JSObjectsRetainerTreeConfig::kNoKey; | 507 const JSObjectsRetainerTreeConfig::Key JSObjectsRetainerTreeConfig::kNoKey; |
| 393 const JSObjectsRetainerTreeConfig::Value JSObjectsRetainerTreeConfig::kNoValue = | 508 const JSObjectsRetainerTreeConfig::Value JSObjectsRetainerTreeConfig::kNoValue = |
| 394 NULL; | 509 NULL; |
| 395 | 510 |
| 396 | 511 |
| 397 RetainerHeapProfile::RetainerHeapProfile() | 512 RetainerHeapProfile::RetainerHeapProfile() |
| 398 : zscope_(DELETE_ON_EXIT), | 513 : zscope_(DELETE_ON_EXIT) { |
| 399 coarse_cluster_tree_(NULL), | |
| 400 current_printer_(NULL), | |
| 401 current_stream_(NULL) { | |
| 402 JSObjectsCluster roots(JSObjectsCluster::ROOTS); | 514 JSObjectsCluster roots(JSObjectsCluster::ROOTS); |
| 403 ReferencesExtractor extractor(roots, this); | 515 ReferencesExtractor extractor(roots, this); |
| 404 Heap::IterateRoots(&extractor); | 516 Heap::IterateRoots(&extractor); |
| 405 } | 517 } |
| 406 | 518 |
| 407 | 519 |
| 408 void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster, | 520 void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster, |
| 409 HeapObject* ref) { | 521 HeapObject* ref) { |
| 410 JSObjectsCluster ref_cluster = Clusterizer::Clusterize(ref); | 522 JSObjectsCluster ref_cluster = Clusterizer::Clusterize(ref); |
| 411 JSObjectsRetainerTree::Locator ref_loc; | 523 JSObjectsRetainerTree::Locator ref_loc; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 426 JSObjectsCluster global_prop(JSObjectsCluster::GLOBAL_PROPERTY); | 538 JSObjectsCluster global_prop(JSObjectsCluster::GLOBAL_PROPERTY); |
| 427 ReferencesExtractor extractor(global_prop, this); | 539 ReferencesExtractor extractor(global_prop, this); |
| 428 obj->Iterate(&extractor); | 540 obj->Iterate(&extractor); |
| 429 } | 541 } |
| 430 } | 542 } |
| 431 | 543 |
| 432 | 544 |
| 433 void RetainerHeapProfile::DebugPrintStats( | 545 void RetainerHeapProfile::DebugPrintStats( |
| 434 RetainerHeapProfile::Printer* printer) { | 546 RetainerHeapProfile::Printer* printer) { |
| 435 coarser_.Process(&retainers_tree_); | 547 coarser_.Process(&retainers_tree_); |
| 436 ASSERT(current_printer_ == NULL); | 548 // Print clusters that have no equivalents, aggregating their retainers. |
| 437 current_printer_ = printer; | 549 AggregatingRetainerTreePrinter agg_printer(&coarser_, printer); |
| 438 retainers_tree_.ForEach(this); | 550 retainers_tree_.ForEach(&agg_printer); |
| 439 current_printer_ = NULL; | 551 // Now aggregate clusters that have equivalents... |
| 552 RetainerTreeAggregator aggregator(&coarser_); |
| 553 aggregator.Process(&retainers_tree_); |
| 554 // ...and print them. |
| 555 SimpleRetainerTreePrinter s_printer(printer); |
| 556 aggregator.output_tree().ForEach(&s_printer); |
| 440 } | 557 } |
| 441 | 558 |
| 442 | 559 |
| 443 void RetainerHeapProfile::PrintStats() { | 560 void RetainerHeapProfile::PrintStats() { |
| 444 RetainersPrinter printer; | 561 RetainersPrinter printer; |
| 445 DebugPrintStats(&printer); | 562 DebugPrintStats(&printer); |
| 446 } | 563 } |
| 447 | 564 |
| 448 | 565 |
| 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 // | 566 // |
| 488 // HeapProfiler class implementation. | 567 // HeapProfiler class implementation. |
| 489 // | 568 // |
| 490 void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) { | 569 void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) { |
| 491 InstanceType type = obj->map()->instance_type(); | 570 InstanceType type = obj->map()->instance_type(); |
| 492 ASSERT(0 <= type && type <= LAST_TYPE); | 571 ASSERT(0 <= type && type <= LAST_TYPE); |
| 493 info[type].increment_number(1); | 572 info[type].increment_number(1); |
| 494 info[type].increment_bytes(obj->Size()); | 573 info[type].increment_bytes(obj->Size()); |
| 495 } | 574 } |
| 496 | 575 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 js_retainer_profile.PrintStats(); | 617 js_retainer_profile.PrintStats(); |
| 539 | 618 |
| 540 LOG(HeapSampleEndEvent("Heap", "allocated")); | 619 LOG(HeapSampleEndEvent("Heap", "allocated")); |
| 541 } | 620 } |
| 542 | 621 |
| 543 | 622 |
| 544 #endif // ENABLE_LOGGING_AND_PROFILING | 623 #endif // ENABLE_LOGGING_AND_PROFILING |
| 545 | 624 |
| 546 | 625 |
| 547 } } // namespace v8::internal | 626 } } // namespace v8::internal |
| OLD | NEW |