#!/usr/bin/env python3 """This script is used to generate the skiplist.py files in pqm{4,3}. It takes the output files from the mps2-an386 target, when run via the make script, i.e., compile pqm{4,3} with the mps2-an38{6,5} plattform and the run-stack-tests targets (remember to backup your benchmark results, if you want to keep them!): cp -r benchmarks benchmarks.bak make clean # Because this will delete it make PLATFORM=mps2-an386 -j4 run-stack-tests find benchmarks -name frommake -exec python3 mupq/genskiplist.py {} + > skiplist.py You can also simply update a single scheme: make PLATFORM=mps2-an386 benchmarks/stack/crypto_kem/mysuperscheme/opt/frommake python3 mupq/genskiplist.py benchmarks/stack/crypto_kem/mysuperscheme/opt/frommake """ import argparse import pprint import re import sys def parse_arguments(): parser = argparse.ArgumentParser( description="Generate a skiplist.py", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=__doc__ ) parser.add_argument( "inputs", help="Stack benchmark output of mps2 platform", nargs="+", type=argparse.FileType("r"), ) parser.add_argument( "-r", "--round", help="Round up the usage to N bytes", default=1024, type=int, metavar="N", ) parser.add_argument( "-m", "--margin", help="Add N bytes of additional stack margin", default=32, type=int, metavar="M", ) return parser.parse_args() def parse_flashsize(contents): match = re.search( r"^\s+(?P\d+)" r"\s+(?P\d+)" r"\s+(?P\d+)" r"\s+(?P\d+)" r"\s+(?P[0-9A-Fa-f]+)" r"\s+(?P[a-zA-Z0-9_\-/\.]+)", contents, re.MULTILINE, ) if match is None: raise Exception("Size output not found!") text = int(match.group("text")) data = int(match.group("data")) bss = int(match.group("bss")) return match.group("filename"), text + data, data + bss def parse_stackusage(contents): match = re.search( r"^keypair stack usage:\s+(?P\d+)", contents, re.MULTILINE, ) if match is None: raise Exception("keypair usage not found") keypair = int(match.group("usage")) match = re.search( r"^(sign|decaps) stack usage:\s+(?P\d+)", contents, re.MULTILINE, ) if match is None: raise Exception("private-op usage not found") private = int(match.group("usage")) match = re.search( r"^(verify|decaps) stack usage:\s+(?P\d+)", contents, re.MULTILINE, ) if match is None: raise Exception("public-op usage not found") public = int(match.group("usage")) return max(keypair, public, private) def parse_filename(filename): match = re.match( r"elf/(?P|mupq|mupq_pqclean)_?" r"crypto_(?Pkem|sign)_" r"(?P[a-zA-Z0-9_\-]+)_" r"(?P[a-zA-Z0-9_\-]+)" r"_stack\.elf", filename, ) if match is None: raise Exception("Can't parse filename!") project = match.group("project") scheme = match.group("scheme") impl = match.group("impl") return project, scheme, impl def roundto(x, to): return x + (to - x % to) def main(): args = parse_arguments() schemes = [] for f in args.inputs: contents = f.read() # Check for failed test try: filename, flashsize, ramsize = parse_flashsize(contents) project, scheme, impl = parse_filename(filename) match = re.search("HardFault", contents, re.MULTILINE) if match is None: stackusage = parse_stackusage(contents) else: stackusage = 4096 * 1024 except Exception as e: if "usage not found" in str(e): stackusage = 4096 * 1024 else: print(f"Error during parsing file {f.name}: {e}", file=sys.stderr) continue memoryusage = roundto(stackusage + ramsize + args.margin, args.round) print( f"Scheme: {scheme} Context: {project} Implementation: {impl} Flashsize: {flashsize} Memorysize: {memoryusage}", file=sys.stderr, ) schemes.append( { "scheme": scheme, "implementation": impl, # 'project': (project + "/") if len(project) > 0 else "", "estmemory": memoryusage, } ) # if project == "": # del schemes[-1]['project'] print("skip_list = [") for it in schemes: print( " " + pprint.pformat(it, indent=4, compact=False, sort_dicts=False, width=110), end=",\n", ) print("]") if __name__ == "__main__": main()