Skip to content

performance: post-compilation kvcache_num_blocks CLI and memory_budget for estimation - #629

Closed
rebel-jongho wants to merge 9 commits into
devfrom
jongho/kvcache-num-blocks-post-compile
Closed

performance: post-compilation kvcache_num_blocks CLI and memory_budget for estimation#629
rebel-jongho wants to merge 9 commits into
devfrom
jongho/kvcache-num-blocks-post-compile

Conversation

@rebel-jongho

@rebel-jongho rebel-jongho commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Type of Change

  • New feature (non-breaking change which adds functionality)

Changes Overview

Two related capabilities for controlling the decoder-only kv-cache block count:

  1. Post-compilation CLI to inspect/resize kvcache_num_blocks on an already-compiled artifact, without recompiling.
  2. Compile-time memory_budget to bound the DRAM the automatic block estimation may assume.

1. Post-compilation CLI

Two subcommands on optimum-rbln-cli operating on an artifact directory (--model-id DIR):

  • --get-kvcache-num-blocks — prints kvcache_num_blocks from rbln_config.json.
  • --set-kvcache-num-blocks N — resizes the kv-cache of every *.rbln to N blocks and writes the .rbln files and rbln_config.json. Edits in place, or with --output-dir writes a full resized copy there (copying the non-.rbln files too) and leaves the source untouched.
# Read the current kv-cache block count
optimum-rbln-cli --get-kvcache-num-blocks --model-id ./my_artifact

# Resize in place to 128 blocks
optimum-rbln-cli --set-kvcache-num-blocks 128 --model-id ./my_artifact

# Resize into a new directory, leaving the source untouched
optimum-rbln-cli --set-kvcache-num-blocks 128 --model-id ./my_artifact --output-dir ./my_artifact_128

Internals — new RBLNDecoderOnlyFlashAttentionMixin.rescale_kvcache_num_blocks(compiled_models, rbln_config, target):

  • Saved kv-cache buffers hold per_block * current bytes (current = rbln_config.kvcache_num_blocks). Rescaling by the rational ratio target / current (rebel-compiler exp_rescale_buffer_size) yields exactly per_block * target.
  • Stateless: rbln_config.json is the single source of truth for the current block count.
  • target < num_min_blocksValueError (config only). Non-fatal warnings (config only): target above the compile-time count (may not fit device DRAM), and target above num_full_blocks (excess blocks never used). Older rebel-compiler without the API → clear RuntimeError via hasattr capability detection.

Depends on rebel-compiler's new exp_rescale_buffer_size (rebellions-sw/rebel_compiler#12067).

2. Compile-time memory_budget

RBLNDecoderOnlyModelConfig gains a memory_budget member that caps the device DRAM the automatic kvcache_num_blocks estimation may assume:

  • Prefer a float in (0, 1] as a fraction of the NPU available DRAM (e.g. 0.8 for 80%, matching vllm's gpu_memory_utilization). A "80%" string is also accepted (handy for passing through the compile CLI), as are bytes given as an int or string ("10GB", "512MB"). The fraction is of usable memory (after the per-chiplet system reserve), not the raw total.
  • Defaults to the full available DRAM and must not exceed it (ValueError otherwise). The budget is split evenly per chiplet with no further reserve subtraction (already excluded), so the default reproduces current estimation exactly.
  • Flows through the compile CLI as a forwarded rbln_config key:
optimum-rbln-cli --model-id meta-llama/Llama-2-7b-chat-hf --memory-budget 0.8
optimum-rbln-cli --model-id meta-llama/Llama-2-7b-chat-hf --memory-budget 80%
optimum-rbln-cli --model-id meta-llama/Llama-2-7b-chat-hf --memory-budget 100GB

Also adds RBLNDecoderOnlyFlashAttentionMixin._required_memory_at(compiled_models, rbln_config, num_blocks), returning the device-wide kv-cache DRAM at a given block count with 2MB alignment applied (non-linear in the block count). It works for any current block size — resizable tensors are normalized to per-block bytes using rbln_config.kvcache_num_blocks. The aligned per-chiplet math is factored into _kvcache_bytes_per_chiplet, shared with the block search (unchanged behavior).

Motivation and Context

  • Users need to tune kvcache_num_blocks on a compiled artifact without recompiling the whole model (CLI).
  • Users need to constrain kv-cache block estimation to a memory budget smaller than the full device (e.g. to leave headroom), expressed intuitively in bytes or a percentage (memory_budget).

How to test

  • CLI: on a compiled decoder-only artifact, --get prints the stored count; --set N (N ≥ num_min_blocks) rewrites the kv-cache buffers to per_block * N and updates the config (verified by reloading the .rbln); --set below num_min_blocks raises ValueError; --output-dir leaves the source untouched.
  • memory_budget: estimation with a smaller budget yields fewer blocks (monotonic), None reproduces the current result, and a budget above the NPU total raises ValueError. _required_memory_at(N) is monotonic in N, equals the current footprint at N = kvcache_num_blocks, and stays correct for an already-resized artifact.

Add `optimum-rbln-cli --get-kvcache-num-blocks` / `--set-kvcache-num-blocks N`
to read and resize the kv-cache block count of an already-compiled artifact
directory without recompiling.

`rescale_kvcache_num_blocks` rescales the kv-cache buffers by the rational
ratio N/current (current = rbln_config.kvcache_num_blocks) via rebel-compiler's
new `exp_rescale_buffer_size`, then rewrites the .rbln files and rbln_config.json.
Stateless: rbln_config.json is the single source of truth for the current count.
Enforces num_min_blocks as a hard lower bound, warns when N exceeds the
compile-time count, and raises a clear error on older rebel-compiler lacking
the API.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
rebel-jongho and others added 2 commits July 9, 2026 09:00
Write the resized artifact to --output-dir instead of editing in place. Copies
the non-.rbln files (config.json, generation_config.json, torch artifacts, etc.)
into the destination so it is a complete, loadable artifact; the source is left
untouched. Without --output-dir the edit stays in place as before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In addition to the device-fit warning, warn when the requested block count
exceeds num_full_blocks (the blocks needed to cover the full batch at
max_seq_len), since the excess blocks are never used at runtime.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rebel-jongho rebel-jongho changed the title feat: add post-compilation kvcache_num_blocks get/set CLI performance(cli): get/set kvcache_num_blocks on a compiled artifact Jul 10, 2026
Add `memory_budget` as a member of RBLNDecoderOnlyModelConfig to cap the device
DRAM the auto kvcache_num_blocks estimation may assume. Accepts an int (bytes),
a byte string ("10GB"/"512MB"), or a percentage ("80%") of the NPU total DRAM;
defaults to the NPU total DRAM and must not exceed it. It overrides the device
total used by get_available_dram_per_chiplet (sys reserve still subtracted, so
the default reproduces current behavior).

Also add RBLNDecoderOnlyFlashAttentionMixin._required_memory_at(num_blocks),
which returns the device-wide kv-cache DRAM at a given block count with 2MB
alignment applied (bytes are non-linear in the block count). The aligned
per-chiplet computation is factored into _kvcache_bytes_per_chiplet, shared by
the block search and _required_memory_at.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rebel-jongho rebel-jongho changed the title performance(cli): get/set kvcache_num_blocks on a compiled artifact performance: post-compilation kvcache_num_blocks CLI and memory_budget for estimation Jul 14, 2026
rebel-jongho and others added 2 commits July 14, 2026 05:01
Normalize resizable kv tensors to per-block bytes (size // current_blocks)
before scaling to the target block count, where current_blocks is
rbln_config.kvcache_num_blocks (0 baseline treated as 1). Previously it assumed
the block-size-1 compile baseline and over-counted on an already-resized model.
The block search still passes current_blocks=1, preserving estimation behavior.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Interpret memory_budget against the device's available DRAM (after the
per-chiplet system reserve) rather than the raw total. A percentage is now a
fraction of the available DRAM, and per-chiplet is budget // num_chiplets with
no further system-reserve subtraction (the reserve is already excluded from the
available total). Default (None) uses the full available DRAM, reproducing the
prior estimation. Drops the now-unused get_total_dram and total_memory override.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rebel-jongho
rebel-jongho marked this pull request as ready for review July 16, 2026 04:03
def _resolve_memory_budget(memory_budget: Optional[object], available_total: int) -> int:
"""Resolve `memory_budget` to usable DRAM bytes (system reserve excluded), capped at available_total.

None -> available_total; "80%" -> that fraction of it; int/"10GB"/"512MB" -> parsed bytes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about using a decimal to express a percentage? e.g. using 0.8 to express 80%.
Upstream vllm is using decimal.
https://github.com/vllm-project/vllm/blob/dcfebf93f4eccf30f71872283331eee757915daf/vllm/config/cache.py#L68

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can also be tricky to validate strictly when we stick with the % representation.

@rebel-jongho rebel-jongho Jul 20, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the pointer — I made the float fraction the recommended form (e.g. 0.8), matching vllm's gpu_memory_utilization, and the docstring now steers users to it.

I did keep the "80%" string as an accepted alias, for one reason: it's convenient to pass through the compile CLI, where values arrive as strings (e.g. optimum-rbln-cli --memory-budget 80%). The float form works there too (--memory-budget 0.8).

rebel-jongho and others added 2 commits July 20, 2026 04:39
Per review, accept a float in (0, 1] as a fraction of the available DRAM
(e.g. 0.8 for 80%), matching vllm's gpu_memory_utilization, instead of a "80%"
string that is awkward to validate. Bytes (int / "10GB") are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keep the float fraction as the recommended form, but also accept a "80%"
percentage string so it can be passed through the compile CLI as an argument.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rebel-jonghewk

Copy link
Copy Markdown
Contributor

@rebel-jongho Since Post-compilation CLI depends on the compiler fix, could you split Post-compilation CLI and Compile-time memory_budget into separate PRs? That would make Compile-time memory_budget easier to review.

@rebel-jongho

Copy link
Copy Markdown
Collaborator Author

Split as requested, thanks @rebel-jonghewk:

Closing this in favor of those two.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants