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 |