blob: ec5c8bd4002f046438db111db2599918401903ef [file] [log] [blame]
#!/usr/bin/python3
# Copyright 2023 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import sys
# Implement this to process the data.
def process_nodes(nodes):
pass
class Node:
def __init__(self, id, type, name):
self.id = id
assert isinstance(type, str)
self.type = type
assert isinstance(name, str)
self.name = name
self.edges_from = []
self.edges_to = []
class Edge:
def __init__(self, type, from_node, name, to_node):
assert isinstance(type, str)
self.type = type
assert isinstance(from_node, Node)
self.from_node = from_node
assert isinstance(name, str)
self.name = name
assert isinstance(to_node, Node)
self.to_node = to_node
def main():
if len(sys.argv) != 2:
print("Usage: python3 heap-snapshot-processor.py snapshot.heapsnapshot")
exit(1)
f = open(sys.argv[1])
data = json.load(f)
# Documentation of the format (caveat: documentation for name_or_index is
# wrong):
# https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/memory-problems/heap-snapshot-schema
snapshot = data['snapshot']
meta = snapshot['meta']
node_fields = meta['node_fields']
node_field_count = len(node_fields)
node_type_ix = node_fields.index('type')
node_name_ix = node_fields.index('name')
node_id_ix = node_fields.index('id')
node_edge_count_ix = node_fields.index('edge_count')
node_types = meta['node_types']
node_type_strings = node_types[node_type_ix]
edge_fields = meta['edge_fields']
edge_field_count = len(edge_fields)
edge_type_ix = edge_fields.index('type')
edge_name_or_index_ix = edge_fields.index('name_or_index')
edge_to_node_ix = edge_fields.index('to_node')
edge_types = meta['edge_types']
edge_type_strings = edge_types[edge_type_ix]
nodes = data['nodes']
edges = data['edges']
strings = data['strings']
node_objects = dict()
for node_ix in range(0, len(nodes), node_field_count):
node_data = nodes[node_ix:(node_ix + node_field_count)]
node_type = node_type_strings[node_data[node_type_ix]]
node_name = strings[node_data[node_name_ix]]
node_id = node_data[node_id_ix]
node = Node(node_id, node_type, node_name)
node_objects[node_id] = node
edge_ix = 0
for node_ix in range(0, len(nodes), node_field_count):
node_data = nodes[node_ix:(node_ix + node_field_count)]
edge_count = node_data[node_edge_count_ix]
from_node_id = node_data[node_id_ix]
from_node = node_objects[from_node_id]
for e in range(edge_count):
edge_data = edges[edge_ix:(edge_ix + edge_field_count)]
edge_type = edge_type_strings[edge_data[edge_type_ix]]
# The interpretation of edge_name_or_index depends on the edge type.
edge_name_or_index = edge_data[edge_name_or_index_ix]
if edge_type == 'element' or edge_type == 'hidden':
edge_name = str(edge_name_or_index)
elif isinstance(edge_name_or_index, str):
edge_name = edge_name_or_index
else:
edge_name = strings[edge_name_or_index]
# "The index within the nodes array that this edge is connected to."
to_node_ix = edge_data[edge_to_node_ix]
to_node_data = nodes[to_node_ix:(to_node_ix + node_field_count)]
to_node_id = to_node_data[node_id_ix]
to_node = node_objects[to_node_id]
edge = Edge(edge_type, from_node, edge_name, to_node)
from_node.edges_from.append(edge)
to_node.edges_to.append(edge)
edge_ix += edge_field_count
process_nodes(node_objects)
if __name__ == '__main__':
main()