File indexing completed on 2026-05-27 07:24:18
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 from impl import read_benchmark_data, plot_benchmark_data, plot_scaling_data
0011 from options import (
0012 common_options,
0013 detector_io_options,
0014 random_track_generator_options,
0015 propagation_options,
0016 plotting_options,
0017 )
0018 from options import (
0019 parse_common_options,
0020 parse_detector_io_options,
0021 parse_plotting_options,
0022 )
0023 from plotting import pyplot_factory as plt_factory
0024 from utils import read_detector_name
0025 from utils import add_track_generator_args, add_propagation_args, add_detector_io_args
0026
0027
0028 import argparse
0029 from collections import namedtuple
0030 import os
0031 import platform
0032 import subprocess
0033 import sys
0034
0035
0036 bknd_types = ["cpu", "cuda", "hip_amd", "hip_nvidia", "sycl"]
0037
0038
0039 bknd_patterns = [
0040 "CPU",
0041 "(TM)",
0042 "GHz",
0043 "@",
0044 "Core",
0045 "Processor",
0046 "with",
0047 "Radeon",
0048 "Graphics",
0049 "GB",
0050 "Laptop",
0051 "GPU",
0052 "GeForce",
0053 ]
0054
0055
0056
0057 def __compactify_bknd_name(name, patterns=bknd_patterns):
0058 out = ""
0059 for sub_string in name.split(" "):
0060 if any(p in sub_string for p in patterns):
0061 continue
0062
0063 out = f"{out} {sub_string}"
0064
0065
0066 return name if len(out[1:]) == 0 else out[1:]
0067
0068
0069
0070 def __read_context_metadata(logging, input_dir, data_file):
0071 context, _ = read_benchmark_data(logging, input_dir, data_file)
0072 bknd = context["Backend"]
0073 bknd_name = __compactify_bknd_name(context["Backend Name"])
0074 algebra = context["Algebra-plugin"]
0075 setup = context["Detector Setup"]
0076 cores = 0
0077 if "Max no. Threads" in context:
0078 cores = int(context["Max no. Threads"]) / 2
0079
0080 return bknd, bknd_name, algebra, setup, cores
0081
0082
0083
0084 def __parse_input_data_files(args, logging):
0085 input_data_files = []
0086 for file in args.data_files:
0087 if not os.path.isfile(file):
0088 logging.error(f"File not found! ({file})")
0089 sys.exit(1)
0090
0091 _, file_extension = os.path.splitext(file)
0092
0093 if file_extension != ".json":
0094 logging.error("Wrong file extension. Should be '.json': " + file)
0095 sys.exit(1)
0096
0097 input_data_files.append(file)
0098
0099 return input_data_files
0100
0101
0102
0103
0104 def __generate_benchmark_dict(
0105 args,
0106 logging,
0107 bindir,
0108 det_name,
0109 input_data_files,
0110 algebra_plugins,
0111 bench_type="benchmark",
0112 ):
0113
0114 benchmark_metadata = namedtuple(
0115 "benchmark_metadata",
0116 "name algebra setup bin file cores",
0117 defaults=["Unknown", "Unknown Algebra", "", None, None, 0],
0118 )
0119
0120
0121 benchmarks = {"CPU": {}}
0122 if args.cuda:
0123 benchmarks["CUDA"] = {}
0124 if args.hip_amd:
0125 benchmarks["HIP_AMD"] = {}
0126 if args.hip_nvidia:
0127 benchmarks["HIP_NVIDIA"] = {}
0128 if args.sycl:
0129
0130 logging.error(f"SYCL propagation {bench_type} is not implemented")
0131
0132
0133 for f in input_data_files:
0134 if not os.path.isfile(f):
0135 logging.error(f"File does not exist: {f}")
0136 sys.exit(1)
0137
0138
0139 input_dir = os.path.dirname(f)
0140 file_name = os.path.basename(f)
0141 bknd, bknd_name, algebra, setup, cores = __read_context_metadata(
0142 logging, input_dir, file_name
0143 )
0144
0145 if bknd not in benchmarks:
0146 benchmarks[bknd] = {}
0147
0148 if bknd_name not in benchmarks[bknd]:
0149 benchmarks[bknd][bknd_name] = []
0150
0151 context, _ = read_benchmark_data(logging, input_dir, file_name)
0152 if bench_type in context["executable"]:
0153 benchmarks[bknd][bknd_name].append(
0154 benchmark_metadata(
0155 name=bknd_name, algebra=algebra, setup=setup, file=f, cores=cores
0156 )
0157 )
0158
0159
0160 for bknd, metadata_dict in benchmarks.items():
0161
0162 if len(algebra_plugins) == 0:
0163 break
0164
0165
0166 bknd_name = "Unknown"
0167 if bknd == "CUDA" or bknd == "HIP_NVIDIA" or bknd == "SYCL":
0168 bknd_name = "Unknown NVIDIA GPU"
0169 try:
0170 import nvidia_smi
0171
0172 try:
0173 nvidia_smi.nvmlInit()
0174 handle = nvidia_smi.nvmlDeviceGetHandleByIndex(0)
0175
0176 bknd_name = nvidia_smi.nvmlDeviceGetName(handle)
0177
0178 nvidia_smi.nvmlShutdown()
0179
0180 except NVMLError as e:
0181 print(e)
0182
0183 except ModuleNotFoundError:
0184 print(
0185 "Python module 'nvidia_smi' is not installed: Falling back on running nvidia-smi as subprocess"
0186 )
0187
0188 try:
0189 gpu_str = str(
0190 subprocess.check_output(
0191 [
0192 "nvidia-smi",
0193 "--query-gpu",
0194 "name",
0195 "--format=csv,noheader",
0196 ]
0197 )
0198 )
0199 gpu_str = __compactify_bknd_name(gpu_str[2:])
0200
0201
0202 if gpu_str[-1] == '"' or gpu_str[-1] == "'":
0203 gpu_str = gpu_str[:-1]
0204 if gpu_str[-2:] == "\\n":
0205 gpu_str = gpu_str[:-2]
0206
0207 if len(gpu_str) != 0:
0208 bknd_name = gpu_str.rstrip(os.linesep)
0209
0210 except Exception as e:
0211
0212 print(e)
0213
0214 bknd_name = f"{bknd.removesuffix('_NVIDIA')} {bknd_name}"
0215
0216 elif bknd == "HIP_AMD":
0217 bknd_name = "Unknown AMD GPU"
0218 try:
0219
0220 from amdsmi import (
0221 amdsmi_init,
0222 amdsmi_shut_down,
0223 amdsmi_get_processor_handles,
0224 amdsmi_get_gpu_asic_info,
0225 AmdSmiException,
0226 )
0227
0228 try:
0229 amdsmi_init()
0230 devices = amdsmi_get_processor_handles()
0231 if len(devices) == 0:
0232 print("No AMD GPUs on machine")
0233 else:
0234 asic_info = amdsmi_get_gpu_asic_info(devices[0])
0235 bknd_name = asic_info["market_name"]
0236
0237 except AmdSmiException as e:
0238 print(e)
0239 finally:
0240 try:
0241 amdsmi_shut_down()
0242 except AmdSmiException as e:
0243 print(e)
0244
0245 except ModuleNotFoundError:
0246 print(
0247 "Python module 'amdsmi' is not installed: Cannot find AMD GPU name"
0248 )
0249
0250 bknd_name = f"{bknd.removesuffix('_AMD')} {bknd_name}"
0251 else:
0252 bknd_name = __compactify_bknd_name(platform.processor())
0253
0254 if bknd_name not in metadata_dict:
0255 metadata_dict[bknd_name] = []
0256
0257
0258 registered_algebra = [data.algebra for data in metadata_dict[bknd_name]]
0259
0260
0261 for algebra in algebra_plugins:
0262
0263 if algebra in registered_algebra:
0264 continue
0265
0266
0267 setup = ""
0268 add_delim = lambda s: s + ", "
0269 if not args.grid_file:
0270 setup = setup + "no grids"
0271 if not args.material_file:
0272 if len(setup) != 0:
0273 setup = add_delim(setup)
0274 setup = setup + "no mat."
0275 if not args.covariance_transport:
0276 if len(setup) != 0:
0277 setup = add_delim(setup)
0278 setup = setup + "no cov."
0279
0280 binary = (
0281 f"{bindir}/detray_propagation_{bench_type}_{bknd.lower()}_{algebra}"
0282 )
0283 file_bknd_name = bknd_name.replace(" ", "_")
0284 file_setup = setup.replace(" ", "_")
0285 file_setup = file_setup.replace(",", "")
0286 file_setup = file_setup.replace(".", "")
0287 data_file = f"{det_name}_{bench_type}_{bknd.lower()}_{file_bknd_name}_{algebra}_{file_setup}.json"
0288 cores = os.cpu_count() / 2
0289
0290 metadata = benchmark_metadata(
0291 name=bknd_name,
0292 algebra=algebra,
0293 setup=setup,
0294 file=data_file,
0295 cores=cores,
0296 )
0297
0298
0299 if data_file not in (os.path.basename(f) for f in input_data_files):
0300
0301 if os.path.isdir(bindir) and os.path.isfile(binary):
0302 metadata = metadata._replace(bin=binary)
0303 else:
0304 logging.warning(
0305 f"Propagation {bench_type} binary not found! ({binary})"
0306 )
0307 continue
0308
0309 metadata_dict[bknd_name].append(metadata)
0310
0311 return benchmarks
0312
0313
0314
0315 def __run_benchmarks(benchmark_dict, args_list, benchmark_options):
0316 for bknd, metadata_dict in benchmark_dict.items():
0317 for bknd_name, metadata_list in metadata_dict.items():
0318 for metadata in metadata_list:
0319 if metadata.bin is not None:
0320 subprocess.run(
0321 [
0322 metadata.bin,
0323 f"--bknd_name={bknd_name}",
0324 f"--benchmark_out=./{metadata.file}",
0325 ]
0326 + benchmark_options
0327 + args_list
0328 )
0329
0330
0331 def __main__():
0332
0333
0334
0335 descr = "Detray Propagation Benchmark"
0336
0337
0338 parent_parsers = [
0339 common_options(descr),
0340 detector_io_options(),
0341 random_track_generator_options(),
0342 propagation_options(),
0343 plotting_options(),
0344 ]
0345
0346 parser = argparse.ArgumentParser(description=descr, parents=parent_parsers)
0347
0348 parser.add_argument(
0349 "--bindir",
0350 "-bin",
0351 help=("Directory containing the benchmark executables"),
0352 default="./bin",
0353 type=str,
0354 )
0355 parser.add_argument(
0356 "--cuda",
0357 help=("Run the CUDA propagation benchmarks."),
0358 action="store_true",
0359 default=False,
0360 )
0361 parser.add_argument(
0362 "--hip_amd",
0363 help=("Run the HIP AMD propagation benchmarks."),
0364 action="store_true",
0365 default=False,
0366 )
0367 parser.add_argument(
0368 "--hip_nvidia",
0369 help=("Run the HIP NVIDIA propagation benchmarks."),
0370 action="store_true",
0371 default=False,
0372 )
0373 parser.add_argument(
0374 "--sycl",
0375 help=("Run the SYCL propagation benchmarks (Not implemented)."),
0376 action="store_true",
0377 default=False,
0378 )
0379 parser.add_argument(
0380 "--sort_tracks",
0381 help=("Sort the track samples by theta."),
0382 action="store_true",
0383 default=False,
0384 )
0385 parser.add_argument(
0386 "--benchmark_repetitions",
0387 help=("Number of repeated benchmark runs."),
0388 default=2,
0389 type=int,
0390 )
0391 parser.add_argument(
0392 "--algebra_plugins",
0393 "-ap",
0394 nargs="*",
0395 help=(
0396 "Algebra plugins to be benchmarked (the plugin must be enabled at build time)."
0397 ),
0398 default=[],
0399 type=str,
0400 )
0401 parser.add_argument(
0402 "--data_files",
0403 "-f",
0404 nargs="*",
0405 help=("Read the benchmark results from a Google benchmark json file instead."),
0406 default=[],
0407 type=str,
0408 )
0409
0410
0411 args = parser.parse_args()
0412
0413 logging = parse_common_options(args, descr)
0414 parse_detector_io_options(args, logging)
0415 input_dir, out_dir, out_format = parse_plotting_options(args, logging)
0416
0417
0418 bindir = args.bindir.strip("/")
0419
0420
0421 det_name = read_detector_name(args.geometry_file, logging)
0422 logging.debug("Detector: " + det_name)
0423
0424
0425 input_data_files = __parse_input_data_files(args, logging)
0426
0427
0428 algebra_plugins = set(args.algebra_plugins)
0429
0430 if len(algebra_plugins) == 0 and len(input_data_files) == 0:
0431 logging.error(
0432 "No data file for plotting and no algebra plugins specified to run benchmarks for. Quitting"
0433 )
0434 sys.exit(1)
0435
0436
0437 benchmarks = __generate_benchmark_dict(
0438 args, logging, bindir, det_name, input_data_files, algebra_plugins, "benchmark"
0439 )
0440
0441 scaling = __generate_benchmark_dict(
0442 args, logging, bindir, det_name, input_data_files, algebra_plugins, "scaling"
0443 )
0444
0445
0446
0447
0448 args_list = []
0449
0450
0451 add_detector_io_args(args_list, args)
0452 add_track_generator_args(args_list, args)
0453 add_propagation_args(args_list, args)
0454
0455 if args.sort_tracks:
0456 args_list.append("--sort_tracks")
0457
0458 logging.debug(args_list)
0459
0460
0461 benchmark_options = [
0462 f"--benchmark_repetitions={args.benchmark_repetitions}",
0463
0464 "--benchmark_display_aggregates_only=true",
0465
0466 "--benchmark_out_format=json",
0467 ]
0468
0469
0470 __run_benchmarks(benchmarks, args_list, benchmark_options)
0471 __run_benchmarks(scaling, args_list, benchmark_options)
0472
0473
0474
0475 logging.info("Generating plots...\n")
0476
0477 plot_factory = plt_factory(out_dir, logging)
0478
0479 def make_label(algebra, setup):
0480 label = f"{algebra}"
0481 if len(setup) != 0:
0482 label = label + f" ({setup})"
0483 return label
0484
0485
0486
0487 for bknd, metadata_dict in benchmarks.items():
0488 for bknd_name, metadata_list in metadata_dict.items():
0489 for metadata in metadata_list:
0490
0491 files = [metadata.file for metadata in metadata_list]
0492 plot_labels = [
0493 make_label(metadata.algebra, metadata.setup)
0494 for metadata in metadata_list
0495 ]
0496
0497 file_bknd_name = bknd_name.replace(" ", "_")
0498 plot_benchmark_data(
0499 logging,
0500 input_dir,
0501 det_name,
0502 files,
0503 plot_labels,
0504 f"hardware backend: {bknd} ({bknd_name})",
0505 f"prop_benchmark_algebra-plugin_comparison_{bknd}_{file_bknd_name}",
0506 plot_factory,
0507 out_format,
0508 )
0509
0510
0511
0512 discovered_algs = []
0513 for bknd, metadata_dict in benchmarks.items():
0514 for bknd_name, metadata_list in metadata_dict.items():
0515 for metadata in metadata_list:
0516 discovered_algs.append(metadata.algebra)
0517
0518 discovered_algs = set(discovered_algs)
0519
0520
0521 for algebra in discovered_algs:
0522 data_files_per_plugin = []
0523 plot_labels = []
0524
0525 for bknd, metadata_dict in benchmarks.items():
0526
0527 for bknd_name, metadata_list in metadata_dict.items():
0528
0529 for metadata in metadata_list:
0530 if algebra == metadata.algebra:
0531 data_files_per_plugin.append(metadata.file)
0532 label = make_label(f"{bknd_name}", metadata.setup)
0533 plot_labels.append(label)
0534
0535 plot_benchmark_data(
0536 logging,
0537 input_dir,
0538 det_name,
0539 data_files_per_plugin,
0540 plot_labels,
0541 f"algebra-plugin: {algebra}",
0542 f"prop_benchmark_backend_comparison_{algebra}",
0543 plot_factory,
0544 out_format,
0545 )
0546
0547
0548 for bknd, metadata_dict in scaling.items():
0549 for bknd_name, metadata_list in metadata_dict.items():
0550 for metadata in metadata_list:
0551
0552 files = [metadata.file for metadata in metadata_list]
0553 plot_labels = [
0554 make_label(metadata.algebra, metadata.setup)
0555 for metadata in metadata_list
0556 ]
0557
0558 plot_scaling_data(
0559 logging,
0560 input_dir,
0561 det_name,
0562 files,
0563 plot_labels,
0564 f"hardware backend: {bknd} ({bknd_name})",
0565 plot_factory,
0566 out_format,
0567 [1, 2, 4, 8, 16, 24, 32, 48, 64, 96, 128, 256],
0568 metadata.cores,
0569 )
0570
0571
0572
0573
0574 if __name__ == "__main__":
0575 __main__()
0576
0577