Commit 31a0d025 authored by alexeif@chromium.org's avatar alexeif@chromium.org

Serialize edge counts instead of indexes in heap snapshot.

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
parent 911d447b
......@@ -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") ","
......
......@@ -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();
......
......@@ -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)");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment