Server Gauss SLURM
| Status | Applies to | Owner |
|---|---|---|
| Pre-release draft; server-specific development operations | main branch as of 2026-06-30 gauss SLURM workflows | Development maintainers |
This repository was originally developed inside the Nix flake on a personal machine. On the Ubuntu SLURM server, keep just as the single entrypoint and split work between:
- login node: dependency sync, formatting, linting, CPU-only tests, lightweight iteration
- GPU node (
landauby default): JAX CUDA probing, GPU tests, GPU benchmarks, REGENIE profiling - CPU compute node (
cantorby default): full CPU validation, Rust builds/tests, Python test parallelism, CPU-heavy benchmark runs
Required Host Tooling
Install or make available on PATH:
gituvsrunzstd
The repo-local dev-bootstrap installs just, Mold, cargo, rustc, plink,
plink2, and regenie into .tools/. Python itself does not need to be
preinstalled globally if uv python install works in your account.
Bootstrap
First-run setup before just is available:
UV_CACHE_DIR=/tmp/g-uv-cache uv run --no-project \
--with 'hydra-core>=1.3.2' \
--with 'pooch>=1.8.2' \
python -m tooling.cli.server --config-name server_bootstrap_tools
source tooling/server/server_env.sh
--no-project is required for this first run: it prevents uv from trying to
compile g before the bootstrap has installed Mold.
CPU-oriented login-node setup after the first-run dev-bootstrap:
just dev-bootstrap
GPU-capable environment:
just dev-bootstrap-gpu
Sanity checks:
just doctor-server
just doctor
just doctor-baselines
Workflow Tiers
Run quick iteration on the login node:
just check-local
just test-local
just test-local-focused
just perf-smoke
just perf-compare BASE.json NEW.json
check-local runs Python format/lint/type checks plus a focused native-extension
smoke. test-local runs the non-data Python suite serially. These are the right
commands for small edits and head-node feedback.
Use one CPU SLURM node for full CPU validation:
just slurm-cpu-check
just slurm-cpu-test
just slurm-cpu-test-full
just slurm-cpu-rust-build
just slurm-cpu-rust-test
just slurm-cpu-coverage
slurm-cpu-check wraps just check. slurm-cpu-test runs the non-data Python
suite with large-node pytest parallelism. slurm-cpu-test-full and
just slurm-cpu-just test run the full Python suite, including data/parity
tests when the required local files are present. Do not run full just check,
full just test, Rust dependency builds, or Rust test builds directly on the
login node.
perf-smoke and perf-compare are intentionally login-node-safe. Do not run
perf-cpu, perf-gpu, full benchmark sweeps, or GPU commands directly on the
login node.
Prepare benchmark data only after plink2 is available:
just data-prepare
Generate binary REGENIE step 1 predictions required by binary step 2:
just data-baseline-binary
just data-verify-binary-gpu-inputs
CPU Workflow Through SLURM
The CPU node defaults to cantor, which currently reports 40 CPUs and about
192 GB memory. The CPU helpers request one task on one node, use
--exclusive by default, and set CARGO_BUILD_JOBS from the allocation inside
the job. Override cluster-specific settings independently from GPU settings:
export GWAS_ENGINE_CPU_NODE=cantor
export GWAS_ENGINE_CPU_CPUS_PER_TASK=40
export GWAS_ENGINE_CPU_MEMORY=128G
export GWAS_ENGINE_CPU_TIME=04:00:00
export GWAS_ENGINE_CPU_PARTITION=compute
export GWAS_ENGINE_CPU_ACCOUNT=my-account
export GWAS_ENGINE_CPU_EXTRA_ARGS='--reservation=my-reservation'
export GWAS_ENGINE_SLURM_EXCLUSIVE=1
The older generic GWAS_ENGINE_SLURM_* variables still work as fallbacks, but
prefer GWAS_ENGINE_CPU_* for CPU jobs and GWAS_ENGINE_GPU_* for GPU jobs.
Set GWAS_ENGINE_CPU_NODE to an empty string when the scheduler should choose
the CPU host.
Open an interactive CPU shell:
just slurm-cpu-shell
Run one-off commands or existing recipes on the CPU node:
just slurm-cpu-run 'cargo build --workspace --all-targets'
just slurm-cpu-just check
just slurm-cpu-just test
just slurm-cpu-just rust-test
Inside CPU SLURM jobs, tooling/server/server_env.sh derives
GWAS_ENGINE_ALLOCATED_CPU_COUNT from SLURM_CPUS_PER_TASK,
SLURM_CPUS_ON_NODE, or nproc; sets CARGO_BUILD_JOBS from an available
SLURM CPU count unless already configured; and sets
GWAS_ENGINE_PYTEST_WORKERS for pytest. Outside SLURM, Cargo uses the
repo-configured default of 30 jobs. CARGO_BUILD_JOBS and Cargo's --jobs
option remain explicit overrides.
Python tests default to at most 8 xdist workers because the suite imports JAX
and the native extension, so one pytest worker per core can oversubscribe
process-level JAX/native thread pools. Override after measuring:
GWAS_ENGINE_CPU_PYTEST_WORKERS=16 just slurm-cpu-test
GWAS_ENGINE_CPU_PYTEST_WORKERS=1 just slurm-cpu-test-full
When xdist is active, pytest subprocesses get conservative BLAS/OpenMP thread limits to reduce accidental oversubscription. Cargo builds and Rust tests use the full allocated CPU count through Cargo's own scheduler.
Build-environment defaults:
- Do not share one global Rust
target/directory across Symphony worktrees by default; that can reduce cold builds but risks cross-worktree contention and confusing invalidation during unattended branch work. - SLURM jobs default to
target/slurm/<node>/becausetarget-cpu=nativeartifacts are not safe to reuse across heterogeneous nodes. SetCARGO_TARGET_DIRexplicitly to override this location. - Do not push every focused test through SLURM; local
check-local,test-local, and targeteduv run pytest ...remain faster for small edits. - Cargo uses the repo-local
.cargo/config.tomlfor Linux Rust builds:target-cpu=nativeis enabled andccselects Mold with-fuse-ld=mold. Runjust server-setup-toolswhenmoldorld.moldis missing.just doctor-serveralso verifies that the installedccdriver accepts the Mold option. The repo does not choose a rustc wrapper; setRUSTC_WRAPPERand cache variables explicitly for isolated experiments.
GPU Workflow Through SLURM
The GPU node defaults to landau. Override cluster-specific settings with GPU
environment variables when needed:
export GWAS_ENGINE_GPU_NODE=landau
export GWAS_ENGINE_GPU_PARTITION=gpu
export GWAS_ENGINE_GPU_ACCOUNT=my-account
export GWAS_ENGINE_GPU_CPUS_PER_TASK=8
export GWAS_ENGINE_GPU_MEMORY=64G
export GWAS_ENGINE_GPU_TIME=04:00:00
export GWAS_ENGINE_GPU_GPUS_PER_TASK=1
Open an interactive GPU shell:
just slurm-gpu-shell
Run a one-off command on the GPU node:
just slurm-gpu-run 'nvidia-smi'
just slurm-gpu-run 'uv run python -m tooling.cli.performance tool.name=jax_runtime'
Run existing repo recipes on the GPU node while keeping just as the top-level interface:
just slurm-gpu-just doctor-jax
just slurm-gpu-just matrix-chr22-smoke
just matrix-chr22-smoke
just slurm-gpu-just matrix-chr22
just matrix-chr22
just slurm-gpu-just legacy-regenie-comparison-gpu
just slurm-gpu-just legacy-profile-regenie-comparison-gpu
slurm-gpu-run and slurm-gpu-shell start in the repository root and call
gwas_engine_configure_rust_build_environment before the requested command.
That keeps GPU-side maturin, Cargo, clippy, or profiler-tool builds within the
GPU allocation's CPU count instead of the repo's otherwise-default 30 jobs.
Run standard performance harness entrypoints:
just perf-cpu
just perf-gpu tool.variant_limit=1000
perf-cpu submits the BGEN reader benchmark through a CPU SLURM allocation and
writes summaries under results/perf/cpu/. Override the CPU host with
GWAS_ENGINE_CPU_NODE; set it to an empty string if the scheduler should choose
the node. perf-gpu wraps the existing binary-hot GPU SLURM recipe and writes
under results/perf/gpu/.
Timing Notes
Baseline measured on cantor before the CPU workflow update, using a 40-CPU,
128 GB, exclusive allocation:
just check: 96.53 seconds with a cold Cargo dependency cache.just test: failed after 714.91 seconds becausecantorhad nogitexecutable in the environment. Installing user-levelgitwithpixi global install gitmadegitavailable on bothgaussandcantor.
Post-change timings on the same node and allocation:
just slurm-cpu-just check: 17.75 seconds with warm Cargo artifacts.just slurm-cpu-check: 66.69 seconds after a native Rust source change forced a rebuild.just test-local: 731.03 seconds on the login node for the serial non-data suite.just slurm-cpu-test: 212.81 seconds for the same non-data suite with 8 xdist workers.just slurm-cpu-just test: 224.76 seconds for the full suite with 8 xdist workers.just slurm-cpu-test-full: 230.24 seconds through the explicit full-suite alias.just slurm-cpu-rust-build: 128.03 seconds.just slurm-cpu-rust-test: 32.45 seconds after the strict-resume diagnostic fix.just slurm-cpu-coverage: 408.87 seconds, with Python coverage at 92.73% and Rust line coverage at 91.21%.
Use large-node validation when the command will compile Rust dependencies, build
Rust tests, run the full Python suite, or combine Python and Rust checks. For
single-file Python changes, targeted uv run pytest tests/<file>.py or
just test-local-focused is usually faster than queueing a SLURM job.
The binary chr22 GPU run uses:
data/1kg_chr22_full.bgen
data/1kg_chr22_full.sample
data/pheno_bin.txt
data/covariates.txt
data/baselines/regenie_step1_pred.list
Outputs are written under:
data/regenie2_binary_chr22_gpu.g/trait_0001_phenotype_binary.regenie2_binary.run/
Notes
just upgrade-depsis now Python-package only. Nix lockfile updates moved tojust upgrade-nix-lock.just doctor-jaxshould be treated as a host-specific check. On a login node without NVIDIA libraries, CPU fallback is expected.- JAX persistent compilation cache defaults to
<platform temporary directory>/<user>/g-jax-cache; use TOML[compute].jax_cache_dirfor an explicit cache path. - Profiling recipes isolate CPU JAX caches under
${G_PROFILE_CPU_JAX_CACHE_PARENT:-/tmp/g-jax-cpu-profile-cache}/host-<hostname>/features-<cpu-fingerprint>/to avoid reusing CPU AOT artifacts across SLURM nodes. GPU profile caches stay node-local under${G_PROFILE_GPU_JAX_CACHE_PARENT:-/tmp/g-jax-profile-cache}. .tools/anddata/are local server state and must not be committed.results/contains local benchmark output, includingperf-*summaries, and must not be committed.tooling/server/server_env.shsets repo-local tools onPATH,UV_CACHE_DIR=/tmp/g-uv-cache,UV_LINK_MODE=copy, repo-local Rust homes unless those variables are already set, and SLURM allocation-derived build parallelism when a scheduler wrapper callsgwas_engine_configure_cpu_parallelism.