From 6f70a1cd140fbf7752678d1bfc5fa972da4120bf Mon Sep 17 00:00:00 2001 From: Matti Hamalainen Date: Fri, 21 Jan 2022 23:35:33 +0200 Subject: [PATCH] gallium/tools: add option for ignoring junk calls in trace dumper Previously tracediff.sh used postprocessing sed-script to remove unwanted calls from the dump output. Instead of that, add option to parse.py to ignore a list of calls at parsing phase. Currently this list is hardcoded in parse.py. Also clean up the trace model code and pointer tracking a bit to avoid static state in Pointer class. Signed-off-by: Matti Hamalainen Acked-by: Mike Blumenkrantz Reviewed-by: Dylan Baker Part-of: --- src/gallium/tools/trace/dump_state.py | 6 +-- src/gallium/tools/trace/model.py | 51 +++++++++++--------- src/gallium/tools/trace/parse.py | 67 +++++++++++++++++++-------- src/gallium/tools/trace/tracediff.sh | 4 +- 4 files changed, 81 insertions(+), 47 deletions(-) diff --git a/src/gallium/tools/trace/dump_state.py b/src/gallium/tools/trace/dump_state.py index 0d5548d7387..9c439ea02f4 100755 --- a/src/gallium/tools/trace/dump_state.py +++ b/src/gallium/tools/trace/dump_state.py @@ -780,8 +780,8 @@ class Interpreter(parser.SimpleTraceDumper): ('pipe_context', 'transfer_unmap'), )) - def __init__(self, stream, options, formatter): - parser.SimpleTraceDumper.__init__(self, stream, options, formatter) + def __init__(self, stream, options, formatter, state): + parser.SimpleTraceDumper.__init__(self, stream, options, formatter, state) self.objects = {} self.result = None self.globl = Global(self) @@ -878,7 +878,7 @@ class Main(parser.Main): def process_arg(self, stream, options): formatter = format.Formatter(sys.stderr) - parser = Interpreter(stream, options, formatter) + parser = Interpreter(stream, options, formatter, model.TraceStateData()) parser.parse() diff --git a/src/gallium/tools/trace/model.py b/src/gallium/tools/trace/model.py index 943f97b8c1a..0c7130aaa6c 100755 --- a/src/gallium/tools/trace/model.py +++ b/src/gallium/tools/trace/model.py @@ -56,6 +56,14 @@ class ModelOptions: self.__dict__[var] = args.__dict__[var] +class TraceStateData: + + def __init__(self): + self.ptr_list = {} + self.ptr_type_list = {} + self.ptr_types_list = {} + + class Node: def visit(self, visitor): @@ -81,14 +89,10 @@ class Literal(Node): class Blob(Node): def __init__(self, value): - self._rawValue = None - self._hexValue = value + self.value = binascii.a2b_hex(value) def getValue(self): - if self._rawValue is None: - self._rawValue = binascii.a2b_hex(self._hexValue) - self._hexValue = None - return self._rawValue + return self.value def visit(self, visitor): visitor.visit_blob(self) @@ -123,19 +127,18 @@ class Struct(Node): class Pointer(Node): - - ptr_list = {} - ptr_type_list = {} - ptr_types_list = {} + ptr_ignore_list = ["ret", "elem"] - def __init__(self, address, pname): + def __init__(self, state, address, pname): self.address = address + self.pname = pname + self.state = state # Check if address exists in list and if it is a return value address - t1 = address in self.ptr_list + t1 = address in state.ptr_list if t1: - rname = self.ptr_type_list[address] + rname = state.ptr_type_list[address] t2 = rname in self.ptr_ignore_list and pname not in self.ptr_ignore_list else: rname = pname @@ -149,15 +152,18 @@ class Pointer(Node): # Add / update self.adjust_ptr_type_count(pname, 1) - tmp = "{}_{}".format(pname, self.ptr_types_list[pname]) - self.ptr_list[address] = tmp - self.ptr_type_list[address] = pname + tmp = "{}_{}".format(pname, state.ptr_types_list[pname]) + state.ptr_list[address] = tmp + state.ptr_type_list[address] = pname def adjust_ptr_type_count(self, pname, delta): - if pname not in self.ptr_types_list: - self.ptr_types_list[pname] = 0 + if pname not in self.state.ptr_types_list: + self.state.ptr_types_list[pname] = 0 - self.ptr_types_list[pname] += delta + self.state.ptr_types_list[pname] += delta + + def named_address(self): + return self.state.ptr_list[self.address] def visit(self, visitor): visitor.visit_pointer(self) @@ -258,13 +264,13 @@ class PrettyPrinter: def visit_pointer(self, node): if self.options.named_ptrs: - self.formatter.address(node.ptr_list[node.address]) + self.formatter.address(node.named_address()) else: self.formatter.address(node.address) def visit_call(self, node): if not self.options.suppress_variants: - self.formatter.text('%s ' % node.no) + self.formatter.text(f'{node.no} ') if node.klass is not None: self.formatter.function(node.klass + '::' + node.method) @@ -289,8 +295,9 @@ class PrettyPrinter: self.formatter.text(' // time ') node.time.visit(self) + self.formatter.newline() + def visit_trace(self, node): for call in node.calls: call.visit(self) - self.formatter.newline() diff --git a/src/gallium/tools/trace/parse.py b/src/gallium/tools/trace/parse.py index ecd5424e6c1..f86b533cee5 100755 --- a/src/gallium/tools/trace/parse.py +++ b/src/gallium/tools/trace/parse.py @@ -36,6 +36,22 @@ import format from model import * +trace_ignore_calls = set(( + ("pipe_screen", "is_format_supported"), + ("pipe_screen", "get_name"), + ("pipe_screen", "get_vendor"), + ("pipe_screen", "get_param"), + ("pipe_screen", "get_paramf"), + ("pipe_screen", "get_shader_param"), + ("pipe_screen", "get_compute_param"), + ("pipe_screen", "get_disk_shader_cache"), +)) + + +def trace_call_ignore(call): + return (call.klass, call.method) in trace_ignore_calls + + ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF = range(4) @@ -192,15 +208,18 @@ class XmlParser: class TraceParser(XmlParser): - def __init__(self, fp): + def __init__(self, fp, options, state): XmlParser.__init__(self, fp) self.last_call_no = 0 - + self.state = state + self.options = options + def parse(self): self.element_start('trace') while self.token.type not in (ELEMENT_END, EOF): call = self.parse_call() - self.handle_call(call) + if not self.options.ignore_junk or not trace_call_ignore(call): + self.handle_call(call) if self.token.type != EOF: self.element_end('trace') @@ -347,7 +366,7 @@ class TraceParser(XmlParser): address = self.character_data() self.element_end('ptr') - return Pointer(address, pname) + return Pointer(self.state, address, pname) def handle_call(self, call): pass @@ -355,21 +374,20 @@ class TraceParser(XmlParser): class SimpleTraceDumper(TraceParser): - def __init__(self, fp, options, formatter): - TraceParser.__init__(self, fp) + def __init__(self, fp, options, formatter, state): + TraceParser.__init__(self, fp, options, state) self.options = options self.formatter = formatter self.pretty_printer = PrettyPrinter(self.formatter, options) def handle_call(self, call): call.visit(self.pretty_printer) - self.formatter.newline() class TraceDumper(SimpleTraceDumper): - def __init__(self, fp, options, formatter): - SimpleTraceDumper.__init__(self, fp, options, formatter) + def __init__(self, fp, options, formatter, state): + SimpleTraceDumper.__init__(self, fp, options, formatter, state) self.call_stack = [] def handle_call(self, call): @@ -377,12 +395,6 @@ class TraceDumper(SimpleTraceDumper): self.call_stack.append(call) else: call.visit(self.pretty_printer) - self.formatter.newline() - - def dump_calls(self): - for call in self.call_stack: - call.visit(self.pretty_printer) - self.formatter.newline() class ParseOptions(ModelOptions): @@ -390,6 +402,7 @@ class ParseOptions(ModelOptions): def __init__(self, args=None): # Initialize options local to this module self.plain = False + self.ignore_junk = False ModelOptions.__init__(self, args) @@ -425,23 +438,38 @@ class Main: return ParseOptions(args) def get_optparser(self): + estr = "\nList of junk calls:\n" + for klass, call in sorted(trace_ignore_calls): + estr += f" {klass}::{call}\n" + optparser = argparse.ArgumentParser( - description="Parse and dump Gallium trace(s)") + description="Parse and dump Gallium trace(s)", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=estr) + optparser.add_argument("filename", action="extend", nargs="+", type=str, metavar="filename", help="Gallium trace filename (plain or .gz, .bz2)") + optparser.add_argument("-p", "--plain", action="store_const", const=True, default=False, dest="plain", help="disable ANSI color etc. formatting") + optparser.add_argument("-S", "--suppress", action="store_const", const=True, default=False, dest="suppress_variants", help="suppress some variants in output for better diffability") + optparser.add_argument("-N", "--named", action="store_const", const=True, default=False, dest="named_ptrs", help="generate symbolic names for raw pointer values") + optparser.add_argument("-M", "--method-only", action="store_const", const=True, default=False, dest="method_only", help="output only call names without arguments") + optparser.add_argument("-I", "--ignore-junk", + action="store_const", const=True, default=False, + dest="ignore_junk", help="filter out/ignore junk calls (see below)") + return optparser def process_arg(self, stream, options): @@ -450,11 +478,12 @@ class Main: else: formatter = format.DefaultFormatter(sys.stdout) - parser = TraceDumper(stream, options, formatter) - parser.parse() + dump = TraceDumper(stream, options, formatter, TraceStateData()) + dump.parse() if options.named_ptrs: - parser.dump_calls() + for call in dump.call_stack: + call.visit(dump.pretty_printer) if __name__ == '__main__': diff --git a/src/gallium/tools/trace/tracediff.sh b/src/gallium/tools/trace/tracediff.sh index d4aaff7d0d3..4b25ebc6f6b 100755 --- a/src/gallium/tools/trace/tracediff.sh +++ b/src/gallium/tools/trace/tracediff.sh @@ -81,11 +81,9 @@ strip_dump() INFILE="$1" OUTFILE="$2" - python3 "$TRACEDUMP" --plain --suppress \ + python3 "$TRACEDUMP" --plain --suppress --ignore-junk \ "${DUMP_ARGS[@]}" "$INFILE" \ | sed \ - -e '/pipe_screen::is_format_supported/d' \ - -e '/pipe_screen::get_\(shader_\)\?paramf\?/d' \ -e 's/\r$//g' \ -e 's/, /,\n\t/g' \ -e 's/) = /)\n\t= /' \