Revision: 2997
Author: [email protected]
Date: Wed Sep 30 07:20:18 2009
Log: Merge bleeding_edge revisions 2971, 2972 (heap profiler updates) to  
trunk.

My changes in Chromium DevTools are depend on these updates.

Review URL: http://codereview.chromium.org/243045
http://code.google.com/p/v8/source/detail?r=2997

Modified:
  /trunk/src/heap-profiler.cc
  /trunk/src/heap-profiler.h
  /trunk/src/version.cc
  /trunk/test/cctest/test-heap-profiler.cc

=======================================
--- /trunk/src/heap-profiler.cc Wed Sep 23 06:43:07 2009
+++ /trunk/src/heap-profiler.cc Wed Sep 30 07:20:18 2009
@@ -162,30 +162,137 @@
  };


-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);
-  JSObjectsCluster eq = GetCoarseEquivalent(cluster);
+  ASSERT(self_ != NULL);
    JSObjectsRetainerTree::Locator loc;
+  if (JSObjectsCluster::Compare(*self_, cluster) == 0) {
+    current_pair_->refs.Add(JSObjectsCluster(JSObjectsCluster::SELF));
+    return;
+  }
+  JSObjectsCluster eq = GetCoarseEquivalent(cluster);
    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);
  }


@@ -444,44 +561,6 @@
    RetainersPrinter printer;
    DebugPrintStats(&printer);
  }
-
-
-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);
-  }
-}


  //
=======================================
--- /trunk/src/heap-profiler.h  Tue Sep 22 03:00:30 2009
+++ /trunk/src/heap-profiler.h  Wed Sep 30 07:20:18 2009
@@ -53,7 +53,8 @@
    // These special cases are used in retainer profile.
    enum SpecialCase {
      ROOTS = 1,
-    GLOBAL_PROPERTY = 2
+    GLOBAL_PROPERTY = 2,
+    SELF = 3  // This case is used in ClustersCoarser only.
    };

    JSObjectsCluster() : constructor_(NULL), instance_(NULL) {}
@@ -77,6 +78,9 @@
          (a.instance_ == b.instance_ ? 0 : (a.instance_ < b.instance_ ?  
-1 : 1))
          : cons_cmp;
    }
+  static int Compare(const JSObjectsCluster* a, const JSObjectsCluster* b)  
{
+    return Compare(*a, *b);
+  }

    bool is_null() const { return constructor_ == NULL; }
    bool can_be_coarsed() const { return instance_ != NULL; }
@@ -93,6 +97,7 @@
      switch (special) {
        case ROOTS: return Heap::result_symbol();
        case GLOBAL_PROPERTY: return Heap::code_symbol();
+      case SELF: return Heap::catch_var_symbol();
        default:
          UNREACHABLE();
          return NULL;
@@ -183,6 +188,8 @@
      ClusterBackRefs& operator=(const ClusterBackRefs& src);

      static int Compare(const ClusterBackRefs& a, const ClusterBackRefs& b);
+    void SortRefs() { refs.Sort(JSObjectsCluster::Compare); }
+    static void SortRefsIterator(ClusterBackRefs* ref) { ref->SortRefs(); }

      JSObjectsCluster cluster;
      ZoneList<JSObjectsCluster> refs;
@@ -219,6 +226,7 @@
    EqualityTree eq_tree_;
    ClusterBackRefs* current_pair_;
    JSObjectsRetainerTree* current_set_;
+  const JSObjectsCluster* self_;
  };


@@ -242,20 +250,9 @@
    void StoreReference(const JSObjectsCluster& cluster, HeapObject* ref);

   private:
-  // Limit on the number of retainers to be printed per cluster.
-  static const int kMaxRetainersToPrint = 50;
    ZoneScope zscope_;
    JSObjectsRetainerTree retainers_tree_;
    ClustersCoarser coarser_;
-  // TODO(mnaganov): Use some helper class to hold these state variables.
-  JSObjectsClusterTree* coarse_cluster_tree_;
-  Printer* current_printer_;
-  StringStream* current_stream_;
- public:
-  // Used by JSObjectsRetainerTree::ForEach.
-  void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
-  void Call(const JSObjectsCluster& cluster,
-            const NumberAndSizeInfo& number_and_size);
  };


=======================================
--- /trunk/src/version.cc       Wed Sep 30 01:27:10 2009
+++ /trunk/src/version.cc       Wed Sep 30 07:20:18 2009
@@ -35,7 +35,7 @@
  #define MAJOR_VERSION     1
  #define MINOR_VERSION     3
  #define BUILD_NUMBER      13
-#define PATCH_LEVEL       4
+#define PATCH_LEVEL       5
  #define CANDIDATE_VERSION false

  // Define SONAME to have the SCons build the put a specific SONAME into the
=======================================
--- /trunk/test/cctest/test-heap-profiler.cc    Tue Sep 22 03:00:30 2009
+++ /trunk/test/cctest/test-heap-profiler.cc    Wed Sep 30 07:20:18 2009
@@ -74,13 +74,12 @@
  }


-static JSObjectsCluster AddHeapObjectToTree(
-    JSObjectsRetainerTree* tree,
-    i::String* constructor,
-    int instance,
-    JSObjectsCluster* ref1 = NULL,
-    JSObjectsCluster* ref2 = NULL,
-    JSObjectsCluster* ref3 = NULL) {
+static JSObjectsCluster AddHeapObjectToTree(JSObjectsRetainerTree* tree,
+                                            i::String* constructor,
+                                            int instance,
+                                            JSObjectsCluster* ref1 = NULL,
+                                            JSObjectsCluster* ref2 = NULL,
+                                            JSObjectsCluster* ref3 = NULL)  
{
    JSObjectsCluster o(constructor, reinterpret_cast<i::Object*>(instance));
    JSObjectsClusterTree* o_tree = new JSObjectsClusterTree();
    JSObjectsClusterTree::Locator o_loc;
@@ -92,6 +91,16 @@
    loc.set_value(o_tree);
    return o;
  }
+
+
+static void AddSelfReferenceToTree(JSObjectsRetainerTree* tree,
+                                   JSObjectsCluster* self_ref) {
+  JSObjectsRetainerTree::Locator loc;
+  CHECK(tree->Find(*self_ref, &loc));
+  JSObjectsClusterTree::Locator o_loc;
+  CHECK_NE(NULL, loc.value());
+  loc.value()->Insert(*self_ref, &o_loc);
+}


  static inline void CheckEqualsHelper(const char* file, int line,
@@ -121,7 +130,7 @@
    if (JSObjectsCluster::Compare(expected, value) == 0) {
      i::HeapStringAllocator allocator;
      i::StringStream stream(&allocator);
-    stream.Add("#  Expected: ");
+    stream.Add("# !Expected: ");
      expected.DebugPrint(&stream);
      stream.Add("\n#  Found: ");
      value.DebugPrint(&stream);
@@ -243,14 +252,64 @@
    coarser.Process(&tree);

    CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
+  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o11));
    CHECK_EQ(coarser.GetCoarseEquivalent(o11),  
coarser.GetCoarseEquivalent(o12));
    CHECK_EQ(coarser.GetCoarseEquivalent(o21),  
coarser.GetCoarseEquivalent(o22));
    CHECK_NE(coarser.GetCoarseEquivalent(o11),  
coarser.GetCoarseEquivalent(o21));
+  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
    CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
    CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
    CHECK_NE(coarser.GetCoarseEquivalent(o11),  
coarser.GetCoarseEquivalent(p));
    CHECK_NE(coarser.GetCoarseEquivalent(o21),  
coarser.GetCoarseEquivalent(p));
  }
+
+
+TEST(ClustersCoarserSelf) {
+  v8::HandleScope scope;
+  v8::Handle<v8::Context> env = v8::Context::New();
+  env->Enter();
+
+  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
+
+  JSObjectsRetainerTree tree;
+
+  // On the following graph:
+  //
+  // p (self-referencing)
+  //          <- o1     <-
+  // q (self-referencing)   o
+  //          <- o2     <-
+  // r (self-referencing)
+  //
+  // we expect that coarser will deduce equivalences: p ~ q ~ r, o1 ~ o2;
+
+  JSObjectsCluster o =
+      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
+  JSObjectsCluster o1 =
+      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
+  JSObjectsCluster o2 =
+      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
+  JSObjectsCluster p =
+      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o1);
+  AddSelfReferenceToTree(&tree, &p);
+  JSObjectsCluster q =
+      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o1,  
&o2);
+  AddSelfReferenceToTree(&tree, &q);
+  JSObjectsCluster r =
+      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o2);
+  AddSelfReferenceToTree(&tree, &r);
+
+  ClustersCoarser coarser;
+  coarser.Process(&tree);
+
+  CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
+  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o1));
+  CHECK_EQ(coarser.GetCoarseEquivalent(o1),  
coarser.GetCoarseEquivalent(o2));
+  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
+  CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
+  CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
+  CHECK_NE(coarser.GetCoarseEquivalent(o1),  
coarser.GetCoarseEquivalent(p));
+}


  namespace {
@@ -322,7 +381,14 @@
    }
    RetainerProfilePrinter printer;
    ret_profile.DebugPrintStats(&printer);
-  CHECK_EQ("(global property);1,B;2,C;2", printer.GetRetainers("A"));
+  const char* retainers_of_a = printer.GetRetainers("A");
+  // The order of retainers is unspecified, so we check string length, and
+  // verify each retainer separately.
+  CHECK_EQ(static_cast<int>(strlen("(global property);1,B;2,C;2")),
+           static_cast<int>(strlen(retainers_of_a)));
+  CHECK(strstr(retainers_of_a, "(global property);1") != NULL);
+  CHECK(strstr(retainers_of_a, "B;2") != NULL);
+  CHECK(strstr(retainers_of_a, "C;2") != NULL);
    CHECK_EQ("(global property);2", printer.GetRetainers("B"));
    CHECK_EQ("(global property);1", printer.GetRetainers("C"));
  }

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to