potassco-benchmark-tool 2.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- benchmarktool/__init__.py +0 -0
- benchmarktool/entry_points.py +417 -0
- benchmarktool/init/programs/gcat.sh +24 -0
- benchmarktool/init/runscripts/runscript-all.xml +49 -0
- benchmarktool/init/runscripts/runscript-dist.xml +20 -0
- benchmarktool/init/runscripts/runscript-example.xml +31 -0
- benchmarktool/init/runscripts/runscript-seq.xml +27 -0
- benchmarktool/init/templates/seq-generic-single.sh +27 -0
- benchmarktool/init/templates/seq-generic-zip.sh +14 -0
- benchmarktool/init/templates/seq-generic.sh +12 -0
- benchmarktool/init/templates/single.dist +25 -0
- benchmarktool/result/__init__.py +0 -0
- benchmarktool/result/ipynb_gen.py +477 -0
- benchmarktool/result/ods_config.py +42 -0
- benchmarktool/result/ods_gen.py +714 -0
- benchmarktool/result/parser.py +167 -0
- benchmarktool/result/result.py +453 -0
- benchmarktool/resultparser/__init__.py +0 -0
- benchmarktool/resultparser/clasp.py +88 -0
- benchmarktool/runscript/__init__.py +0 -0
- benchmarktool/runscript/parser.py +477 -0
- benchmarktool/runscript/runscript.py +1481 -0
- benchmarktool/tools.py +82 -0
- potassco_benchmark_tool-2.1.1.dist-info/METADATA +112 -0
- potassco_benchmark_tool-2.1.1.dist-info/RECORD +29 -0
- potassco_benchmark_tool-2.1.1.dist-info/WHEEL +5 -0
- potassco_benchmark_tool-2.1.1.dist-info/entry_points.txt +2 -0
- potassco_benchmark_tool-2.1.1.dist-info/licenses/LICENSE +21 -0
- potassco_benchmark_tool-2.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Created on Jan 17, 2010
|
|
3
|
+
|
|
4
|
+
@author: Roland Kaminski
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
import sys
|
|
10
|
+
from typing import TYPE_CHECKING, Any
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from benchmarktool.runscript import runscript # nocoverage
|
|
14
|
+
|
|
15
|
+
clasp_re = {
|
|
16
|
+
"models": ("float", re.compile(r"^(c )?Models[ ]*:[ ]*(?P<val>[0-9]+)\+?[ ]*$")),
|
|
17
|
+
"choices": ("float", re.compile(r"^(c )?Choices[ ]*:[ ]*(?P<val>[0-9]+)\+?[ ]*$")),
|
|
18
|
+
"time": ("float", re.compile(r"^\[runlim\] real:\s*(?P<val>[0-9]+(\.[0-9]+)?)")),
|
|
19
|
+
"conflicts": ("float", re.compile(r"^(c )?Conflicts[ ]*:[ ]*(?P<val>[0-9]+)\+?.*$")),
|
|
20
|
+
"restarts": ("float", re.compile(r"^(c )?Restarts[ ]*:[ ]*(?P<val>[0-9]+)\+?.*$")),
|
|
21
|
+
"optimum": ("string", re.compile(r"^(c )?Optimization[ ]*:[ ]*(?P<val>(-?[0-9]+)( -?[0-9]+)*)[ ]*$")),
|
|
22
|
+
"status": ("string", re.compile(r"^(s )?(?P<val>SATISFIABLE|UNSATISFIABLE|UNKNOWN|OPTIMUM FOUND)[ ]*$")),
|
|
23
|
+
"interrupted": ("string", re.compile(r"(c )?(?P<val>INTERRUPTED)")),
|
|
24
|
+
"error": ("string", re.compile(r"^\*\*\* clasp ERROR: (?P<val>.*)$")),
|
|
25
|
+
"rstatus": ("string", re.compile(r"^\[runlim\] status:\s*(?P<val>.*)$")),
|
|
26
|
+
"mem": ("float", re.compile(r"^\[runlim\] space:\s*(?P<val>[0-9]+(\.[0-9]+)?) MB")),
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# penalized-average-runtime score constant
|
|
30
|
+
PAR = 2
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# pylint: disable=unused-argument
|
|
34
|
+
def parse(
|
|
35
|
+
root: str, runspec: "runscript.Runspec", instance: "runscript.Benchmark.Instance"
|
|
36
|
+
) -> dict[str, tuple[str, Any]]:
|
|
37
|
+
"""
|
|
38
|
+
Extracts some clasp statistics.
|
|
39
|
+
|
|
40
|
+
Attributes:
|
|
41
|
+
root (str): The folder with results.
|
|
42
|
+
runspec (Runspec): The run specification of the benchmark.
|
|
43
|
+
instance (Benchmark.Instance): The benchmark instance.
|
|
44
|
+
"""
|
|
45
|
+
timeout = runspec.project.job.timeout
|
|
46
|
+
res: dict[str, tuple[str, Any]] = {"time": ("float", timeout)}
|
|
47
|
+
for f in ["runsolver.solver", "runsolver.watcher"]:
|
|
48
|
+
with open(os.path.join(root, f), errors="ignore", encoding="utf-8") as file:
|
|
49
|
+
for line in file:
|
|
50
|
+
for val, reg in clasp_re.items():
|
|
51
|
+
m = reg[1].match(line)
|
|
52
|
+
if m:
|
|
53
|
+
res[val] = (reg[0], float(m.group("val")) if reg[0] == "float" else m.group("val"))
|
|
54
|
+
|
|
55
|
+
if "rstatus" in res and res["rstatus"][1] == "out of memory":
|
|
56
|
+
res["error"] = ("string", "std::bad_alloc")
|
|
57
|
+
res["status"] = ("string", "UNKNOWN")
|
|
58
|
+
result: dict[str, tuple[str, Any]] = {}
|
|
59
|
+
error = "status" not in res or ("error" in res and res["error"][1] != "std::bad_alloc")
|
|
60
|
+
memout = "error" in res and res["error"][1] == "std::bad_alloc"
|
|
61
|
+
status = res["status"][1] if "status" in res else None
|
|
62
|
+
timedout = (
|
|
63
|
+
memout
|
|
64
|
+
or error
|
|
65
|
+
or status == "UNKNOWN"
|
|
66
|
+
or (status == "SATISFIABLE" and "optimum" in res)
|
|
67
|
+
or res["time"][1] >= timeout
|
|
68
|
+
or "interrupted" in res
|
|
69
|
+
)
|
|
70
|
+
if timedout:
|
|
71
|
+
res["time"] = ("float", timeout)
|
|
72
|
+
if error:
|
|
73
|
+
sys.stderr.write("*** ERROR: Run {0} failed with unrecognized status or error!\n".format(root))
|
|
74
|
+
result["error"] = ("float", int(error))
|
|
75
|
+
result["timeout"] = ("float", int(timedout))
|
|
76
|
+
result["memout"] = ("float", int(memout))
|
|
77
|
+
|
|
78
|
+
if "optimum" in res and not " " in res["optimum"][1]:
|
|
79
|
+
result["optimum"] = ("float", float(res["optimum"][1]))
|
|
80
|
+
del res["optimum"]
|
|
81
|
+
if "interrupted" in res:
|
|
82
|
+
del res["interrupted"]
|
|
83
|
+
if "error" in res:
|
|
84
|
+
del res["error"]
|
|
85
|
+
for key, value in res.items():
|
|
86
|
+
result[key] = (value[0], value[1])
|
|
87
|
+
|
|
88
|
+
return result
|
|
File without changes
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains an XML-parser for run script specifications.
|
|
3
|
+
It reads and converts a given specification and returns its
|
|
4
|
+
representation in form of python classes.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
__author__ = "Roland Kaminski"
|
|
8
|
+
import os
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from lxml import etree # type: ignore[import-untyped]
|
|
12
|
+
|
|
13
|
+
from benchmarktool import tools
|
|
14
|
+
from benchmarktool.runscript.runscript import (
|
|
15
|
+
Benchmark,
|
|
16
|
+
Config,
|
|
17
|
+
DistJob,
|
|
18
|
+
Machine,
|
|
19
|
+
Project,
|
|
20
|
+
Runscript,
|
|
21
|
+
SeqJob,
|
|
22
|
+
Setting,
|
|
23
|
+
System,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
from StringIO import StringIO # type: ignore[import-not-found]
|
|
28
|
+
except ModuleNotFoundError:
|
|
29
|
+
from io import StringIO
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# pylint: disable=anomalous-backslash-in-string, line-too-long, too-many-locals
|
|
33
|
+
class Parser:
|
|
34
|
+
"""
|
|
35
|
+
A parser to parse xml runscript specifications.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self) -> None:
|
|
39
|
+
"""
|
|
40
|
+
Initializes the parser.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
# pylint: disable=too-many-branches, too-many-statements, too-many-nested-blocks
|
|
44
|
+
def parse(self, file_name: str) -> Runscript:
|
|
45
|
+
"""
|
|
46
|
+
Parse a given runscript and return its representation
|
|
47
|
+
in form of an instance of class Runscript.
|
|
48
|
+
|
|
49
|
+
Attributes:
|
|
50
|
+
fileName (str): a string holding a path to a xml file.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
schemadoc = etree.parse(
|
|
54
|
+
StringIO(
|
|
55
|
+
"""\
|
|
56
|
+
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
57
|
+
<!-- the runscript -->
|
|
58
|
+
<xs:complexType name="runscriptType">
|
|
59
|
+
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
|
60
|
+
<xs:element name="machine" type="machineType"/>
|
|
61
|
+
<xs:element name="system" type="systemType">
|
|
62
|
+
<!-- setting keys have to be unique per system/version-->
|
|
63
|
+
<!-- unfortunately i have found no way to create a link between settings and systems -->
|
|
64
|
+
<!-- schematron should be able to do this but the lxml implementation seems to be incomplete-->
|
|
65
|
+
<xs:unique name="settingKey">
|
|
66
|
+
<xs:selector xpath="setting"/>
|
|
67
|
+
<xs:field xpath="@name"/>
|
|
68
|
+
</xs:unique>
|
|
69
|
+
</xs:element>
|
|
70
|
+
<xs:element name="config" type="configType"/>
|
|
71
|
+
<xs:element name="benchmark" type="benchmarkType"/>
|
|
72
|
+
<xs:element name="distjob" type="distjobType"/>
|
|
73
|
+
<xs:element name="seqjob" type="seqjobType"/>
|
|
74
|
+
<xs:element name="project" type="projectType"/>
|
|
75
|
+
</xs:choice>
|
|
76
|
+
<xs:attribute name="output" type="xs:string" use="required"/>
|
|
77
|
+
</xs:complexType>
|
|
78
|
+
|
|
79
|
+
<!-- a project -->
|
|
80
|
+
<xs:complexType name="projectType">
|
|
81
|
+
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
|
82
|
+
<xs:element name="runspec" type="runspecType"/>
|
|
83
|
+
<xs:element name="runtag" type="runtagType"/>
|
|
84
|
+
</xs:choice>
|
|
85
|
+
<xs:attribute name="name" type="nameType" use="required"/>
|
|
86
|
+
<xs:attribute name="job" type="nameType" use="required"/>
|
|
87
|
+
</xs:complexType>
|
|
88
|
+
|
|
89
|
+
<!-- a machine -->
|
|
90
|
+
<xs:complexType name="machineType">
|
|
91
|
+
<xs:attribute name="name" type="nameType" use="required"/>
|
|
92
|
+
<xs:attribute name="cpu" type="xs:token" use="required"/>
|
|
93
|
+
<xs:attribute name="memory" type="xs:token" use="required"/>
|
|
94
|
+
</xs:complexType>
|
|
95
|
+
|
|
96
|
+
<!-- a system -->
|
|
97
|
+
<xs:complexType name="systemType">
|
|
98
|
+
<xs:choice minOccurs="1" maxOccurs="unbounded">
|
|
99
|
+
<xs:element name="setting">
|
|
100
|
+
<xs:complexType>
|
|
101
|
+
<xs:sequence>
|
|
102
|
+
<xs:element name="encoding" minOccurs="0" maxOccurs="unbounded">
|
|
103
|
+
<xs:complexType>
|
|
104
|
+
<xs:attribute name="file" type="xs:string" use="required"/>
|
|
105
|
+
<xs:attribute name="enctag">
|
|
106
|
+
<xs:simpleType>
|
|
107
|
+
<xs:list itemType="nameType"/>
|
|
108
|
+
</xs:simpleType>
|
|
109
|
+
</xs:attribute>
|
|
110
|
+
</xs:complexType>
|
|
111
|
+
</xs:element>
|
|
112
|
+
</xs:sequence>
|
|
113
|
+
<xs:attribute name="name" type="nameType" use="required"/>
|
|
114
|
+
<xs:attribute name="cmdline" type="xs:string"/>
|
|
115
|
+
<xs:attribute name="tag">
|
|
116
|
+
<xs:simpleType>
|
|
117
|
+
<xs:list itemType="nameType"/>
|
|
118
|
+
</xs:simpleType>
|
|
119
|
+
</xs:attribute>
|
|
120
|
+
<xs:attribute name="disttemplate" type="xs:string"/>
|
|
121
|
+
<xs:attribute name="distopts" type="xs:string"/>
|
|
122
|
+
<xs:anyAttribute processContents="lax"/>
|
|
123
|
+
</xs:complexType>
|
|
124
|
+
</xs:element>
|
|
125
|
+
</xs:choice>
|
|
126
|
+
<xs:attribute name="name" type="nameType" use="required"/>
|
|
127
|
+
<xs:attribute name="version" type="versionType" use="required"/>
|
|
128
|
+
<xs:attribute name="measures" type="nameType" use="required"/>
|
|
129
|
+
<xs:attribute name="config" type="nameType" use="required"/>
|
|
130
|
+
<xs:attribute name="cmdline" type="xs:string"/>
|
|
131
|
+
</xs:complexType>
|
|
132
|
+
|
|
133
|
+
<!-- generic attributes for jobs-->
|
|
134
|
+
<xs:attributeGroup name="jobAttr">
|
|
135
|
+
<xs:attribute name="name" type="nameType" use="required"/>
|
|
136
|
+
<xs:attribute name="timeout" type="timeType" use="required"/>
|
|
137
|
+
<xs:attribute name="runs" type="xs:positiveInteger" use="required"/>
|
|
138
|
+
<xs:attribute name="memout" type="xs:positiveInteger"/>
|
|
139
|
+
<xs:anyAttribute processContents="lax"/>
|
|
140
|
+
</xs:attributeGroup>
|
|
141
|
+
|
|
142
|
+
<!-- a seqjob -->
|
|
143
|
+
<xs:complexType name="seqjobType">
|
|
144
|
+
<xs:attributeGroup ref="jobAttr"/>
|
|
145
|
+
<xs:attribute name="parallel" type="xs:positiveInteger" use="required"/>
|
|
146
|
+
</xs:complexType>
|
|
147
|
+
|
|
148
|
+
<!-- a distjob -->
|
|
149
|
+
<xs:complexType name="distjobType">
|
|
150
|
+
<xs:attributeGroup ref="jobAttr"/>
|
|
151
|
+
<xs:attribute name="script_mode" use="required">
|
|
152
|
+
<xs:simpleType>
|
|
153
|
+
<xs:restriction base="xs:string">
|
|
154
|
+
<xs:enumeration value="multi"/>
|
|
155
|
+
<xs:enumeration value="timeout"/>
|
|
156
|
+
</xs:restriction>
|
|
157
|
+
</xs:simpleType>
|
|
158
|
+
</xs:attribute>
|
|
159
|
+
<xs:attribute name="walltime" type="timeType" use="required"/>
|
|
160
|
+
<xs:attribute name="cpt" type="xs:positiveInteger" use="required"/>
|
|
161
|
+
<xs:attribute name="partition" type="xs:string"/>
|
|
162
|
+
</xs:complexType>
|
|
163
|
+
|
|
164
|
+
<!-- a config -->
|
|
165
|
+
<xs:complexType name="configType">
|
|
166
|
+
<xs:attribute name="name" type="nameType" use="required"/>
|
|
167
|
+
<xs:attribute name="template" type="xs:string" use="required"/>
|
|
168
|
+
</xs:complexType>
|
|
169
|
+
|
|
170
|
+
<!-- a benchmark -->
|
|
171
|
+
<xs:complexType name="benchmarkType">
|
|
172
|
+
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
|
173
|
+
<xs:element name="files">
|
|
174
|
+
<xs:complexType>
|
|
175
|
+
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
|
176
|
+
<xs:element name="add">
|
|
177
|
+
<xs:complexType>
|
|
178
|
+
<xs:attribute name="file" type="xs:string" use="required"/>
|
|
179
|
+
<xs:attribute name="group" type="xs:string"/>
|
|
180
|
+
</xs:complexType>
|
|
181
|
+
</xs:element>
|
|
182
|
+
<xs:element name="encoding">
|
|
183
|
+
<xs:complexType>
|
|
184
|
+
<xs:attribute name="file" type="xs:string" use="required"/>
|
|
185
|
+
</xs:complexType>
|
|
186
|
+
</xs:element>
|
|
187
|
+
</xs:choice>
|
|
188
|
+
<xs:attribute name="path" type="xs:string" use="required"/>
|
|
189
|
+
<xs:attribute name="enctag">
|
|
190
|
+
<xs:simpleType>
|
|
191
|
+
<xs:list itemType="nameType"/>
|
|
192
|
+
</xs:simpleType>
|
|
193
|
+
</xs:attribute>
|
|
194
|
+
</xs:complexType>
|
|
195
|
+
</xs:element>
|
|
196
|
+
<xs:element name="folder">
|
|
197
|
+
<xs:complexType>
|
|
198
|
+
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
|
199
|
+
<xs:element name="ignore">
|
|
200
|
+
<xs:complexType>
|
|
201
|
+
<xs:attribute name="prefix" type="xs:string" use="required"/>
|
|
202
|
+
</xs:complexType>
|
|
203
|
+
</xs:element>
|
|
204
|
+
<xs:element name="encoding">
|
|
205
|
+
<xs:complexType>
|
|
206
|
+
<xs:attribute name="file" type="xs:string" use="required"/>
|
|
207
|
+
</xs:complexType>
|
|
208
|
+
</xs:element>
|
|
209
|
+
</xs:choice>
|
|
210
|
+
<xs:attribute name="path" type="xs:string" use="required"/>
|
|
211
|
+
<xs:attribute name="group" type="xs:boolean"/>
|
|
212
|
+
<xs:attribute name="enctag">
|
|
213
|
+
<xs:simpleType>
|
|
214
|
+
<xs:list itemType="nameType"/>
|
|
215
|
+
</xs:simpleType>
|
|
216
|
+
</xs:attribute>
|
|
217
|
+
</xs:complexType>
|
|
218
|
+
</xs:element>
|
|
219
|
+
</xs:choice>
|
|
220
|
+
<xs:attribute name="name" type="nameType" use="required"/>
|
|
221
|
+
</xs:complexType>
|
|
222
|
+
|
|
223
|
+
<!-- common attributes for runspec/runtag -->
|
|
224
|
+
<xs:attributeGroup name="runAttr">
|
|
225
|
+
<xs:attribute name="machine" type="nameType" use="required"/>
|
|
226
|
+
<xs:attribute name="benchmark" type="nameType" use="required"/>
|
|
227
|
+
</xs:attributeGroup>
|
|
228
|
+
|
|
229
|
+
<!-- a runspec -->
|
|
230
|
+
<xs:complexType name="runspecType">
|
|
231
|
+
<xs:attribute name="system" type="nameType" use="required"/>
|
|
232
|
+
<xs:attribute name="version" type="versionType" use="required"/>
|
|
233
|
+
<xs:attribute name="setting" type="nameType" use="required"/>
|
|
234
|
+
<xs:attributeGroup ref="runAttr"/>
|
|
235
|
+
</xs:complexType>
|
|
236
|
+
|
|
237
|
+
<!-- a runtag -->
|
|
238
|
+
<xs:complexType name="runtagType">
|
|
239
|
+
<xs:attributeGroup ref="runAttr"/>
|
|
240
|
+
<xs:attribute name="tag" type="tagrefType" use="required"/>
|
|
241
|
+
</xs:complexType>
|
|
242
|
+
|
|
243
|
+
<!-- simple types used througout the above definitions -->
|
|
244
|
+
<xs:simpleType name="versionType">
|
|
245
|
+
<xs:restriction base="xs:string">
|
|
246
|
+
<xs:pattern value="[0-9a-zA-Z._-]+"/>
|
|
247
|
+
</xs:restriction>
|
|
248
|
+
</xs:simpleType>
|
|
249
|
+
|
|
250
|
+
<xs:simpleType name="timeType">
|
|
251
|
+
<xs:restriction base="xs:string">
|
|
252
|
+
<xs:pattern value="([0-9]+)|([0-9]+d)?[ ]*([0-9]+h)?[ ]*([0-9]+m)?[ ]*([0-9]+s)?"/>
|
|
253
|
+
</xs:restriction>
|
|
254
|
+
</xs:simpleType>
|
|
255
|
+
|
|
256
|
+
<xs:simpleType name="tagrefType">
|
|
257
|
+
<xs:restriction base="xs:string">
|
|
258
|
+
<xs:pattern value="(\\*all\\*)|([A-Za-z_\\-0-9]+([ ]*[A-Za-z_\\-0-9]+)*)([ ]*\\|[ ]*([A-Za-z_\\-0-9]+([ ]*[A-Za-z_\\-0-9]+)*))*"/>
|
|
259
|
+
</xs:restriction>
|
|
260
|
+
</xs:simpleType>
|
|
261
|
+
|
|
262
|
+
<xs:simpleType name="nameType">
|
|
263
|
+
<xs:restriction base="xs:string">
|
|
264
|
+
<xs:pattern value="[A-Za-z_\\-0-9]*"/>
|
|
265
|
+
</xs:restriction>
|
|
266
|
+
</xs:simpleType>
|
|
267
|
+
|
|
268
|
+
<!-- the root element -->
|
|
269
|
+
<xs:element name="runscript" type="runscriptType">
|
|
270
|
+
<!-- machine keys -->
|
|
271
|
+
<xs:keyref name="machineRef" refer="machineKey">
|
|
272
|
+
<xs:selector xpath="project/runspec|project/runall"/>
|
|
273
|
+
<xs:field xpath="@machine"/>
|
|
274
|
+
</xs:keyref>
|
|
275
|
+
<xs:key name="machineKey">
|
|
276
|
+
<xs:selector xpath="machine"/>
|
|
277
|
+
<xs:field xpath="@name"/>
|
|
278
|
+
</xs:key>
|
|
279
|
+
<!-- benchmark keys -->
|
|
280
|
+
<xs:keyref name="benchmarkRef" refer="benchmarkKey">
|
|
281
|
+
<xs:selector xpath="project/runspec|project/runall"/>
|
|
282
|
+
<xs:field xpath="@benchmark"/>
|
|
283
|
+
</xs:keyref>
|
|
284
|
+
<xs:key name="benchmarkKey">
|
|
285
|
+
<xs:selector xpath="benchmark"/>
|
|
286
|
+
<xs:field xpath="@name"/>
|
|
287
|
+
</xs:key>
|
|
288
|
+
<!-- system keys -->
|
|
289
|
+
<xs:keyref name="systemRef" refer="systemKey">
|
|
290
|
+
<xs:selector xpath="project/runspec"/>
|
|
291
|
+
<xs:field xpath="@system"/>
|
|
292
|
+
<xs:field xpath="@version"/>
|
|
293
|
+
</xs:keyref>
|
|
294
|
+
<xs:key name="systemKey">
|
|
295
|
+
<xs:selector xpath="system"/>
|
|
296
|
+
<xs:field xpath="@name"/>
|
|
297
|
+
<xs:field xpath="@version"/>
|
|
298
|
+
</xs:key>
|
|
299
|
+
<!-- config keys -->
|
|
300
|
+
<xs:keyref name="configRef" refer="configKey">
|
|
301
|
+
<xs:selector xpath="system"/>
|
|
302
|
+
<xs:field xpath="@config"/>
|
|
303
|
+
</xs:keyref>
|
|
304
|
+
<xs:key name="configKey">
|
|
305
|
+
<xs:selector xpath="config"/>
|
|
306
|
+
<xs:field xpath="@name"/>
|
|
307
|
+
</xs:key>
|
|
308
|
+
<!-- config keys -->
|
|
309
|
+
<xs:keyref name="jobRef" refer="jobKey">
|
|
310
|
+
<xs:selector xpath="project"/>
|
|
311
|
+
<xs:field xpath="@job"/>
|
|
312
|
+
</xs:keyref>
|
|
313
|
+
<xs:key name="jobKey">
|
|
314
|
+
<xs:selector xpath="seqjob|distjob"/>
|
|
315
|
+
<xs:field xpath="@name"/>
|
|
316
|
+
</xs:key>
|
|
317
|
+
<!-- project keys -->
|
|
318
|
+
<xs:unique name="projectKey">
|
|
319
|
+
<xs:selector xpath="project"/>
|
|
320
|
+
<xs:field xpath="@name"/>
|
|
321
|
+
</xs:unique>
|
|
322
|
+
</xs:element>
|
|
323
|
+
</xs:schema>
|
|
324
|
+
"""
|
|
325
|
+
)
|
|
326
|
+
)
|
|
327
|
+
schema = etree.XMLSchema(schemadoc)
|
|
328
|
+
|
|
329
|
+
with open(file_name, "r", encoding="utf8") as file:
|
|
330
|
+
doc = etree.parse(file)
|
|
331
|
+
schema.assertValid(doc)
|
|
332
|
+
|
|
333
|
+
root = doc.getroot()
|
|
334
|
+
run = Runscript(root.get("output"))
|
|
335
|
+
|
|
336
|
+
job: DistJob | SeqJob
|
|
337
|
+
|
|
338
|
+
for node in root.xpath("./distjob"):
|
|
339
|
+
attr = self._filter_attr(
|
|
340
|
+
node, ["name", "timeout", "runs", "script_mode", "walltime", "cpt", "partition"]
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
partition = node.get("partition")
|
|
344
|
+
if partition is None:
|
|
345
|
+
partition = "kr"
|
|
346
|
+
job = DistJob(
|
|
347
|
+
node.get("name"),
|
|
348
|
+
tools.xml_to_seconds_time(node.get("timeout")),
|
|
349
|
+
int(node.get("runs")),
|
|
350
|
+
attr,
|
|
351
|
+
node.get("script_mode"),
|
|
352
|
+
tools.xml_to_seconds_time(node.get("walltime")),
|
|
353
|
+
int(node.get("cpt")),
|
|
354
|
+
partition,
|
|
355
|
+
)
|
|
356
|
+
run.add_job(job)
|
|
357
|
+
|
|
358
|
+
for node in root.xpath("./seqjob"):
|
|
359
|
+
attr = self._filter_attr(node, ["name", "timeout", "runs", "parallel"])
|
|
360
|
+
job = SeqJob(
|
|
361
|
+
node.get("name"),
|
|
362
|
+
tools.xml_to_seconds_time(node.get("timeout")),
|
|
363
|
+
int(node.get("runs")),
|
|
364
|
+
attr,
|
|
365
|
+
int(node.get("parallel")),
|
|
366
|
+
)
|
|
367
|
+
run.add_job(job)
|
|
368
|
+
|
|
369
|
+
for node in root.xpath("./machine"):
|
|
370
|
+
machine = Machine(node.get("name"), node.get("cpu"), node.get("memory"))
|
|
371
|
+
run.add_machine(machine)
|
|
372
|
+
|
|
373
|
+
for node in root.xpath("./config"):
|
|
374
|
+
config = Config(node.get("name"), node.get("template"))
|
|
375
|
+
run.add_config(config)
|
|
376
|
+
|
|
377
|
+
compound_settings: dict[str, list[str]] = {}
|
|
378
|
+
system_order = 0
|
|
379
|
+
for node in root.xpath("./system"):
|
|
380
|
+
config = run.configs[node.get("config")]
|
|
381
|
+
system = System(node.get("name"), node.get("version"), node.get("measures"), system_order, config)
|
|
382
|
+
setting_order = 0
|
|
383
|
+
sys_cmdline = node.get("cmdline")
|
|
384
|
+
for child in node.xpath("setting"):
|
|
385
|
+
attr = self._filter_attr(child, ["name", "cmdline", "tag", "distopts", "disttemplate"])
|
|
386
|
+
compound_settings[child.get("name")] = []
|
|
387
|
+
disttemplate = child.get("disttemplate")
|
|
388
|
+
if disttemplate is None:
|
|
389
|
+
disttemplate = "templates/single.dist"
|
|
390
|
+
if child.get("tag") is None:
|
|
391
|
+
tag = set()
|
|
392
|
+
else:
|
|
393
|
+
tag = set(child.get("tag").split(None))
|
|
394
|
+
dist_options = child.get("distopts")
|
|
395
|
+
if dist_options is None:
|
|
396
|
+
dist_options = ""
|
|
397
|
+
encodings: dict[str, set[str]] = {"_default_": set()}
|
|
398
|
+
for grandchild in child.xpath("./encoding"):
|
|
399
|
+
if grandchild.get("enctag") is None:
|
|
400
|
+
encodings["_default_"].add(os.path.normpath(grandchild.get("file")))
|
|
401
|
+
else:
|
|
402
|
+
enctags = set(grandchild.get("enctag").split(None))
|
|
403
|
+
for t in enctags:
|
|
404
|
+
if t not in encodings:
|
|
405
|
+
encodings[t] = set()
|
|
406
|
+
encodings[t].add(os.path.normpath(grandchild.get("file")))
|
|
407
|
+
|
|
408
|
+
cmdline = " ".join(filter(None, [sys_cmdline, child.get("cmdline")]))
|
|
409
|
+
name = child.get("name")
|
|
410
|
+
compound_settings[child.get("name")].append(name)
|
|
411
|
+
setting = Setting(name, cmdline, tag, setting_order, disttemplate, attr, dist_options, encodings)
|
|
412
|
+
system.add_setting(setting)
|
|
413
|
+
setting_order += 1
|
|
414
|
+
|
|
415
|
+
run.systems[(system.name, system.version)] = system
|
|
416
|
+
system_order += 1
|
|
417
|
+
|
|
418
|
+
element: Any
|
|
419
|
+
for node in root.xpath("./benchmark"):
|
|
420
|
+
benchmark = Benchmark(node.get("name"))
|
|
421
|
+
for child in node.xpath("./folder"):
|
|
422
|
+
if child.get("group") is not None:
|
|
423
|
+
group = child.get("group").lower() == "true"
|
|
424
|
+
else:
|
|
425
|
+
group = False
|
|
426
|
+
element = Benchmark.Folder(child.get("path"), group)
|
|
427
|
+
if child.get("enctag") is None:
|
|
428
|
+
tag = set()
|
|
429
|
+
else:
|
|
430
|
+
tag = set(child.get("enctag").split(None))
|
|
431
|
+
element.add_enctags(tag)
|
|
432
|
+
for grandchild in child.xpath("./encoding"):
|
|
433
|
+
element.add_encoding(grandchild.get("file"))
|
|
434
|
+
for grandchild in child.xpath("./ignore"):
|
|
435
|
+
element.add_ignore(grandchild.get("prefix"))
|
|
436
|
+
benchmark.add_element(element)
|
|
437
|
+
for child in node.xpath("./files"):
|
|
438
|
+
element = Benchmark.Files(child.get("path"))
|
|
439
|
+
if child.get("enctag") is None:
|
|
440
|
+
tag = set()
|
|
441
|
+
else:
|
|
442
|
+
tag = set(child.get("enctag").split(None))
|
|
443
|
+
element.add_enctags(tag)
|
|
444
|
+
for grandchild in child.xpath("./encoding"):
|
|
445
|
+
element.add_encoding(grandchild.get("file"))
|
|
446
|
+
for grandchild in child.xpath("./add"):
|
|
447
|
+
element.add_file(grandchild.get("file"), grandchild.get("group"))
|
|
448
|
+
benchmark.add_element(element)
|
|
449
|
+
run.add_benchmark(benchmark)
|
|
450
|
+
|
|
451
|
+
for node in root.xpath("./project"):
|
|
452
|
+
project = Project(node.get("name"), run, run.jobs[node.get("job")])
|
|
453
|
+
run.add_project(project)
|
|
454
|
+
for child in node.xpath("./runspec"):
|
|
455
|
+
for setting_name in compound_settings[child.get("setting")]:
|
|
456
|
+
project.add_runspec(
|
|
457
|
+
child.get("machine"),
|
|
458
|
+
child.get("system"),
|
|
459
|
+
child.get("version"),
|
|
460
|
+
setting_name,
|
|
461
|
+
child.get("benchmark"),
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
for child in node.xpath("./runtag"):
|
|
465
|
+
project.add_runtag(child.get("machine"), child.get("benchmark"), child.get("tag"))
|
|
466
|
+
return run
|
|
467
|
+
|
|
468
|
+
def _filter_attr(self, node: etree._Element, skip: list[str]) -> dict[str, Any]:
|
|
469
|
+
"""
|
|
470
|
+
Returns a dictionary containing all attributes of a given node.
|
|
471
|
+
Attributes whose name occurs in the skip list are ignored.
|
|
472
|
+
"""
|
|
473
|
+
attr = {}
|
|
474
|
+
for key, val in node.items():
|
|
475
|
+
if not key in skip:
|
|
476
|
+
attr[key] = val
|
|
477
|
+
return attr
|