Serialize edge counts instead of indexes in heap snapshot.
authoralexeif@chromium.org <alexeif@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 6 Jun 2012 10:57:20 +0000 (10:57 +0000)
committeralexeif@chromium.org <alexeif@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 6 Jun 2012 10:57:20 +0000 (10:57 +0000)
The serialized node structure currently holds an index
of its first containment edge in the edges array.
The index can be quite big (up to 7 digits for large snapshots).
The patch changes the serialization format to pass
node containment edge count instead. For most nodes the count
is just a single digit number.
This reduces serialized snapshot size and therefore its transfer time.

Review URL: https://chromiumcodereview.appspot.com/10534008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11728 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/profile-generator.cc
src/profile-generator.h
test/cctest/test-heap-profiler.cc

index 69ef082..02c67f4 100644 (file)
@@ -3248,7 +3248,6 @@ HeapSnapshot* HeapSnapshotJSONSerializer::CreateFakeSnapshot() {
 
 
 void HeapSnapshotJSONSerializer::SerializeImpl() {
-  List<HeapEntry>& nodes = snapshot_->entries();
   ASSERT(0 == snapshot_->root()->index());
   writer_->AddCharacter('{');
   writer_->AddString("\"snapshot\":{");
@@ -3256,11 +3255,11 @@ void HeapSnapshotJSONSerializer::SerializeImpl() {
   if (writer_->aborted()) return;
   writer_->AddString("},\n");
   writer_->AddString("\"nodes\":[");
-  SerializeNodes(nodes);
+  SerializeNodes();
   if (writer_->aborted()) return;
   writer_->AddString("],\n");
   writer_->AddString("\"edges\":[");
-  SerializeEdges(nodes);
+  SerializeEdges();
   if (writer_->aborted()) return;
   writer_->AddString("],\n");
   writer_->AddString("\"strings\":[");
@@ -3302,9 +3301,9 @@ static int utoa(unsigned value, const Vector<char>& buffer, int buffer_pos) {
 
 void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
                                                bool first_edge) {
-  // The buffer needs space for 3 ints, 3 commas and \0
+  // The buffer needs space for 3 unsigned ints, 3 commas and \0
   static const int kBufferSize =
-      MaxDecimalDigitsIn<sizeof(int)>::kSigned * 3 + 3 + 1;  // NOLINT
+      MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned * 3 + 3 + 1;  // NOLINT
   EmbeddedVector<char, kBufferSize> buffer;
   int edge_name_or_index = edge->type() == HeapGraphEdge::kElement
       || edge->type() == HeapGraphEdge::kHidden
@@ -3324,25 +3323,21 @@ void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge,
 }
 
 
-void HeapSnapshotJSONSerializer::SerializeEdges(const List<HeapEntry>& nodes) {
-  bool first_edge = true;
-  for (int i = 0; i < nodes.length(); ++i) {
-    HeapEntry* entry = &nodes[i];
-    Vector<HeapGraphEdge*> children = entry->children();
-    for (int j = 0; j < children.length(); ++j) {
-      SerializeEdge(children[j], first_edge);
-      first_edge = false;
-      if (writer_->aborted()) return;
-    }
+void HeapSnapshotJSONSerializer::SerializeEdges() {
+  List<HeapGraphEdge*>& edges = snapshot_->children();
+  for (int i = 0; i < edges.length(); ++i) {
+    ASSERT(i == 0 ||
+           edges[i - 1]->from()->index() <= edges[i]->from()->index());
+    SerializeEdge(edges[i], i == 0);
+    if (writer_->aborted()) return;
   }
 }
 
 
-void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry,
-                                               int edges_index) {
-  // The buffer needs space for 5 uint32_t, 5 commas, \n and \0
+void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
+  // The buffer needs space for 5 unsigned ints, 5 commas, \n and \0
   static const int kBufferSize =
-      5 * MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned  // NOLINT
+      5 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned  // NOLINT
       + 5 + 1 + 1;
   EmbeddedVector<char, kBufferSize> buffer;
   int buffer_pos = 0;
@@ -3357,19 +3352,17 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry,
   buffer[buffer_pos++] = ',';
   buffer_pos = utoa(entry->self_size(), buffer, buffer_pos);
   buffer[buffer_pos++] = ',';
-  buffer_pos = utoa(edges_index, buffer, buffer_pos);
+  buffer_pos = utoa(entry->children_count(), buffer, buffer_pos);
   buffer[buffer_pos++] = '\n';
   buffer[buffer_pos++] = '\0';
   writer_->AddString(buffer.start());
 }
 
 
-void HeapSnapshotJSONSerializer::SerializeNodes(const List<HeapEntry>& nodes) {
-  int edges_index = 0;
-  for (int i = 0; i < nodes.length(); ++i) {
-    HeapEntry* entry = &nodes[i];
-    SerializeNode(entry, edges_index);
-    edges_index += entry->children().length() * kEdgeFieldsCount;
+void HeapSnapshotJSONSerializer::SerializeNodes() {
+  List<HeapEntry>& entries = snapshot_->entries();
+  for (int i = 0; i < entries.length(); ++i) {
+    SerializeNode(&entries[i]);
     if (writer_->aborted()) return;
   }
 }
@@ -3393,7 +3386,7 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
         JSON_S("name") ","
         JSON_S("id") ","
         JSON_S("self_size") ","
-        JSON_S("edges_index")) ","
+        JSON_S("edge_count")) ","
     JSON_S("node_types") ":" JSON_A(
         JSON_A(
             JSON_S("hidden") ","
index 6388985..45dc9a4 100644 (file)
@@ -1072,10 +1072,10 @@ class HeapSnapshotJSONSerializer {
   int GetStringId(const char* s);
   int entry_index(HeapEntry* e) { return e->index() * kNodeFieldsCount; }
   void SerializeEdge(HeapGraphEdge* edge, bool first_edge);
-  void SerializeEdges(const List<HeapEntry>& nodes);
+  void SerializeEdges();
   void SerializeImpl();
-  void SerializeNode(HeapEntry* entry, int edges_index);
-  void SerializeNodes(const List<HeapEntry>& nodes);
+  void SerializeNode(HeapEntry* entry);
+  void SerializeNodes();
   void SerializeSnapshot();
   void SerializeString(const unsigned char* s);
   void SerializeStrings();
index 560d004..9d2755d 100644 (file)
@@ -565,7 +565,7 @@ TEST(HeapSnapshotJSONSerialization) {
   // Get node and edge "member" offsets.
   v8::Local<v8::Value> meta_analysis_result = CompileRun(
       "var meta = parsed.snapshot.meta;\n"
-      "var edges_index_offset = meta.node_fields.indexOf('edges_index');\n"
+      "var edge_count_offset = meta.node_fields.indexOf('edge_count');\n"
       "var node_fields_count = meta.node_fields.length;\n"
       "var edge_fields_count = meta.edge_fields.length;\n"
       "var edge_type_offset = meta.edge_fields.indexOf('type');\n"
@@ -575,7 +575,13 @@ TEST(HeapSnapshotJSONSerialization) {
       "    meta.edge_types[edge_type_offset].indexOf('property');\n"
       "var shortcut_type ="
       "    meta.edge_types[edge_type_offset].indexOf('shortcut');\n"
-      "parsed.nodes.concat(0, 0, 0, 0, 0, 0, parsed.edges.length);");
+      "var node_count = parsed.nodes.length / node_fields_count;\n"
+      "var first_edge_indexes = parsed.first_edge_indexes = [];\n"
+      "for (var i = 0, first_edge_index = 0; i < node_count; ++i) {\n"
+      "  first_edge_indexes[i] = first_edge_index;\n"
+      "  first_edge_index += edge_fields_count *\n"
+      "      parsed.nodes[i * node_fields_count + edge_count_offset];\n"
+      "}\n");
   CHECK(!meta_analysis_result.IsEmpty());
 
   // A helper function for processing encoded nodes.
@@ -584,8 +590,9 @@ TEST(HeapSnapshotJSONSerialization) {
       "  var nodes = parsed.nodes;\n"
       "  var edges = parsed.edges;\n"
       "  var strings = parsed.strings;\n"
-      "  for (var i = nodes[pos + edges_index_offset],\n"
-      "      count = nodes[pos + node_fields_count + edges_index_offset];\n"
+      "  var node_ordinal = pos / node_fields_count;\n"
+      "  for (var i = parsed.first_edge_indexes[node_ordinal],\n"
+      "      count = parsed.first_edge_indexes[node_ordinal + 1];\n"
       "      i < count; i += edge_fields_count) {\n"
       "    if (edges[i + edge_type_offset] === prop_type\n"
       "        && strings[edges[i + edge_name_offset]] === prop_name)\n"
@@ -598,8 +605,7 @@ TEST(HeapSnapshotJSONSerialization) {
       "GetChildPosByProperty(\n"
       "  GetChildPosByProperty(\n"
       "    GetChildPosByProperty("
-      "      parsed.edges[parsed.nodes[edges_index_offset]"
-      "                   + edge_to_node_offset],"
+      "      parsed.edges[edge_to_node_offset],"
       "      \"b\", property_type),\n"
       "    \"x\", property_type),"
       "  \"s\", property_type)");