diff options
Diffstat (limited to 'tools/debug_renamer.py')
-rw-r--r-- | tools/debug_renamer.py | 113 |
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) |