forked from pulp-platform/Deeploy
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdeeployRunner.py
More file actions
427 lines (356 loc) · 18.2 KB
/
deeployRunner.py
File metadata and controls
427 lines (356 loc) · 18.2 KB
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# SPDX-FileCopyrightText: 2025 ETH Zurich and University of Bologna
#
# SPDX-License-Identifier: Apache-2.0
import argparse
import codecs
import os
import sys
from pathlib import Path
from typing import Optional
import coloredlogs
from Deeploy.Logging import DEFAULT_FMT
from Deeploy.Logging import DEFAULT_LOGGER as log
from Deeploy.Logging import DETAILED_FILE_LOG_FORMAT
from .core import DeeployTestConfig, run_complete_test
from .core.paths import get_test_paths
def cmake_str(arg_str):
return "-D" + codecs.decode(str(arg_str), 'unicode_escape')
class _ArgumentDefaultMetavarTypeFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.MetavarTypeHelpFormatter):
def __init__(self, prog: str, indent_increment: int = 2, max_help_position: int = 100, width = None) -> None:
super().__init__(prog, indent_increment, max_help_position, width)
class DeeployRunnerArgumentParser(argparse.ArgumentParser):
def __init__(self,
tiling_arguments: bool,
description: Optional[str] = None,
platform_required: bool = True,
allow_extra_args: bool = False):
formatter = _ArgumentDefaultMetavarTypeFormatter
if description is None:
super().__init__(description = "Deeploy Code Generation and Test Utility.", formatter_class = formatter)
else:
super().__init__(description = description, formatter_class = formatter)
self.allow_extra_args = allow_extra_args
self.tiling_arguments = tiling_arguments
self.add_argument('-t',
metavar = '<dir>',
dest = 'dir',
type = str,
required = True,
help = 'Test directory (e.g., Tests/Kernels/Integer/Add/Regular)\n')
self.add_argument('-p',
metavar = '<platform>',
dest = 'platform',
type = str,
required = platform_required,
default = None,
help = 'Target platform (e.g., Generic, QEMU-ARM, Siracusa, Snitch)\n')
self.add_argument('-s',
metavar = '<simulator>',
dest = 'simulator',
type = str,
default = None,
help = 'Simulator to use (gvsoc, banshee, qemu, vsim, host, none)\n')
self.add_argument('-v', action = 'count', dest = 'verbose', default = 0, help = 'Increase verbosity level\n')
self.add_argument('-D',
dest = 'cmake',
action = 'extend',
nargs = "*",
type = cmake_str,
help = "Create or update a cmake cache entry\n")
self.add_argument('--debug',
dest = 'debug',
action = 'store_true',
default = False,
help = 'Enable debugging mode\n')
self.add_argument('--skipgen',
dest = 'skipgen',
action = 'store_true',
default = False,
help = 'Skip network generation (reuse existing generated code)\n')
self.add_argument('--skipsim',
dest = 'skipsim',
action = 'store_true',
default = False,
help = 'Skip simulation (build only)\n')
self.add_argument('--profileUntiled',
'--profile-untiled',
dest = 'profileUntiled',
action = 'store_true',
default = False,
help = 'Enable untiled profiling (Siracusa only)\n')
self.add_argument('--toolchain',
metavar = '<LLVM|GCC>',
dest = 'toolchain',
type = str,
default = "LLVM",
help = 'Compiler toolchain\n')
self.add_argument('--toolchain-install-dir',
metavar = '<dir>',
dest = 'toolchain_install_dir',
type = str,
default = os.environ.get('LLVM_INSTALL_DIR'),
help = 'Toolchain installation directory\n')
self.add_argument('--input-type-map',
nargs = '*',
default = [],
type = str,
help = '(Optional) mapping of input names to data types. '
'Example: --input-type-map input_0=int8_t input_1=float32_t\n')
self.add_argument('--input-offset-map',
nargs = '*',
default = [],
type = str,
help = '(Optional) mapping of input names to offsets. '
'Example: --input-offset-map input_0=0 input_1=128\n')
if self.tiling_arguments:
self.add_argument('--defaultMemLevel',
metavar = '<level>',
dest = 'defaultMemLevel',
type = str,
default = "L2",
help = 'Default memory level (L2 or L3)\n')
self.add_argument('--doublebuffer', action = 'store_true', help = 'Enable double buffering\n')
self.add_argument('--l1',
metavar = '<size>',
dest = 'l1',
type = int,
default = 64000,
help = 'L1 size in bytes\n')
self.add_argument('--l2',
metavar = '<size>',
dest = 'l2',
type = int,
default = 1024000,
help = 'L2 size in bytes\n')
self.add_argument('--randomizedMemoryScheduler',
action = "store_true",
help = 'Enable randomized memory scheduler\n')
self.add_argument('--profileTiling', action = 'store_true', help = 'Enable tiling profiling\n')
self.add_argument('--memAllocStrategy',
metavar = '<strategy>',
dest = 'memAllocStrategy',
type = str,
default = "MiniMalloc",
help = 'Memory allocation strategy: TetrisRandom, TetrisCo-Opt, MiniMalloc\n')
self.add_argument('--searchStrategy',
metavar = '<strategy>',
dest = 'searchStrategy',
type = str,
default = "random-max",
help = 'CP solver search strategy: random-max, max, min\n')
self.add_argument('--plotMemAlloc',
action = 'store_true',
help = 'Plot memory allocation and save in deeployState folder\n')
self.args = None
def parse_args(self, args = None, namespace = None) -> argparse.Namespace:
self.args = super().parse_args(args, namespace)
if self.args.verbose > 2:
coloredlogs.install(level = 'DEBUG', logger = log, fmt = DETAILED_FILE_LOG_FORMAT)
elif self.args.verbose > 1:
coloredlogs.install(level = 'DEBUG', logger = log, fmt = DEFAULT_FMT)
elif self.args.verbose > 0:
coloredlogs.install(level = 'INFO', logger = log, fmt = DEFAULT_FMT)
else:
coloredlogs.install(level = 'WARNING', logger = log, fmt = DEFAULT_FMT)
return self.args
def create_config_from_args(args: argparse.Namespace,
platform: str,
simulator: str,
tiling: bool,
platform_specific_cmake_args: Optional[list] = None) -> DeeployTestConfig:
script_path = Path(__file__).resolve()
base_dir = script_path.parent.parent
test_dir = args.dir
gen_dir, test_dir_abs, test_name = get_test_paths(test_dir, platform, base_dir = str(base_dir))
# Use worker-specific build directory to avoid collisions with parallel execution with pytest-xdist
worker_id = os.environ.get("PYTEST_XDIST_WORKER", "master")
if worker_id == "master":
build_dir = str(base_dir / f"TEST_{platform.upper()}" / "build_master")
else:
build_dir = str(base_dir / f"TEST_{platform.upper()}" / f"build_{worker_id}")
cmake_args_list = list(args.cmake) if args.cmake else []
# Add platform-specific CMake args
if platform_specific_cmake_args:
cmake_args_list.extend(platform_specific_cmake_args)
# Prepare generation args
gen_args_list = []
if args.input_type_map:
gen_args_list.append("--input-type-map")
gen_args_list.extend(args.input_type_map)
if args.input_offset_map:
gen_args_list.append("--input-offset-map")
gen_args_list.extend(args.input_offset_map)
if tiling:
if hasattr(args, 'defaultMemLevel') and args.defaultMemLevel:
gen_args_list.append(f"--defaultMemLevel={args.defaultMemLevel}")
if hasattr(args, 'doublebuffer') and args.doublebuffer:
gen_args_list.append("--doublebuffer")
if hasattr(args, 'l1') and args.l1:
gen_args_list.append(f"--l1={args.l1}")
if hasattr(args, 'l2') and args.l2 and args.l2 != 1024000:
gen_args_list.append(f"--l2={args.l2}")
if hasattr(args, 'randomizedMemoryScheduler') and args.randomizedMemoryScheduler:
gen_args_list.append("--randomizedMemoryScheduler")
if hasattr(args, 'profileTiling') and args.profileTiling:
gen_args_list.append("--profileTiling")
if hasattr(args, 'memAllocStrategy') and args.memAllocStrategy:
gen_args_list.append(f"--memAllocStrategy={args.memAllocStrategy}")
if hasattr(args, 'searchStrategy') and args.searchStrategy:
gen_args_list.append(f"--searchStrategy={args.searchStrategy}")
if hasattr(args, 'plotMemAlloc') and args.plotMemAlloc:
gen_args_list.append("--plotMemAlloc")
if not tiling and getattr(args, 'profileUntiled', False):
gen_args_list.append("--profileUntiled")
config = DeeployTestConfig(
test_name = test_name,
test_dir = test_dir_abs,
platform = platform,
simulator = simulator,
tiling = tiling,
gen_dir = gen_dir,
build_dir = build_dir,
toolchain = args.toolchain,
toolchain_install_dir = args.toolchain_install_dir,
gvsoc_install_dir = getattr(args, 'gvsoc_install_dir', None),
cmake_args = cmake_args_list,
gen_args = gen_args_list,
verbose = args.verbose,
debug = args.debug,
)
return config
def print_colored_result(result, test_name: str):
GREEN = '\033[92m'
RED = '\033[91m'
RESET = '\033[0m'
if result.success and result.error_count == 0:
print(f"\n{GREEN}✓ Test {test_name} PASSED - No errors found{RESET}")
if result.runtime_cycles is not None:
print(f"{GREEN} Runtime: {result.runtime_cycles} cycles{RESET}")
else:
print(f"\n{RED}✗ Test {test_name} FAILED - {result.error_count} errors out of {result.total_count}{RESET}")
if result.runtime_cycles is not None:
print(f"{RED} Runtime: {result.runtime_cycles} cycles{RESET}")
def print_configuration(config: DeeployTestConfig):
CYAN = '\033[96m'
BOLD = '\033[1m'
RESET = '\033[0m'
print(f"\n{BOLD}{CYAN}═══════════════════════════════════════════════════════════════{RESET}")
print(f"{BOLD}{CYAN} Deeploy Test Configuration {RESET}")
print(f"{BOLD}{CYAN}═══════════════════════════════════════════════════════════════{RESET}\n")
print(f"{BOLD}Test Configuration:{RESET}")
print(f" Test Name : {config.test_name}")
print(f" Test Directory : {config.test_dir}")
print(f" Generation Directory: {config.gen_dir}")
print(f" Build Directory : {config.build_dir}")
print(f"\n{BOLD}Platform Configuration:{RESET}")
print(f" Platform : {config.platform}")
print(f" Simulator : {config.simulator}")
print(f" Tiling Enabled : {'Yes' if config.tiling else 'No'}")
print(f"\n{BOLD}Build Configuration:{RESET}")
print(f" Toolchain : {config.toolchain}")
if config.toolchain_install_dir:
print(f" Toolchain Directory : {config.toolchain_install_dir}")
if config.cmake_args:
print(f" CMake Arguments : {' '.join(config.cmake_args)}")
print(f"\n{BOLD}Runtime Configuration:{RESET}")
print(f" Verbosity Level : {config.verbose}")
print(f" Debug Mode : {'Enabled' if config.debug else 'Disabled'}")
if config.gen_args:
print(f" Generation Arguments: {' '.join(config.gen_args)}")
print(f"\n{BOLD}{CYAN}═══════════════════════════════════════════════════════════════{RESET}\n")
def main(default_platform: Optional[str] = None,
default_simulator: Optional[str] = None,
tiling_enabled: bool = False,
platform_specific_cmake_args: Optional[list] = None,
parsed_args: Optional[argparse.Namespace] = None,
parser_setup_callback = None):
"""
Main entry point for Deeploy test runners.
Args:
default_platform: Default platform if not specified via -p
default_simulator: Default simulator if not specified via -s
tiling_enabled: Whether tiling is enabled
platform_specific_cmake_args: Additional CMake arguments for platform-specific configurations
parsed_args: Pre-parsed arguments (if None, will parse from sys.argv)
parser_setup_callback: Optional callback to configure parser before parsing (receives parser as arg)
"""
if parsed_args is None:
# Make -p optional if default_platform is provided
parser = DeeployRunnerArgumentParser(tiling_arguments = tiling_enabled,
platform_required = (default_platform is None))
# Allow platform-specific runners to add their own arguments
if parser_setup_callback:
parser_setup_callback(parser)
args = parser.parse_args()
else:
args = parsed_args
platform_map = {
"generic": "Generic",
"qemu-arm": "QEMU-ARM",
"mempool": "MemPool",
"siracusa": "Siracusa",
"siracusa_w_neureka": "Siracusa_w_neureka",
"snitch": "Snitch",
"chimera": "Chimera",
"softhier": "SoftHier",
}
if args.platform:
platform = platform_map.get(args.platform.lower(), args.platform)
else:
platform = default_platform
# Validate platform if default is provided
if default_platform and args.platform:
normalized_specified = platform_map.get(args.platform.lower(), args.platform)
if normalized_specified != default_platform:
RED = '\033[91m'
BOLD = '\033[1m'
RESET = '\033[0m'
print(f"\n{RED}{BOLD}ERROR: Platform mismatch!{RESET}", file = sys.stderr)
print(f"{RED}This runner is designed for the '{default_platform}' platform.{RESET}", file = sys.stderr)
print(f"{RED}You specified platform: '{args.platform}' (normalized to '{normalized_specified}'){RESET}\n",
file = sys.stderr)
print(f"Please use one of the following options:", file = sys.stderr)
print(f" 1. Remove the '-p {args.platform}' argument to use the default platform", file = sys.stderr)
print(f" 2. Use the correct platform-specific runner script for '{normalized_specified}'",
file = sys.stderr)
sys.exit(1)
simulator = args.simulator if args.simulator else default_simulator
if platform is None:
print("Error: Platform must be specified with -p or provided as default", file = sys.stderr)
sys.exit(1)
if simulator is None:
simulator_map = {
"Generic": "host",
"QEMU-ARM": "qemu",
"MemPool": "banshee",
"Siracusa": "gvsoc",
"Siracusa_w_neureka": "gvsoc",
"Snitch": "gvsoc",
"Chimera": "gvsoc",
"SoftHier": "gvsoc",
}
simulator = simulator_map.get(platform, "host")
log.info(f"No simulator specified, using default for {platform}: {simulator}")
# Extract platform-specific CMake args from parsed args if available
if platform_specific_cmake_args is None:
platform_specific_cmake_args = []
# Check for platform-specific arguments in args object and build CMake args
if hasattr(args, 'cores'):
platform_specific_cmake_args.append(f"-DNUM_CORES={args.cores}")
elif hasattr(args, 'num_cores'):
platform_specific_cmake_args.append(f"-DNUM_CORES={args.num_cores}")
if hasattr(args, 'num_clusters'):
platform_specific_cmake_args.append(f"-DNUM_CLUSTERS={args.num_clusters}")
config = create_config_from_args(args, platform, simulator, tiling_enabled, platform_specific_cmake_args)
print_configuration(config)
try:
result = run_complete_test(config, skipgen = args.skipgen, skipsim = args.skipsim)
print_colored_result(result, config.test_name)
return 0 if result.success else 1
except Exception as e:
RED = '\033[91m'
RESET = '\033[0m'
print(f"\n{RED}✗ Test {config.test_name} FAILED with exception: {e}{RESET}")
return 1
if __name__ == "__main__":
sys.exit(main())