profile-connector-benches
Run certus-connector-bench and cputier-connector-bench with identical workload parameters, then write an HTML report comparing the two KV-offload backends side by side (throughput, IOPS, per-phase lat
SKILL.md.claude/skills/profile-connector-benches/SKILL.md
GitHubprofile-connector-benches
Benchmark the two KV-offload connector backends with the same workload and present them side by side:
| Arm | Bench | Backend |
|---|---|---|
| certus | tools/certus-connector-bench/bench_connector_lifecycle.py (host) |
certus-server over /dev/shm/certus-shmq, SPDK NVMe |
| cputier | tools/cputier-connector-bench/run-in-container.sh (vLLM ≥ 0.30 image) |
vLLM TieringOffloadingSpec: pinned CPU tier + fs disk tier |
All work is done by run_compare.sh in this skill's directory. It takes every
workload flag once and forwards the same list to both benches, so the arms
cannot drift. The DRAM tier size --dram becomes certus-server's
--memory-tier-size and cputier's --cpu-bytes (and the container's
CPU_BYTES). make_report.py then checks parity from the columns each bench
actually wrote to its CSV and flags any difference in red.
Argument
<output-html-path>(required): where to write the HTML report, e.g.bench-results/connector-compare.html. If it is missing, ask for it. Raw artifacts (params.json, both CSVs, both bench logs, server.log) go to the sibling directory<path-without-.html>.d/.
The fs-tier path, the certus SSD count and the memory tier size are asked for
interactively (step 3). Everything else has working defaults. Pass through any extra flags the user
gives (see run_compare.sh --help): --mode (default all), --bs,
--num-blocks, --block-bytes, --min-duration, --warmup, --working-set,
--pipeline-depth, --direction, --hit-ratio, --requests-per-step,
--num-sessions, --lookup-order, --gpu, --tp, --dram; certus-only
--device-pci/--drive-count, --eviction-threshold, --workers,
--channels; cputier-only --fs-tier, --image.
Steps for Claude
Resolve the output path from the argument. Make it absolute relative to the repo root if it is relative.
Gather facts to offer as answer options in step 3:
- GPU:
nvidia-smi --query-gpu=index,name,memory.used --format=csvand its NUMA node (nvidia-smi topo -m). - NVMe SSDs for certus:
lspci -Dnd ::0108, with each device's NUMA node (/sys/bus/pci/devices/<addr>/numa_node) and driver (basename $(readlink /sys/bus/pci/devices/<addr>/driver); SPDK needsvfio-pcioruio_pci_generic). - Hugepages:
grep -i huge /proc/meminfo(free hugepage bytes cap the certus memory tier). - Free host RAM:
free -g(caps the cputier CPU tier, which lives in the container's/dev/shm). - Candidate cputier fs-tier filesystems:
df -hTmounts that are local block devices (xfs/ext4), and for each the backing device type (lsblk -s -o NAME,TYPE,TRAN,MODEL <source>) so the user can see which are NVMe.
- GPU:
Ask the user with one AskUserQuestion call holding these three questions (skip any the invocation already answered via
--fs-tier,--device-pci/--drive-count, or--dram):- cputier fs-tier path — options: the default
~/cputier-bench-fs-tier(state its filesystem and backing device, e.g. "xfs on SAS SSD LVM"), plus up to two other candidate mounts from step 2, preferring NVMe-backed ones (a directory<mount>/cputier-bench-fs-tier). Note that an NVMe-backed fs tier gives the fairest cold-path comparison with certus, and that it must not be overlay storage (noO_DIRECT). "Other" lets the user type a path. - Number of certus SSDs — options
1,2, ... up to the number of SPDK-bound NVMe devices found (max 4 options; recommend all devices on the GPU's NUMA node, or 1 if none are). Then pick that many devices, GPU-NUMA node first, and pass each as--device-pci. Warn if any chosen SSD is on a different NUMA node from the GPU. - Memory tier size (applies to both arms: certus
--memory-tier-sizeand cputier--cpu-bytes) — options4G(recommended, the default),8G,16G, filtered to sizes that fit both the free hugepages and free RAM (less ~4G headroom for the container's/dev/shm). Remind the user that--working-set(default 512 × 2 MiB = 1 GiB) must exceed it for the mixed-eviction phase to apply pressure, and offer to scale--working-setwith it (e.g. 2 × tier ÷--block-bytes), passed to both arms. Cap it by GPU memory: the certus bench allocates two GPU buffers ofmax(num_blocks, working_set) × block_byteseach at startup, so2 × working_set × block_bytesmust fit in the GPU's free memory with ~1 GiB to spare, or the certus arm dies with CUDA OOM before writing any results (8192 × 2 MiB blocks needs 32 GiB; an A30 has 24). If no working set both fits the GPU and exceeds the tier, say so and only offer tier sizes that leave room for one.
If the chosen fs-tier directory does not exist, create it (
mkdir -p).- cputier fs-tier path — options: the default
Preflight and tell the user what will run, with the answers from step 3:
- GPU free (no memory in use).
- certus arm:
target/release/certus-serverexists and is newer than the last commit touchingapps/certus-server,componentsorlib(otherwise rebuild:cargo build -p certus-server --release); it runs as the current user, no sudo. Make sure no othercertus-serveris running (it would own/dev/shm/certus-shmq). - cputier arm:
podman image exists docker.io/vllm/vllm-openai:v0.30.0(or--image). - If a prerequisite for one arm is missing, offer
--skip-certusor--skip-cputierinstead of aborting; the report then shows that arm as having no results.
Launch in the background (a
--mode allrun is several minutes per arm; the arms run one after the other because they share the GPU):.claude/skills/profile-connector-benches/run_compare.sh --out <output-html-path> \ --fs-tier <answer> --device-pci <addr> [--device-pci <addr> ...] \ --dram <answer> [--working-set N] [flags]Wait for it to finish. The script stops certus-server (SIGTERM, then SIGKILL after 8 s) on exit, including on failure.
Report. Give the user the HTML path and a short summary taken from the CSVs in
<path>.d/: which backend wins each result row and by how much, and anything notable in the per-phase latency (for example cputier'slookup_waiton the cold path, or cputier store drops in its log). Ifmake_report.pyprinted a parameter mismatch warning, or an arm failed, say so first and point at the log under<path>.d/. To re-render the HTML from existing artifacts, runrun_compare.sh --out <path> --report-onlywith the same flags.
What is and is not held equal
- Equal (forwarded identically): mode,
bs,num_blocks,block_bytes,min_duration,warmup,working_set,pipeline_depth,direction,hit_ratio,requests_per_step,num_sessions,lookup_order,tp, GPU(s), DRAM tier size. - Inherently different: the disk tier (SPDK raw NVMe vs fs files), and options
only one bench has: certus
--workers,--channels, eviction threshold,--prefix-sharing(left at its default,shared, which is how cputier behaves); cputier--layers,--blocks-per-chunk, fs thread counts (left at their defaults). The report lists these under "Backend-specific settings". - Read cputier store throughput with care: it excludes the per-pass fs
write-through drain (see
tools/cputier-connector-bench/README.md).