diff --git a/osaca/frontend.py b/osaca/frontend.py index 19814c3..06b55e7 100755 --- a/osaca/frontend.py +++ b/osaca/frontend.py @@ -201,6 +201,78 @@ class Frontend(object): + self.loopcarried_dependencies(kernel_dg.get_loopcarried_dependencies()) ) + def full_analysis_dict( + self, + kernel, + kernel_dg: KernelDG, + arch_warning=False, + length_warning=False, + lcd_warning=False, + ): + warnings = [] + + if arch_warning: + warnings.append("ArchWarning") + + if length_warning: + warnings.append("LengthWarning") + + if lcd_warning: + warnings.append("LcdWarning") + + if INSTR_FLAGS.TP_UNKWN in [flag for instr in kernel for flag in instr["flags"]]: + warnings.append("UnknownInstrWarning") + + tp_sum = ArchSemantics.get_throughput_sum(kernel) or kernel[0]["port_pressure"] + cp_kernel = kernel_dg.get_critical_path() + + dep_dict = kernel_dg.get_loopcarried_dependencies() + lcd_sum = 0.0 + if dep_dict: + longest_lcd = max(dep_dict, key=lambda ln: dep_dict[ln]["latency"]) + lcd_sum = dep_dict[longest_lcd]["latency"] + + return { + "Header": self._header_report_dict(), + "Warnings": warnings, + "Kernel": [ + { + "Line": re.sub(r"\s+", " ", x["line"].strip()), + "Flags": list(x["flags"]), + "Instruction": x["instruction"], + "Label": x["label"], + "Latency": x["latency"], + "LatencyCP": x["latency_cp"], + "LatencyLCD": x["latency_lcd"], + "Throughput": float(x["throughput"]), + "LatencyWithoutLoad": x["latency_wo_load"], + "PortPressure": { + self._machine_model.get_ports()[i]: v + for i, v in enumerate(x["port_pressure"]) + }, + "PortUops": [ + { + "Ports": list(y[1]), + "Cycles": y[0], + } + for y in x["port_uops"] + ], + } + for x in kernel + ], + "Summary": { + "PortPressure": { + self._machine_model.get_ports()[i]: v for i, v in enumerate(tp_sum) + }, + "CriticalPath": sum([x["latency_cp"] for x in cp_kernel]), + "LCD": lcd_sum, + }, + "Target": { + "Name": self._arch.upper(), + "Ports": list(self._machine_model.get_ports()), + }, + } + def combined_view( self, kernel, @@ -449,6 +521,14 @@ class Frontend(object): ) return header + "\n" + def _header_report_dict(self): + """Return header information in a dictionary format""" + return { + "Version": _get_version("__init__.py"), + "FileName": self._filename, + "Timestamp": dt.utcnow().strftime("%Y-%m-%d %H:%M:%S"), + } + def _symbol_map(self): """Prints instruction flag map.""" symbol_dict = { diff --git a/osaca/osaca.py b/osaca/osaca.py index f5f9bcf..a6e57e9 100755 --- a/osaca/osaca.py +++ b/osaca/osaca.py @@ -7,6 +7,8 @@ import re import sys from functools import lru_cache +import ruamel.yaml + from osaca.db_interface import import_benchmark_output, sanity_check from osaca.frontend import Frontend from osaca.parser import BaseParser, ParserAArch64, ParserX86ATT @@ -188,6 +190,13 @@ def create_parser(parser=None): type=argparse.FileType("w"), help="Write analysis to this file (default to stdout).", ) + parser.add_argument( + "--yaml-out", + default=None, + dest="yaml_out", + type=argparse.FileType("w"), + help="Write YAML analysis to this file", + ) parser.add_argument( "file", type=argparse.FileType("r"), @@ -360,6 +369,17 @@ def inspect(args, output_file=sys.stdout): ), file=output_file, ) + if args.yaml_out is not None: + ruamel.yaml.dump( + frontend.full_analysis_dict( + kernel, + kernel_graph, + arch_warning=print_arch_warning, + length_warning=print_length_warning, + lcd_warning=kernel_graph.timed_out, + ), + args.yaml_out, + ) def run(args, output_file=sys.stdout):