aboutsummaryrefslogtreecommitdiffstats
path: root/tools/debug_renamer.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/debug_renamer.py')
-rw-r--r--tools/debug_renamer.py113
1 files changed, 113 insertions, 0 deletions
diff --git a/tools/debug_renamer.py b/tools/debug_renamer.py
new file mode 100644
index 000000000..ec777388b
--- /dev/null
+++ b/tools/debug_renamer.py
@@ -0,0 +1,113 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import re
+import sys
+from argparse import ArgumentParser, FileType, RawTextHelpFormatter
+from collections import OrderedDict
+
+DESC = """
+debug_renamer.py
+================
+
+This script renames object addresses in debug protocols to useful names.
+Comparing output will produce minimal deltas.
+
+
+Problem:
+--------
+
+In the debugging output of PYSIDE-79, we want to study different output
+before and after applying some change to the implementation.
+
+We have support from the modified Python interpreter that creates full
+traces of every object creation and increment/decrement of refcounts.
+
+The comparison between "before" and "after" gets complicated because
+the addresses of objects do not compare well.
+
+
+Input format:
+-------------
+The Python output lines can be freely formatted.
+
+Any line which contains "0x.." followed by some name will be changed,
+all others are left alone.
+
+
+To Do List
+----------
+
+Names of objects which are already deleted should be monitored and
+not by chance be re-used. We need to think of a way to specify deletion.
+"""
+
+
+def make_name(typename, name_pos):
+ """
+ Build a name by using uppercase letters and numbers
+ """
+ if name_pos < 26:
+ name = chr(ord("A") + name_pos)
+ return f"{typename}_{name}"
+ return f"{typename}_{str(name_pos)}"
+
+
+known_types = {}
+pattern = r"0x\w+\s+\S+" # hex word followed by non-WS
+rex = re.compile(pattern, re.IGNORECASE)
+
+
+def rename_hexval(line):
+ if not (res := rex.search(line)):
+ return line
+ start_pos, end_pos = res.start(), res.end()
+ beg, mid, end = line[:start_pos], line[start_pos:end_pos], line[end_pos:]
+ object_id, typename = mid.split()
+ if int(object_id, 16) == 0:
+ return(f"{beg}{typename}_NULL{end}")
+ if typename not in known_types:
+ known_types[typename] = OrderedDict()
+ obj_store = known_types[typename]
+ if object_id not in obj_store:
+ obj_store[object_id] = make_name(typename, len(obj_store))
+ return(f"{beg}{obj_store[object_id]}{end}")
+
+
+def hide_floatval(line):
+ return re.sub(r"\d+\.\d+", "<float>", line)
+
+
+def process_all_lines(options):
+ """
+ Process all lines from fin to fout.
+ The caller is responsible of opening and closing files if at all.
+ """
+ fi, fo = options.input, options.output
+ rename = options.rename
+ float_ = options.float
+ while line := fi.readline():
+ if rename:
+ line = rename_hexval(line)
+ if float_:
+ line = hide_floatval(line)
+ fo.write(line)
+
+
+def create_argument_parser(desc):
+ parser = ArgumentParser(description=desc, formatter_class=RawTextHelpFormatter)
+ parser.add_argument("--rename", "-r", action="store_true",
+ help="Rename hex value and following word to a readable f'{word}_{anum}'")
+ parser.add_argument("--float", "-f", action="store_true",
+ help="Replace timing numbers by '<float>' (for comparing ctest output)")
+ parser.add_argument("--input", "-i", nargs="?", type=FileType("r"), default=sys.stdin,
+ help="Use the specified file instead of sys.stdin")
+ parser.add_argument("--output", "-o", nargs="?", type=FileType("w"), default=sys.stdout,
+ help="Use the specified file instead of sys.stdout")
+ return parser
+
+
+if __name__ == "__main__":
+ argument_parser = create_argument_parser(DESC)
+ options = argument_parser.parse_args()
+ process_all_lines(options)