This directory contains example configurations for deploying madengine workloads on SLURM HPC clusters.
No explicit deploy field needed! The presence of a slurm field automatically indicates SLURM deployment:
{
"slurm": {
"partition": "amd-rccl",
"nodes": 2,
"gpus_per_node": 8
}
}amd-rccl (for AMD RCCL clusters). If your cluster uses a different partition name (e.g., gpu, compute, batch), override it in your configuration:
{
"slurm": {
"partition": "your-partition-name" // Override default
}
}Check your cluster's partitions:
sinfo -o "%P" # List all available partitionsThe deployment type is inferred from the configuration structure:
- ✅ Deployment type (k8s/slurm/local) inferred from config structure
- ✅ Layered defaults: base → profile → user configuration
- ✅ Intelligent profile selection based on node count
| File | Description | Nodes | GPUs | Use Case |
|---|---|---|---|---|
01-single-node-single-gpu.json |
Single GPU training | 1 | 1 | Quick tests, small models |
02-single-node-multi-gpu.json |
Single node, 8 GPUs | 1 | 8 | Single-node distributed workload |
03-multi-node-basic.json |
2 nodes, 8 GPUs each | 2 | 16 | Multi-node distributed workload |
03-multi-node-basic-nodelist.json |
Same as 03 with nodelist |
2 | 16 | Pin job to specific nodes (e.g. node01,node02) |
04-multi-node-advanced.json |
4 nodes, advanced features | 4 | 32 | Production-scale training |
| File | Description | Nodes | GPUs | Use Case |
|---|---|---|---|---|
05-vllm-single-node.json |
Single node vLLM | 1 | 4 | Single-node LLM inference |
06-vllm-multi-node.json |
Multi-node vLLM | 2 | 8 | Multi-node LLM inference with Ray |
Stripped-down configurations showing only essential fields:
torchrun-single-gpu-minimal.json- Minimal single GPU configtorchrun-multi-gpu-minimal.json- Minimal 8 GPU configtorchrun-multi-node-minimal.json- Minimal 2-node configvllm-single-node-minimal.json- Minimal vLLM single-nodevllm-multi-node-minimal.json- Minimal vLLM multi-nodeslurm-multi-minimal.json- Minimal slurm_multi self-managed launcher (3 nodes)
For slurm_multi escape-hatch launcher, see Launchers Guide.
Understanding how configurations flow through madengine:
┌──────────────────────────────────────────────────┐
│ 1. Config File (*.json) │
│ - Contains: slurm, distributed, env_vars │
└──────────────────┬───────────────────────────────┘
│ --additional-context-file
↓
┌──────────────────────────────────────────────────┐
│ 2. madengine build │
│ - BuildOrchestrator._save_deployment_config() │
│ - Extracts env_vars, slurm, distributed │
└──────────────────┬───────────────────────────────┘
│
↓
┌──────────────────────────────────────────────────┐
│ 3. build_manifest.json │
│ - deployment_config.env_vars (saved) │
│ - deployment_config.slurm (saved) │
└──────────────────┬───────────────────────────────┘
│ --manifest-file
↓
┌──────────────────────────────────────────────────┐
│ 4. madengine run │
│ - RunOrchestrator._execute_*() │
│ - Loads deployment_config from manifest │
└──────────────────┬───────────────────────────────┘
│
↓
┌──────────────────────────────────────────────────┐
│ 5. Docker Container Environment │
│ - env_vars passed to container │
│ - SLURM job submitted with configuration │
└──────────────────────────────────────────────────┘
Key Points:
- ✅ Config files are the source of truth - Don't edit
build_manifest.jsonmanually - ✅ Build phase embeds configuration - Configuration is saved during build for use at runtime
- ✅ Run phase uses manifest - All settings come from the generated manifest
- ✅ Environment variables flow automatically - From config → manifest → Docker
When using configuration files with env_vars, use the two-phase workflow:
# SSH to SLURM login node first
ssh user@hpc-cluster.example.com
# Phase 1: Build with configuration
MODEL_DIR=models/my-model madengine build \
--tags model_tag \
--additional-context-file examples/slurm-configs/basic/03-multi-node-basic.json \
--manifest-output build_manifest.json
# Phase 2: Run from manifest
MODEL_DIR=models/my-model madengine run \
--manifest-file build_manifest.jsonWhy two phases?
- Build phase embeds your
env_varsand deployment config into the manifest - Run phase uses the pre-configured manifest
- Ensures consistency across builds and deployments
For quick tests without custom env_vars:
madengine run --tags model_tag \
--additional-context-file examples/slurm-configs/minimal/torchrun-single-gpu-minimal.jsonmadengine run --tags model_tag \
--additional-context '{
"slurm": {
"partition": "gpu",
"nodes": 2,
"gpus_per_node": 8,
"time": "24:00:00"
}
}'# Use base config, override specific fields
madengine run --tags model_tag \
--additional-context-file examples/slurm-configs/basic/03-multi-node-basic.json \
--additional-context '{"slurm": {"nodes": 4, "time": "48:00:00"}}'The SLURM deployment automatically configures distributed execution for multi-node and multi-GPU setups (training with torchrun/deepspeed or inference with vLLM/SGLang):
- Environment Variables: SLURM sets distributed execution environment (MASTER_ADDR, MASTER_PORT, RANK, etc.)
- MAD_MULTI_NODE_RUNNER: Automatically configured with the appropriate
torchruncommand - Docker Containers: Environment variables are passed into containers via
docker_env_vars - Model Scripts: Use
$MAD_MULTI_NODE_RUNNERto launch training (see below)
Your model's run script should use the MAD_MULTI_NODE_RUNNER environment variable:
#!/bin/bash
# Example: scripts/my_model/run.sh
# MAD_MULTI_NODE_RUNNER is automatically set by madengine for distributed workloads
if [ -z "$MAD_MULTI_NODE_RUNNER" ]; then
# Fallback for standalone execution
N_GPUS="${MAD_RUNTIME_NGPUS:-1}"
MAD_MULTI_NODE_RUNNER="torchrun --standalone --nproc_per_node=$N_GPUS"
fi
# Launch your Python training script with torchrun
$MAD_MULTI_NODE_RUNNER train.py --your-argsThe following variables are automatically available in your containers:
| Variable | Description | Example |
|---|---|---|
MASTER_ADDR |
Master node address | node001 |
MASTER_PORT |
Master communication port | 29500 |
WORLD_SIZE |
Total number of processes | 16 (2 nodes × 8 GPUs) |
RANK |
Global process rank | 0, 1, ... |
LOCAL_RANK |
Local GPU rank on node | 0-7 |
NNODES |
Number of nodes | 2 |
NPROC_PER_NODE |
GPUs per node | 8 |
MAD_MULTI_NODE_RUNNER |
Complete torchrun command | torchrun --nnodes=2 ... |
Single-Node Multi-GPU (Data Parallel):
{
"slurm": {
"nodes": 1,
"gpus_per_node": 8
}
}→ MAD_MULTI_NODE_RUNNER="torchrun --standalone --nproc_per_node=8"
Multi-Node Distributed Workload:
{
"slurm": {
"nodes": 4,
"gpus_per_node": 8
}
}→ MAD_MULTI_NODE_RUNNER="torchrun --nnodes=4 --nproc_per_node=8 --node_rank=$SLURM_PROCID --master_addr=$MASTER_ADDR --master_port=29500"
Check that distributed execution is configured correctly:
# In your SLURM output logs, you should see:
Distributed Execution Configuration:
NNODES: 2
GPUS_PER_NODE: 8
TOTAL_GPUS: 16
MASTER_ADDR: node001
MASTER_PORT: 29500
NODE_RANK: 0
Launcher: torchrun (distributed)
MAD_MULTI_NODE_RUNNER: torchrun --nnodes=2 --nproc_per_node=8 ...vLLM is a high-throughput LLM inference engine. madengine provides pre-configured setups for both single-node and multi-node deployments.
vLLM configurations include critical memory management environment variables to prevent OOM (Out of Memory) errors, especially in multi-node deployments with pipeline parallelism.
1. VLLM_KV_CACHE_SIZE
- Purpose: Limits the percentage of GPU memory allocated for KV cache
- Default in configs:
0.8(80% of available GPU memory) - Why needed: Prevents vLLM from aggressively allocating all available memory, which can cause fragmentation and OOM errors
- Tuning:
- Increase (e.g.,
0.9) if you have large memory headroom - Decrease (e.g.,
0.6,0.7) if experiencing OOM errors
- Increase (e.g.,
2. PYTORCH_CUDA_ALLOC_CONF
- Purpose: Configures PyTorch's CUDA/HIP memory allocator
- Value:
expandable_segments:True - Why needed: Reduces memory fragmentation by allowing the allocator to expand memory segments dynamically
- Reference: PyTorch Memory Management
Single-Node Configurations:
05-vllm-single-node.json- Full single-node config with NCCL settingsvllm-single-node-minimal.json- Minimal single-node config (inminimal/directory)
Multi-Node Configurations:
06-vllm-multi-node.json- Full multi-node config with NCCL and Ray settingsvllm-multi-node-minimal.json- Minimal multi-node config (inminimal/directory)
# 1. Build with vLLM configuration
MODEL_DIR=models/llama2-70b madengine build \
--tags vllm \
--additional-context-file examples/slurm-configs/basic/06-vllm-multi-node.json \
--manifest-output build_manifest.json
# 2. Verify memory management env_vars were embedded
grep -A 10 "env_vars" build_manifest.json
# Should show:
# "VLLM_KV_CACHE_SIZE": "0.8"
# "PYTORCH_CUDA_ALLOC_CONF": "expandable_segments:True"
# 3. Run the inference job
MODEL_DIR=models/llama2-70b madengine run \
--manifest-file build_manifest.jsonvLLM automatically selects parallelism based on your configuration:
Single-Node (TP only):
{
"slurm": {
"nodes": 1,
"gpus_per_node": 4
},
"distributed": {
"launcher": "vllm",
"nnodes": 1,
"nproc_per_node": 4
}
}→ Tensor Parallelism (TP) = 4 across GPUs
Multi-Node (TP + PP):
{
"slurm": {
"nodes": 2,
"gpus_per_node": 4
},
"distributed": {
"launcher": "vllm",
"nnodes": 2,
"nproc_per_node": 4
}
}→ Tensor Parallelism (TP) = 4 within each node
→ Pipeline Parallelism (PP) = 2 across nodes
→ Requires Ray cluster for multi-node coordination
madengine uses intelligent multi-layer configuration merging:
┌─────────────────────────────────┐
│ 1. Base Defaults │ ← slurm/defaults.json
│ (partition, time, etc.) │
├─────────────────────────────────┤
│ 2. Profile Selection │ ← single-node.json or multi-node.json
│ (auto-selected by nodes) │ (based on nodes count)
├─────────────────────────────────┤
│ 3. User Configuration │ ← Your config file + CLI args
│ (highest priority) │
└─────────────────────────────────┘
- Single-node profile: Applied when
nodes == 1 - Multi-node profile: Applied when
nodes > 1
{
"slurm": {
"partition": "amd-rccl", // SLURM partition name (default: amd-rccl)
"nodes": 2, // Number of nodes
"nodelist": "node01,node02", // Optional: restrict job to these nodes (skips node health preflight)
"gpus_per_node": 8, // GPUs per node
"time": "24:00:00", // Wall time (HH:MM:SS)
"output_dir": "./slurm_results", // Local output directory
"results_dir": "/shared/results", // Shared results collection
"shared_workspace": "/shared/workspace", // Shared workspace (NFS/Lustre)
"exclusive": true, // Exclusive node access
"reservation": "my-reservation", // Optional SLURM reservation name
"qos": "high", // Quality of Service
"account": "project-name", // SLURM account
"network_interface": "ib0", // Network interface (ib0/eth0)
"modules": ["rocm/5.7.0"], // Environment modules to load
"enable_node_check": true, // Run node health preflight before submission (default: true)
"auto_cleanup_nodes": false, // Automatically clean up unhealthy nodes found during preflight (default: false)
"allow_submit_without_clean_nodes": false, // Submit even if fewer clean nodes than requested are found (default: false)
"verbose_node_check": false // Print detailed node health-check output (default: false)
}
}nodelist: When set to a comma-separated list of node names (e.g. "node01,node02"), the job runs only on those nodes. Automatic node health preflight is skipped when nodelist is set.
Node Health Preflight: Before submitting multi-node jobs, madengine runs a health check across candidate nodes and pins the job to the healthy ones (skipped if nodelist is set).
enable_node_check(defaulttrue): Enables/disables the preflight health check.auto_cleanup_nodes(defaultfalse): Automatically attempts to clean up unhealthy nodes found during preflight.allow_submit_without_clean_nodes(defaultfalse): If fewer clean nodes are found than requested, submit anyway instead of failing.verbose_node_check(defaultfalse): Print detailed health-check output during preflight.
{
"distributed": {
"launcher": "torchrun", // Launcher type: torchrun, vllm, sglang, deepspeed, megatron, slurm_multi
"backend": "nccl", // Communication backend (nccl/gloo)
"port": 29500, // Master node port
"nnodes": 2, // Number of nodes (overrides slurm.nodes if set)
"nproc_per_node": 8 // GPUs per node (overrides slurm.gpus_per_node if set)
}
}Supported Launchers:
torchrun: PyTorch distributed training (default)vllm: vLLM inference engine (TP/PP parallelism)sglang: SGLang inference enginedeepspeed: DeepSpeed training frameworkmegatron: Megatron-LM large model trainingslurm_multi/slurm-multi: Self-managed multi-container topologies (escape hatch)- Custom: Set environment variables, model script handles launcher
Note: For vLLM and SGLang, the model script handles process spawning directly.
For torchrun/deepspeed/megatron, use $MAD_MULTI_NODE_RUNNER in your model script.
For slurm_multi, the model's .slurm script runs on baremetal and manages Docker containers via srun internally.
{
"env_vars": {
"NCCL_DEBUG": "WARN",
"NCCL_SOCKET_IFNAME": "ib0",
"OMP_NUM_THREADS": "8",
"MIOPEN_FIND_MODE": "1",
"VLLM_KV_CACHE_SIZE": "0.8",
"PYTORCH_CUDA_ALLOC_CONF": "expandable_segments:True"
}
}Note: Environment variables set in config files are:
- Saved to
deployment_config.env_varsduringbuildphase - Automatically passed to Docker containers during
runphase - Available to your model scripts inside containers
madengine run --tags my_model \
--additional-context-file examples/slurm-configs/minimal/torchrun-single-gpu-minimal.json# Build with config
MODEL_DIR=models/my-model madengine build \
--tags training \
--additional-context-file examples/slurm-configs/basic/03-multi-node-basic.json
# Run from manifest
MODEL_DIR=models/my-model madengine run \
--manifest-file build_manifest.json# Build with vLLM config
MODEL_DIR=models/llama2-13b madengine build \
--tags vllm \
--additional-context-file examples/slurm-configs/basic/05-vllm-single-node.json
# Run inference
MODEL_DIR=models/llama2-13b madengine run \
--manifest-file build_manifest.json# Build with multi-node vLLM config
MODEL_DIR=models/llama2-70b madengine build \
--tags vllm \
--additional-context-file examples/slurm-configs/basic/06-vllm-multi-node.json
# Run multi-node inference
MODEL_DIR=models/llama2-70b madengine run \
--manifest-file build_manifest.jsonmadengine build --tags my_model \
--additional-context-file examples/slurm-configs/basic/04-multi-node-advanced.json
madengine run --manifest-file build_manifest.jsonFor custom memory configurations, create a new config file:
{
"slurm": {
"partition": "amd-rccl",
"nodes": 2,
"gpus_per_node": 8,
"time": "04:00:00"
},
"distributed": {
"launcher": "vllm",
"nnodes": 2,
"nproc_per_node": 8
},
"env_vars": {
"VLLM_KV_CACHE_SIZE": "0.7",
"PYTORCH_CUDA_ALLOC_CONF": "expandable_segments:True",
"VLLM_ALLOW_LONG_MAX_MODEL_LEN": "1",
"HSA_FORCE_FINE_GRAIN_PCIE": "1"
}
}The slurm_multi launcher is an escape hatch for workloads that orchestrate their own Docker containers via srun (e.g. SGLang Disaggregated proxy + prefill + decode topologies). Unlike templated launchers, the model's .slurm script runs directly on baremetal.
# 1. Build with pre-built image (slurm_multi typically uses external images)
madengine build --tags sglang_disagg \
--use-image lmsysorg/sglang:latest
# 2. Run — launcher auto-detected from model card
madengine run --manifest-file build_manifest.jsonWhen running inside an existing salloc allocation, slurm_multi runs synchronously with bash instead of nesting sbatch:
salloc --nodes=3 --gpus-per-node=8 --partition=gpu
madengine run --manifest-file build_manifest.json
# → Detected existing SLURM allocation: runs with bash{
"slurm": {
"partition": "gpu",
"nodes": 3,
"gpus_per_node": 8,
"time": "04:00:00",
"exclusive": true,
"reservation": "my-reservation"
},
"distributed": {
"launcher": "slurm_multi",
"nnodes": 3,
"nproc_per_node": 8
}
}See Launchers Guide — slurm_multi for full details.
Load specific software versions:
{
"slurm": {
"modules": [
"rocm/5.7.0",
"gcc/11.2.0",
"openmpi/4.1.4"
]
}
}Configure shared workspace and data:
{
"slurm": {
"shared_workspace": "/lustre/workspace",
"results_dir": "/lustre/results"
},
"shared_data": "/lustre/datasets"
}For InfiniBand clusters:
{
"slurm": {
"network_interface": "ib0"
},
"env_vars": {
"NCCL_SOCKET_IFNAME": "ib0",
"NCCL_IB_DISABLE": "0",
"NCCL_IB_HCA": "mlx5_0:1,mlx5_1:1"
}
}After submission, monitor your SLURM job:
# Check job status
squeue -u $USER
# View job details
scontrol show job <job_id>
# View output logs (real-time)
tail -f slurm_results/madengine-*_<job_id>_*.out
# View error logs
tail -f slurm_results/madengine-*_<job_id>_*.err
# Cancel job if needed
scancel <job_id>- Check SLURM partition exists:
sinfo - Verify GPU resources available:
sinfo -o "%P %.5a %.10l %.6D %.6t %N %G" - Check SLURM account/QoS settings
- Review job script:
slurm_results/madengine_*.sh
General OOM:
- Reduce batch size or model size
- Use gradient accumulation
- Enable CPU offloading
- Check available GPU memory:
rocm-smioramd-smi
vLLM-Specific OOM (torch.OutOfMemoryError: HIP out of memory):
Symptom: Error during vLLM initialization or KV cache allocation:
torch.OutOfMemoryError: HIP out of memory. Tried to allocate 22.14 GiB.
GPU has a total capacity of 191.98 GiB of which 145.02 GiB is free.
Root Cause: Memory fragmentation or aggressive KV cache allocation
Solutions:
- Reduce KV cache size:
"env_vars": { "VLLM_KV_CACHE_SIZE": "0.6" // Try 0.6 or 0.7 }
- Enable expandable segments (should already be in configs):
"env_vars": { "PYTORCH_CUDA_ALLOC_CONF": "expandable_segments:True" }
- Reduce parallelism: Use fewer GPUs or nodes for smaller models
- Check GPU memory:
rocm-smioramd-smito verify available memory - Rebuild with updated config: Don't edit
build_manifest.json- update the source config file and rebuild
- Verify network interface name:
ifconfigorip addr - Check InfiniBand status:
ibstat(if using IB) - Test connectivity between nodes
- Set correct
NCCL_SOCKET_IFNAMEinenv_vars
Symptom: Failed to connect to GCS at address <node>:6379
Solutions:
- Check network connectivity between nodes
- Ensure Ray port (6379) is accessible
- Verify NCCL/RCCL environment variables are set correctly
- For smaller models, consider using tensor parallelism only (single node)
- List available modules:
module avail - Check module syntax:
module load rocm/5.7.0(manual test) - Verify module names match cluster configuration
- Start Small: Test on single GPU first, then scale up
- Use Configuration Files: Prefer config files over CLI arguments for reproducibility
- Build-Then-Run: Use two-phase workflow when configs include
env_vars - Use Shared Storage: Configure shared workspace for multi-node jobs
- Network Configuration: Properly configure NCCL for your network fabric
- Resource Requests: Request exclusive node access for large jobs
- Time Limits: Set realistic wall times (add buffer for checkpointing)
- Output Collection: Use
results_dirto collect outputs from all nodes
- Memory Management: Always include
VLLM_KV_CACHE_SIZEandPYTORCH_CUDA_ALLOC_CONF - Start Conservative: Use
VLLM_KV_CACHE_SIZE: "0.8"initially, tune if needed - Test Locally First: Validate vLLM configs on single-node before scaling to multi-node
- Monitor Memory: Check GPU memory usage during initialization
- Don't Edit Manifests: Always modify source config files, not generated
build_manifest.json - Rebuild After Changes: Re-run
buildphase when changingenv_vars
- Version Control: Keep your config files in git
- Naming Convention: Use descriptive names (e.g.,
my-project-vllm-8gpu.json) - Documentation: Add
_commentand_descriptionfields to configs - Reusability: Create base configs and override specific fields
- Validation: Test configs on small scale before production runs
# 1. SSH to SLURM login node
ssh user@hpc-cluster.example.com
# 2. Load any required modules (if needed before madengine)
module load python/3.9
# 3. Build with configuration
MODEL_DIR=models/my-model madengine build \
--tags llama2_training \
--additional-context-file examples/slurm-configs/basic/03-multi-node-basic.json \
--manifest-output build_manifest.json
# 4. Run from manifest
MODEL_DIR=models/my-model madengine run \
--manifest-file build_manifest.json
# 5. Monitor job
watch squeue -u $USER
# 6. Check logs when complete
ls -lh slurm_results/
tail -f slurm_results/madengine-*_<job_id>_*.out# 1. SSH to SLURM login node
ssh user@hpc-cluster.example.com
# 2. Build vLLM image with memory management config
MODEL_DIR=models/llama2-70b madengine build \
--tags vllm \
--additional-context-file examples/slurm-configs/basic/06-vllm-multi-node.json \
--manifest-output build_manifest.json
# 3. Verify configuration was embedded
grep -A 5 "VLLM_KV_CACHE_SIZE" build_manifest.json
# 4. Submit inference job
MODEL_DIR=models/llama2-70b madengine run \
--manifest-file build_manifest.json
# 5. Monitor for OOM errors
tail -f slurm_results/madengine-*_<job_id>_*.err | grep -i "memory"
# 6. If OOM occurs, adjust config and rebuild
# Edit your config file to set VLLM_KV_CACHE_SIZE to 0.6 or 0.7
# Then repeat steps 2-4- Deployment Guide - Kubernetes and SLURM multi-node
- Launchers Guide - Distributed training and inference
- K8s Configuration Examples
- SLURM Official Documentation
- vLLM Documentation
- PyTorch Distributed Training
- vLLM Distributed Inference
- SGLang Distributed Serving
Note: All configurations assume you've already SSH'd to the SLURM login node. madengine runs sbatch locally on the login node - no remote SSH handling needed.