NIXL Bench#
This workload (test_template_name is NIXLBench) runs NIXL benchmarking suite for network and interconnect performance testing.
Usage Examples#
Test TOML example:
name = "my_nixl_bench_test"
description = "Example NIXL Bench test"
test_template_name = "NIXLBench"
[cmd_args]
docker_image_url = "<docker container url here>"
path_to_benchmark = "/workspace/nixlbench/build/nixlbench"
backend = "UCX"
initiator_seg_type = "VRAM"
target_seg_type = "VRAM"
op_type = "READ"
filepath = "/data"
device_list = "11:F:/store0.bin"
# one could also use <num>kb, <num>mb, <num>gb shortcuts
total_buffer_size = 8000000000
Test Scenario example:
name = "nixl-bench-test"
[[Tests]]
id = "bench.1"
num_nodes = 1
time_limit = "00:10:00"
test_name = "my_nixl_bench_test"
Test-in-Scenario example:
name = "nixl-bench-test"
[[Tests]]
id = "bench.1"
num_nodes = 1
time_limit = "00:10:00"
name = "my_nixl_bench_test"
description = "Example NIXL Bench test"
test_template_name = "NIXLBench"
[Tests.cmd_args]
docker_image_url = "<docker container url here>"
path_to_benchmark = "/workspace/nixlbench/build/nixlbench"
backend = "UCX"
initiator_seg_type = "DRAM"
target_seg_type = "DRAM"
op_type = "WRITE"
Runtime Coordination#
NIXLBench uses ETCD by default. CloudAI starts ETCD from the benchmark image when
etcd_image_url is omitted, or from the configured image.
To use NIXLBench’s direct two-process ASIO runtime instead, set:
runtime_type = "ASIO"
CloudAI resolves asio_address to the first allocated node by default and does not
install or start ETCD. asio_address and asio_port can be overridden explicitly.
ASIO requires exactly two NIXLBench processes. For UCX, a one-node test runs both
processes locally, while a two-node test runs one process on each node.
Storage backends can run without either runtime by using an empty ETCD endpoint:
backend = "POSIX"
etcd_endpoints = ""
This null-runtime mode is limited to storage backends and launches one NIXLBench process by default.
Independent Storage Processes#
To run independent storage benchmarks in one allocation, set
launch_mode = "independent" and etcd_endpoints = "". CloudAI launches one
process per node by default; use num_nodes to choose the number of nodes:
name = "storage-scaling"
[[Tests]]
id = "storage.4nodes"
test_name = "my_storage_test"
num_nodes = 4
[Tests.cmd_args]
launch_mode = "independent"
etcd_endpoints = ""
num_threads = [4, 8]
Here, my_storage_test is a NIXLBench test defining the storage backend, container
image, benchmark path and workload arguments. CloudAI runs the 4-thread and 8-thread
configurations as separate tests.
launch_mode selects CloudAI’s launch strategy and is not passed to NIXLBench.
Its default value, "default", preserves existing behavior, including when task
placement options are present. Placement options alone do not enable independent runs.
Independent mode requires etcd_endpoints = "" and the default
runtime_type = "ETCD" setting, which together select NIXLBench’s null runtime.
Managed/external ETCD and ASIO cannot be used with this mode. CloudAI launches one
Slurm step across the requested nodes. Use extra_srun_args only when overriding
the default task placement. System-level options precede test-level options.
Each task executes in its own shell. Node-specific environment values and command expansions are evaluated there. CloudAI does not discover backend devices.
Results and Reporting#
Independent runs retain nixlbench/<task-id>.stdout, .stderr, .status and
.hostname files. The nixlbench/ntasks file records the actual Slurm task count.
A failed process, missing task output or inconsistent block-size/batch-size coverage
makes the run unsuccessful; incomplete results are not aggregated.
nixlbench_per_task.csv preserves individual measurements with task IDs and hostnames.
nixlbench.csv summarizes matching block sizes and batch sizes: avg_lat and
bw_gb_sec are arithmetic means across tasks, bw_min_gb_sec is the minimum
task bandwidth, bw_sum_gb_sec is the sum, and task_count records the contributors.
The native HTML report shows mean latency and minimum/mean/summed bandwidth, with
separate plots for each batch size. Comparison reports and metric observations use
the mean per-task bandwidth and latency. Existing single-process reports are unchanged.
API Documentation#
Command Arguments#
- pydantic model cloudai.workloads.nixl_bench.nixl_bench.NIXLBenchCmdArgs[source]#
Command line arguments for a NIXL Bench test.
- field path_to_benchmark: str [Required]#
- field launch_mode: Literal['default', 'independent'] = 'default'#
CloudAI launch mode: ‘default’ preserves existing orchestration; ‘independent’ launches one null-runtime task per node in one Slurm step by default. Use num_nodes to select the node count and extra_srun_args to override task placement. Not passed to NIXLBench.
- field etcd_endpoints: str = 'http://$NIXL_ETCD_ENDPOINTS'#
- field runtime_type: Literal['ETCD', 'ASIO'] = 'ETCD'#
- field asio_address: str = '$NIXL_ASIO_ADDRESS'#
- field asio_port: int = 12345#
- Constraints:
ge = 1
le = 65535
- field docker_image_url: str [Required]#
URL of the Docker image to use for the benchmark.
- field etcd_path: str = 'etcd'#
Path to the etcd executable.
- field wait_etcd_for: int = 60#
Number of seconds to wait for etcd to become healthy.
- field etcd_image_url: str | None = None#
Optional URL of the Docker image to use for etcd, by default etcd will be run from the same image as the benchmark.
- field filepath: str | None = None#
Directory path (in container) for storage operations. Example: /data
- field total_buffer_size: str | list[str] | None = None#
Total buffer size in bytes. Examples: 1024, 1kb, 1mb, 1gb. Use with device_list. The size will be passed into NIXL as integer (bytes)
- field device_list: str | list[str] | None = None#
Device specs in format ‘id:type:path’ (e.g., ‘11:F:/store0.bin,27:K:/dev/nvme0n1’)
Test Definition#
- class cloudai.workloads.nixl_bench.nixl_bench.NIXLBenchTestDefinition(*, name: str, description: str, test_template_name: str, cmd_args: ~cloudai.workloads.nixl_bench.nixl_bench.NIXLBenchCmdArgs, dse_excluded_args: list[str] = <factory>, extra_env_vars: dict[str, str | ~typing.List[str]] = {}, extra_cmd_args: dict[str, str] = {}, extra_container_mounts: list[str] = [], git_repos: list[~cloudai._core.installables.git_repo.GitRepo] = [], nsys: ~cloudai.models.workload.NsysConfiguration | None = None, predictor: ~cloudai.models.workload.PredictorConfig | None = None, training_report: ~cloudai.models.workload.TrainingReportConfig | None = None, agent: str = 'grid_search', agent_steps: int = 1, agent_metrics: list[str] = ['default'], agent_reward_function: str = 'inverse', agent_config: dict[str, ~typing.Any] | None = None, env_params: dict[str, ~cloudai.configurator.env_params.EnvParamSpec] = <factory>)[source]#
Bases:
NIXLBaseTestDefinition[NIXLBenchCmdArgs]Test definition for a NIXL Bench test.
- property uses_etcd: bool#
Return whether CloudAI should launch ETCD for this benchmark.
- property uses_asio: bool#
Return whether this benchmark uses NIXLBench’s ASIO runtime.
- metric_observations(
- system: System,
- tr: TestRun,
Return canonical metric observations produced by this test run, if supported.
- property is_domain_randomization_enabled: bool#
at least one
env_paramsannotation.- Type:
Whether the config declares domain randomization
- is_dse_excluded_arg(path: str) bool#
Return whether a dot-separated cmd_args path should be ignored by DSE.
- is_env_sampled(cmd_args_path: str) bool#
Whether a cmd_args field is env-sampled (env draws it per trial, not the agent).
- validator validate_env_params » all fields#
Validate env_params annotations against cmd_args.
env_paramsis an annotation: each key names acmd_argsfield whose value is the candidate set (the single source of truth), and the entry carries only how to sample. So each key must name a realcmd_argsfield whose value is a candidate list; a scalar is already fixed, so annotating it is a meaningless label and is rejected here. Whenweightsare declared, the list needs >= 2 values and the weights must align 1:1 with it. Sampling, persistence, the per-trial cmd_args overlay, and the cache key all live inCloudAIGymEnv; keeping this shape check in core lets the overlay stay agent- and workload-agnostic rather than re-implemented per workload.