posix-aio¶
Invokes ucm/store/test/e2e/posixstore_aio_test.py from the repository to perform dump/load performance testing via UcmPipelineStore, for evaluating UCM POSIX store disk read/write bandwidth. IO engine (posix_io_engine, psync/aio), transfer concurrency (posix_data_trans_concurrency), and O_DIRECT (io_direct) are all configurable via CLI.
Two usage modes are supported:
- Manual mode (default): directly specify
--shard-size/--shard-number/--block-number, etc. - Model-driven mode: pass
--modelpointing to a model directory; automatically readsconfig.jsonto detect architecture (GQA / MLA / DSA) and computesshard-size/shard-number/block-number, then forwards to the same script for automated bandwidth testing.
← Back to UCM Toolkit
Dependencies¶
The UCM Python package and its native extensions must be available, and numpy must be importable. Model-driven mode only uses the standard library (json / math), with no dependency on transformers / vllm.
Examples¶
Manual Mode¶
ucm-toolkit run posix-aio
ucm-toolkit run posix-aio \
--worker-number 1 \
--shard-size 8388608 \
--shard-number 1 \
--block-number 64 \
--dump-epoch-number 32 \
--load-epoch-number 32 \
--storage-backend ./build/data
Model-Driven Mode¶
# MLA, layerwise
ucm-toolkit run posix-aio --model /models/DeepSeek-V3 --tp 8 --input-len 4096 \
--worker-number 8 --layerwise --storage-backend /mnt/ssd/ucm
# DSA (GLM-5.1 / DeepSeek-V3.2), non-layerwise (--no-layerwise)
ucm-toolkit run posix-aio --model /models/GLM-5.1 --tp 8 --input-len 4096 \
--worker-number 8 --no-layerwise --storage-backend /mnt/ssd/ucm
# GQA, layerwise
ucm-toolkit run posix-aio --model /models/Qwen3-32B --tp 8 --input-len 4096 \
--worker-number 8 --layerwise --storage-backend /mnt/ssd/ucm
# Only print UCM Store IO Info (io size / io number), without running the script
ucm-toolkit run posix-aio --model /models/Qwen3-32B --tp 8 --input-len 4096 --layerwise --dry-run
Unsupported architectures will warn and exit:
ucm-toolkit run posix-aio --model /models/DeepSeek-V4-Pro --tp 8 --input-len 4096 --worker-number 8
# → warning: architecture 'hybrid' not supported, only GQA and MLA family (MLA/DSA) are supported now
Parameters¶
Manual Mode Parameters¶
| Parameter | Default | Description |
|---|---|---|
-w, --worker-number |
1 |
worker number: number of worker processes to start concurrently. |
-s, --shard-size |
8388608 |
shard size: POSIX store I/O size. In layerwise mode, this is the K/V tensor size for one layer of one block. In non-layerwise mode, this is the K/V tensor size for all layers of one block. |
-n, --shard-number |
1 |
shard number: number of layers in layerwise mode; use 1 in non-layerwise mode. |
-b, --block-number |
64 |
block number: total number of blocks. |
-d, --dump-epoch-number |
32 |
dump epoch number: number of dump epochs. |
-l, --load-epoch-number |
32 |
load epoch number: number of load epochs. |
-o, --storage-backend |
./build/data |
storage backend: storage backend path; may be repeated. Passing this option replaces the default backend list with the provided values. |
--posix-data-trans-concurrency |
32 |
posix data transfer concurrency (psync worker count). |
--posix-io-engine |
aio |
posix IO engine: psync or aio. |
--io-direct |
True |
Whether to use O_DIRECT for aligned file I/O; disable with --no-io-direct. |
Model-Driven Mode Parameters¶
Passing --model enters model-driven mode. In this mode, --shard-size / --shard-number / --block-number are computed from the model config and override any manual settings (with a warning printed). --storage-backend / --dump-epoch-number / --load-epoch-number / --worker-number / --posix-io-engine / --posix-data-trans-concurrency / --io-direct are still passed through to the script.
| Parameter | Default | Description |
|---|---|---|
--model |
— | Model directory (containing config.json) or config.json file path; passing it enters model-driven mode. |
--tp |
1 |
tensor parallel size; for GQA, used to split num_kv_heads by rank. |
--input-len |
4096 |
Request input length; block_number = ceil(input_len / block_size). |
--layerwise |
True |
Layerwise mode: one shard = one layer (default true); use --no-layerwise for non-layerwise (one shard = all layers). |
--block-size |
128 |
vLLM paged block token count, used for input_len → block_number conversion. |
--kv-dtype |
config's torch_dtype, or bfloat16 if absent |
Override KV dtype: bfloat16/bf16, float16/fp16, float32/fp32, float8_e4m3fn/fp8, float8_e5m2, int8. |
--dry-run |
False |
Only print the UCM Store IO Info summary and forwarded command, without launching the script (for verifying io size / io number). |
Supported Architectures and Formulas¶
Detection logic follows docs/source/_static/calculator.js's detectArchitectureType. Let T = KV bytes per layer per block, B = --block-size, elem = dtype byte count, L = num_hidden_layers:
| Architecture | Detection Fields | Per-Layer-Per-Block Bytes T |
TP Handling |
|---|---|---|---|
| GQA (Qwen, MiniMax) | Has num_key_value_heads |
2 * (num_kv_heads // tp) * head_dim * B * elem |
Each rank stores its own KV, num_kv_heads/tp |
| MLA (DeepSeek-V3/R1) | kv_lora_rank + qk_rope_head_dim, no index_head_dim |
(kv_lora_rank + qk_rope_head_dim) * B * elem |
No TP division (latent replicated across TP, only rank0 dumps) |
| DSA (DeepSeek-V3.2, GLM-5/5.1) | Above + index_head_dim |
(kv_lora_rank + qk_rope_head_dim + index_head_dim) * B * elem |
No TP division (same as MLA family) |
head_dim derivation: MLA → kv_lora_rank + qk_rope_head_dim; DSA → add index_head_dim; GQA → config.head_dim, otherwise hidden_size // num_attention_heads.
Layerwise vs non-layerwise (aligned with real UCM store shard/block partitioning):
| Mode | Shard Size | Shards Per File | Description |
|---|---|---|---|
| Layerwise | align_up(T, 4096) |
L |
One file = L shards, per-layer I/O, can overlap with forward pipeline |
| Non-layerwise | align_up(L * T, 4096) |
1 |
One file = 1 shard, single I/O transfers all layers |
file size = shard size * shards per file; shard size is aligned up to 4096, matching the real store's I/O granularity and compatible with io_direct. One block corresponds to one file (DataFilePath(blockId)), so shards per file is the number of shards in a file and file size is the file size.
Not supported (warns and exits 1): Hybrid / DeepSeek V4 (compress_ratios etc.), Mamba / linear attention (linear_attention / model_type containing mamba), unknown architectures.
Resource Estimation¶
Per-worker data volume ≈ shard-size * shard-number * block-number
Total data volume ≈ worker-number * shard-size * shard-number * block-number
In model-driven mode, shard-size / shard-number / block-number are computed using the formulas above. Before running, a UCM Store IO Info summary is printed: architecture (uppercase GQA/MLA/DSA), num_hidden_layers, head_dim, dtype, per_layer/block (bytes+KB+formula), shard size (bytes+KB+formula), shards per file, file size (bytes+KB+MB), block_number, total per-worker data volume. With --dry-run, only the summary and forwarded command are printed without actually running the script.