[gjs: 4/11] heapgraph: Add ability to label nodes
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs: 4/11] heapgraph: Add ability to label nodes
- Date: Sun, 18 Aug 2019 19:21:53 +0000 (UTC)
commit 724c4a50eb24f67d2662c0d187234ac3650b893b
Author: Philip Chimento <philip chimento gmail com>
Date: Thu Aug 8 22:08:41 2019 -0700
heapgraph: Add ability to label nodes
The profusion of Object or GObject_Object nodes can be quite confusing.
If you add a __heapgraph_name property to an object in your code with a
string value, then it should be visible in the heap dump, and heapgraph
will now detect this situation and display it as a label.
myObj.__heapgraph_name = 'My object';
tools/heapdot.py | 16 ++++++++++------
tools/heapgraph.md | 14 ++++++++++++++
tools/heapgraph.py | 38 +++++++++++++++++++++++++++++++-------
3 files changed, 55 insertions(+), 13 deletions(-)
---
diff --git a/tools/heapdot.py b/tools/heapdot.py
index f455d01c..3f829cb7 100644
--- a/tools/heapdot.py
+++ b/tools/heapdot.py
@@ -126,13 +126,17 @@ def output_dot_file(args, graph, targs, fname):
color = 'red'
style = 'bold'
- if args.no_addr:
- outf.write(' node [label="{0}", color={1}, shape={2}, style="{3}"] q{4};\n'.format(label,
color, shape, style, addr))
- else:
+ node_label = label
+ if not args.no_addr:
+ node_label += '\\njsobj@' + addr
if native:
- outf.write(' node [label="{0}\\njsobj@{4}\\nnative@{5}", color={1}, shape={2}, style="{3}"]
q{4};\n'.format(label, color, shape, style, addr, native))
- else:
- outf.write(' node [label="{0}\\njsobj@{4}", color={1}, shape={2}, style="{3}"]
q{4};\n'.format(label, color, shape, style, addr))
+ node_label += '\\nnative@' + native
+ annotation = graph.annotations.get(addr, None)
+ if annotation:
+ node_label += '\\n\\"{}\\"'.format(annotation)
+
+ node_text = ' node [label="{0}", color={1}, shape={2}, style="{3}"] q{4};\n'.format(node_label,
color, shape, style, addr)
+ outf.write(node_text)
# Edges (relationships)
for origin, destinations in edges.items():
diff --git a/tools/heapgraph.md b/tools/heapgraph.md
index fb5dcd84..c0193a13 100644
--- a/tools/heapgraph.md
+++ b/tools/heapgraph.md
@@ -117,6 +117,20 @@ $ ./heapgraph.py --hide-addr 0x7f6ef022c060 \
$ ./heapgraph.py --hide-node 0x55e93cf5deb0 /home/user/myApp2.heap Object
```
+### Labeling Nodes
+
+It can be hard to see what some nodes mean, especially if all the nodes
+you are interested in are labeled `GObject_Object`.
+Luckily there is a way to label the nodes in your program so that they
+are visible in the heap graph.
+Add a property named `__heapgraph_name` with a simple string value to
+your object:
+```js
+myObj.__heapgraph_name = 'My object';
+```
+Heapgraph will detect this and display the name as part of the node's
+label, e.g. GObject_Object "My object".
+
### Command-Line Arguments
**NOTE:** Command line arguments are subject to change; Check
diff --git a/tools/heapgraph.py b/tools/heapgraph.py
index adec6e4c..bf1ae58e 100755
--- a/tools/heapgraph.py
+++ b/tools/heapgraph.py
@@ -20,6 +20,7 @@ try:
except ImportError:
sys.stderr.write('DOT graph output not available\n')
+NAME_ANNOTATION = '__heapgraph_name'
########################################################
# Command line arguments.
@@ -100,7 +101,7 @@ filt_opts.add_argument('--hide-node', '-hn', dest='hide_nodes', action='append',
help='Don\'t show nodes with labels containing LABEL')
filt_opts.add_argument('--hide-edge', '-he', dest='hide_edges', action='append',
- metavar='LABEL', default=[],
+ metavar='LABEL', default=[NAME_ANNOTATION],
help="Don't show edges labeled LABEL")
@@ -108,7 +109,8 @@ filt_opts.add_argument('--hide-edge', '-he', dest='hide_edges', action='append',
# Heap Patterns
###############################################################################
-GraphAttribs = namedtuple('GraphAttribs', 'edge_labels node_labels roots root_labels weakMapEntries')
+GraphAttribs = namedtuple('GraphAttribs',
+ 'edge_labels node_labels roots root_labels weakMapEntries annotations')
WeakMapEntry = namedtuple('WeakMapEntry', 'weakMap key keyDelegate value')
@@ -119,6 +121,7 @@ wme_regex = re.compile(r'WeakMapEntry map=((?:0x)?[a-zA-Z0-9]+|\(nil\)) key=((?:
func_regex = re.compile('Function(?: ([^/]+)(?:/([<|\w]+))?)?')
gobj_regex = re.compile('([^ ]+) (0x[a-fA-F0-9]+$)')
+atom_regex = re.compile(r'^string <atom: length (?:\d+)> (.*)\r?$')
###############################################################################
# Heap Parsing
@@ -172,6 +175,7 @@ def parse_graph(fobj):
edges = {}
edge_labels = {}
node_labels = {}
+ annotations = {}
def addNode (addr, node_label):
edges[addr] = {}
@@ -192,9 +196,15 @@ def parse_graph(fobj):
e = edge_regex.match(line)
if e:
+ target, edge_label = e.group(1, 3)
+ if edge_label == NAME_ANNOTATION:
+ a = atom_regex.match(node_labels[target])
+ if a:
+ annotations[node_addr] = a.group(1)
+
if (node_addr not in args.hide_addrs and
- e.group(3) not in args.hide_edges):
- addEdge(node_addr, e.group(1), e.group(3))
+ edge_label not in args.hide_edges):
+ addEdge(node_addr, target, edge_label)
else:
node = node_regex.match(line)
@@ -217,7 +227,7 @@ def parse_graph(fobj):
sys.stderr.write('Error: Unknown line: {}\n'.format(line[:-1]))
# yar, should pass the root crud in and wedge it in here, or somewhere
- return [edges, edge_labels, node_labels]
+ return [edges, edge_labels, node_labels, annotations]
def parse_heap(fname):
@@ -230,12 +240,12 @@ def parse_heap(fname):
exit(-1)
[roots, root_labels, weakMapEntries] = parse_roots(fobj)
- [edges, edge_labels, node_labels] = parse_graph(fobj)
+ [edges, edge_labels, node_labels, annotations] = parse_graph(fobj)
fobj.close()
graph = GraphAttribs(edge_labels=edge_labels, node_labels=node_labels,
roots=roots, root_labels=root_labels,
- weakMapEntries=weakMapEntries)
+ weakMapEntries=weakMapEntries, annotations=annotations)
return (edges, graph)
@@ -309,6 +319,7 @@ class style:
BOLD = '\033[1m'
ITALIC = '\033[3m'
UNDERLINE = '\033[4m'
+ PURPLE = '\033[0;36m'
END = '\033[0m'
@@ -356,6 +367,10 @@ def get_node_label(graph, addr):
return label[:50]
+def get_node_annotation(graph, addr):
+ return graph.annotations.get(addr, None)
+
+
def output_tree_graph(graph, data, base='', parent=''):
while data:
addr, children = data.popitem()
@@ -367,6 +382,7 @@ def output_tree_graph(graph, data, base='', parent=''):
edge = graph.root_labels[addr]
node = get_node_label(graph, addr)
+ annotation = get_node_annotation(graph, addr)
has_native = gobj_regex.match(node)
# Color/Style
@@ -390,6 +406,14 @@ def output_tree_graph(graph, data, base='', parent=''):
node = has_native.group(1)
orig += ' native@' + has_native.group(2)
+ # Add the annotation
+ if annotation:
+ if os.isatty(1):
+ node += ' "' + style.PURPLE + annotation + style.END + '"'
+ else:
+ node += ' "' + annotation + '"'
+
+
# Print the path segment
if args.no_addr:
if data:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]