| Index: src/heap-profiler.cc
|
| ===================================================================
|
| --- src/heap-profiler.cc (revision 2996)
|
| +++ src/heap-profiler.cc (working copy)
|
| @@ -162,31 +162,138 @@
|
| };
|
|
|
|
|
| -class RetainerTreePrinter BASE_EMBEDDED {
|
| +// Visitor for printing a cluster tree.
|
| +class ClusterTreePrinter BASE_EMBEDDED {
|
| public:
|
| - explicit RetainerTreePrinter(StringStream* stream) : stream_(stream) {}
|
| + explicit ClusterTreePrinter(StringStream* stream) : stream_(stream) {}
|
| void Call(const JSObjectsCluster& cluster,
|
| const NumberAndSizeInfo& number_and_size) {
|
| Print(stream_, cluster, number_and_size);
|
| }
|
| static void Print(StringStream* stream,
|
| const JSObjectsCluster& cluster,
|
| - const NumberAndSizeInfo& numNNber_and_size);
|
| + const NumberAndSizeInfo& number_and_size);
|
|
|
| private:
|
| StringStream* stream_;
|
| };
|
|
|
|
|
| -void RetainerTreePrinter::Print(StringStream* stream,
|
| - const JSObjectsCluster& cluster,
|
| - const NumberAndSizeInfo& number_and_size) {
|
| +void ClusterTreePrinter::Print(StringStream* stream,
|
| + const JSObjectsCluster& cluster,
|
| + const NumberAndSizeInfo& number_and_size) {
|
| stream->Put(',');
|
| cluster.Print(stream);
|
| stream->Add(";%d", number_and_size.number());
|
| }
|
|
|
|
|
| +// Visitor for printing a retainer tree.
|
| +class SimpleRetainerTreePrinter BASE_EMBEDDED {
|
| + public:
|
| + explicit SimpleRetainerTreePrinter(RetainerHeapProfile::Printer* printer)
|
| + : printer_(printer) {}
|
| + void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
|
| +
|
| + private:
|
| + RetainerHeapProfile::Printer* printer_;
|
| +};
|
| +
|
| +
|
| +void SimpleRetainerTreePrinter::Call(const JSObjectsCluster& cluster,
|
| + JSObjectsClusterTree* tree) {
|
| + HeapStringAllocator allocator;
|
| + StringStream stream(&allocator);
|
| + ClusterTreePrinter retainers_printer(&stream);
|
| + tree->ForEach(&retainers_printer);
|
| + printer_->PrintRetainers(cluster, stream);
|
| +}
|
| +
|
| +
|
| +// Visitor for aggregating references count of equivalent clusters.
|
| +class RetainersAggregator BASE_EMBEDDED {
|
| + public:
|
| + RetainersAggregator(ClustersCoarser* coarser, JSObjectsClusterTree* dest_tree)
|
| + : coarser_(coarser), dest_tree_(dest_tree) {}
|
| + void Call(const JSObjectsCluster& cluster,
|
| + const NumberAndSizeInfo& number_and_size);
|
| +
|
| + private:
|
| + ClustersCoarser* coarser_;
|
| + JSObjectsClusterTree* dest_tree_;
|
| +};
|
| +
|
| +
|
| +void RetainersAggregator::Call(const JSObjectsCluster& cluster,
|
| + const NumberAndSizeInfo& number_and_size) {
|
| + JSObjectsCluster eq = coarser_->GetCoarseEquivalent(cluster);
|
| + if (eq.is_null()) eq = cluster;
|
| + JSObjectsClusterTree::Locator loc;
|
| + dest_tree_->Insert(eq, &loc);
|
| + NumberAndSizeInfo aggregated_number = loc.value();
|
| + aggregated_number.increment_number(number_and_size.number());
|
| + loc.set_value(aggregated_number);
|
| +}
|
| +
|
| +
|
| +// Visitor for printing retainers tree. Aggregates equivalent retainer clusters.
|
| +class AggregatingRetainerTreePrinter BASE_EMBEDDED {
|
| + public:
|
| + AggregatingRetainerTreePrinter(ClustersCoarser* coarser,
|
| + RetainerHeapProfile::Printer* printer)
|
| + : coarser_(coarser), printer_(printer) {}
|
| + void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
|
| +
|
| + private:
|
| + ClustersCoarser* coarser_;
|
| + RetainerHeapProfile::Printer* printer_;
|
| +};
|
| +
|
| +
|
| +void AggregatingRetainerTreePrinter::Call(const JSObjectsCluster& cluster,
|
| + JSObjectsClusterTree* tree) {
|
| + if (!coarser_->GetCoarseEquivalent(cluster).is_null()) return;
|
| + JSObjectsClusterTree dest_tree_;
|
| + RetainersAggregator retainers_aggregator(coarser_, &dest_tree_);
|
| + tree->ForEach(&retainers_aggregator);
|
| + HeapStringAllocator allocator;
|
| + StringStream stream(&allocator);
|
| + ClusterTreePrinter retainers_printer(&stream);
|
| + dest_tree_.ForEach(&retainers_printer);
|
| + printer_->PrintRetainers(cluster, stream);
|
| +}
|
| +
|
| +
|
| +// A helper class for building a retainers tree, that aggregates
|
| +// all equivalent clusters.
|
| +class RetainerTreeAggregator BASE_EMBEDDED {
|
| + public:
|
| + explicit RetainerTreeAggregator(ClustersCoarser* coarser)
|
| + : coarser_(coarser) {}
|
| + void Process(JSObjectsRetainerTree* input_tree) {
|
| + input_tree->ForEach(this);
|
| + }
|
| + void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
|
| + JSObjectsRetainerTree& output_tree() { return output_tree_; }
|
| +
|
| + private:
|
| + ClustersCoarser* coarser_;
|
| + JSObjectsRetainerTree output_tree_;
|
| +};
|
| +
|
| +
|
| +void RetainerTreeAggregator::Call(const JSObjectsCluster& cluster,
|
| + JSObjectsClusterTree* tree) {
|
| + JSObjectsCluster eq = coarser_->GetCoarseEquivalent(cluster);
|
| + if (eq.is_null()) return;
|
| + JSObjectsRetainerTree::Locator loc;
|
| + if (output_tree_.Insert(eq, &loc)) {
|
| + loc.set_value(new JSObjectsClusterTree());
|
| + }
|
| + RetainersAggregator retainers_aggregator(coarser_, loc.value());
|
| + tree->ForEach(&retainers_aggregator);
|
| +}
|
| +
|
| } // namespace
|
|
|
|
|
| @@ -226,6 +333,8 @@
|
| accumulator->Add("(roots)");
|
| } else if (constructor_ == FromSpecialCase(GLOBAL_PROPERTY)) {
|
| accumulator->Add("(global property)");
|
| + } else if (constructor_ == FromSpecialCase(SELF)) {
|
| + accumulator->Add("(self)");
|
| } else {
|
| SmartPointer<char> s_name(
|
| constructor_->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL));
|
| @@ -286,9 +395,11 @@
|
|
|
|
|
| ClustersCoarser::ClustersCoarser()
|
| - : zscope_(DELETE_ON_EXIT),
|
| - sim_list_(ClustersCoarser::kInitialSimilarityListCapacity),
|
| - current_pair_(NULL) {
|
| + : zscope_(DELETE_ON_EXIT),
|
| + sim_list_(ClustersCoarser::kInitialSimilarityListCapacity),
|
| + current_pair_(NULL),
|
| + current_set_(NULL),
|
| + self_(NULL) {
|
| }
|
|
|
|
|
| @@ -299,10 +410,12 @@
|
| ASSERT(current_pair_ == NULL);
|
| current_pair_ = &pair;
|
| current_set_ = new JSObjectsRetainerTree();
|
| + self_ = &cluster;
|
| tree->ForEach(this);
|
| sim_list_.Add(pair);
|
| current_pair_ = NULL;
|
| current_set_ = NULL;
|
| + self_ = NULL;
|
| }
|
|
|
|
|
| @@ -310,8 +423,13 @@
|
| const NumberAndSizeInfo& number_and_size) {
|
| ASSERT(current_pair_ != NULL);
|
| ASSERT(current_set_ != NULL);
|
| + ASSERT(self_ != NULL);
|
| + JSObjectsRetainerTree::Locator loc;
|
| + if (JSObjectsCluster::Compare(*self_, cluster) == 0) {
|
| + current_pair_->refs.Add(JSObjectsCluster(JSObjectsCluster::SELF));
|
| + return;
|
| + }
|
| JSObjectsCluster eq = GetCoarseEquivalent(cluster);
|
| - JSObjectsRetainerTree::Locator loc;
|
| if (!eq.is_null()) {
|
| if (current_set_->Find(eq, &loc)) return;
|
| current_pair_->refs.Add(eq);
|
| @@ -336,11 +454,7 @@
|
|
|
| int ClustersCoarser::DoProcess(JSObjectsRetainerTree* tree) {
|
| tree->ForEach(this);
|
| - // To sort similarity list properly, references list of a cluster is
|
| - // required to be sorted, thus 'O1 <- A, B' and 'O2 <- B, A' would
|
| - // be considered equivalent. But we don't sort them explicitly
|
| - // because we know that they come from a splay tree traversal, so
|
| - // they are already sorted.
|
| + sim_list_.Iterate(ClusterBackRefs::SortRefsIterator);
|
| sim_list_.Sort(ClusterBackRefsCmp);
|
| return FillEqualityTree();
|
| }
|
| @@ -356,8 +470,9 @@
|
|
|
| bool ClustersCoarser::HasAnEquivalent(const JSObjectsCluster& cluster) {
|
| // Return true for coarsible clusters that have a non-identical equivalent.
|
| - return cluster.can_be_coarsed() &&
|
| - JSObjectsCluster::Compare(cluster, GetCoarseEquivalent(cluster)) != 0;
|
| + if (!cluster.can_be_coarsed()) return false;
|
| + JSObjectsCluster eq = GetCoarseEquivalent(cluster);
|
| + return !eq.is_null() && JSObjectsCluster::Compare(cluster, eq) != 0;
|
| }
|
|
|
|
|
| @@ -395,10 +510,7 @@
|
|
|
|
|
| RetainerHeapProfile::RetainerHeapProfile()
|
| - : zscope_(DELETE_ON_EXIT),
|
| - coarse_cluster_tree_(NULL),
|
| - current_printer_(NULL),
|
| - current_stream_(NULL) {
|
| + : zscope_(DELETE_ON_EXIT) {
|
| JSObjectsCluster roots(JSObjectsCluster::ROOTS);
|
| ReferencesExtractor extractor(roots, this);
|
| Heap::IterateRoots(&extractor);
|
| @@ -433,10 +545,15 @@
|
| void RetainerHeapProfile::DebugPrintStats(
|
| RetainerHeapProfile::Printer* printer) {
|
| coarser_.Process(&retainers_tree_);
|
| - ASSERT(current_printer_ == NULL);
|
| - current_printer_ = printer;
|
| - retainers_tree_.ForEach(this);
|
| - current_printer_ = NULL;
|
| + // Print clusters that have no equivalents, aggregating their retainers.
|
| + AggregatingRetainerTreePrinter agg_printer(&coarser_, printer);
|
| + retainers_tree_.ForEach(&agg_printer);
|
| + // Now aggregate clusters that have equivalents...
|
| + RetainerTreeAggregator aggregator(&coarser_);
|
| + aggregator.Process(&retainers_tree_);
|
| + // ...and print them.
|
| + SimpleRetainerTreePrinter s_printer(printer);
|
| + aggregator.output_tree().ForEach(&s_printer);
|
| }
|
|
|
|
|
| @@ -446,44 +563,6 @@
|
| }
|
|
|
|
|
| -void RetainerHeapProfile::Call(const JSObjectsCluster& cluster,
|
| - JSObjectsClusterTree* tree) {
|
| - // First level of retainer graph.
|
| - if (coarser_.HasAnEquivalent(cluster)) return;
|
| - ASSERT(current_stream_ == NULL);
|
| - HeapStringAllocator allocator;
|
| - StringStream stream(&allocator);
|
| - current_stream_ = &stream;
|
| - ASSERT(coarse_cluster_tree_ == NULL);
|
| - coarse_cluster_tree_ = new JSObjectsClusterTree();
|
| - tree->ForEach(this);
|
| - // Print aggregated counts and sizes.
|
| - RetainerTreePrinter printer(current_stream_);
|
| - coarse_cluster_tree_->ForEach(&printer);
|
| - coarse_cluster_tree_ = NULL;
|
| - current_printer_->PrintRetainers(cluster, stream);
|
| - current_stream_ = NULL;
|
| -}
|
| -
|
| -
|
| -void RetainerHeapProfile::Call(const JSObjectsCluster& cluster,
|
| - const NumberAndSizeInfo& number_and_size) {
|
| - ASSERT(coarse_cluster_tree_ != NULL);
|
| - ASSERT(current_stream_ != NULL);
|
| - JSObjectsCluster eq = coarser_.GetCoarseEquivalent(cluster);
|
| - if (eq.is_null()) {
|
| - RetainerTreePrinter::Print(current_stream_, cluster, number_and_size);
|
| - } else {
|
| - // Aggregate counts and sizes for equivalent clusters.
|
| - JSObjectsClusterTree::Locator loc;
|
| - coarse_cluster_tree_->Insert(eq, &loc);
|
| - NumberAndSizeInfo eq_number_and_size = loc.value();
|
| - eq_number_and_size.increment_number(number_and_size.number());
|
| - loc.set_value(eq_number_and_size);
|
| - }
|
| -}
|
| -
|
| -
|
| //
|
| // HeapProfiler class implementation.
|
| //
|
|
|