-
Notifications
You must be signed in to change notification settings - Fork 0
/
genskiplist.py
executable file
·171 lines (153 loc) · 4.93 KB
/
genskiplist.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0 or CC0-1.0
"""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<text>\d+)"
r"\s+(?P<data>\d+)"
r"\s+(?P<bss>\d+)"
r"\s+(?P<dec>\d+)"
r"\s+(?P<hex>[0-9A-Fa-f]+)"
r"\s+(?P<filename>[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<usage>\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<usage>\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<usage>\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<project>|mupq|mupq_pqclean)_?"
r"crypto_(?P<type>kem|sign)_"
r"(?P<scheme>[a-zA-Z0-9_\-]+)_"
r"(?P<impl>[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()