Consider KV cache storage tier in scoring#1293
Conversation
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces tier-weighted scoring based on storage mediums (such as GPU and CPU) for the KV cache-aware scheduler plugin, updating both the Go scheduler and the Python event-handling and Redis-management components. Feedback highlights critical performance bottlenecks in the Python kv_cache_manager.py due to sequential hget queries inside loops, which should be batched. Additionally, the Go implementation has logic issues with weight validation: it prevents setting a weight of 0.0 (overriding it to defaults or 1.0) and lacks validation to ensure weights do not exceed 1.0, which could cause calculated pod scores to exceed the maximum limit of 100.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
c2dc7c9 to
3bbd9be
Compare
hzxuzhonghu
left a comment
There was a problem hiding this comment.
Please first update the proposal.
How about sglang? Does it already handle the medium info?
| MaxBlocksToMatch int `yaml:"maxBlocksToMatch,omitempty"` | ||
| BlockSizeToHash int `yaml:"blockSizeToHash,omitempty"` | ||
| MaxBlocksToMatch int `yaml:"maxBlocksToMatch,omitempty"` | ||
| TierWeights map[string]float64 `yaml:"tierWeights,omitempty"` |
There was a problem hiding this comment.
The user guide needs to be updated regarding how to use this feature.
There was a problem hiding this comment.
already on it, pls wait.
| found = true | ||
| } | ||
| } | ||
| if !found { |
There was a problem hiding this comment.
More doc about the case which medium is not specified or unknown.
3bbd9be to
b3fdd7f
Compare
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
@YaoZengzeng updated the proposal and user guide, PTAL
@hzxuzhonghu SGLang already carries medium in the event pathand. this PR now persists it in Redis so the router can use it for tier-weighted scoring. Also documented that timestamp only entries, missing media, and unknown media fall back to weight 1.0. |
I dont think so.Sglang use |
b3fdd7f to
8b3abfc
Compare
|
@FAUST-BENCHOU thnks, good catch. I checked the linked SGLang code and CPU_PINNED is the value emitted for host-pinned CPU blocks. have updated the defaults, docs, and tests. |
hzxuzhonghu
left a comment
There was a problem hiding this comment.
I would suggest you first deep dive what all the supported medium from vllm, sglang And document it clearly
| | ------------------ | ------- | -------------------------------------------------------------------------------- | | ||
| | `blockSizeToHash` | 16 | Number of tokens per block. Must match the vLLM block size for optimal matching. | | ||
| | `maxBlocksToMatch` | 128 | Maximum number of blocks to process per request. Limits Redis queries. | | ||
| | `tierWeights` | gpu: 1.0<br />cpu_pinned: 0.8 | Optional weights for reported KV cache storage media. Missing or unknown media use weight `1.0`. | |
There was a problem hiding this comment.
As only sglang supported cpu_pinned, so this does not apply to vllm?
There was a problem hiding this comment.
vLLM reports CPU blocks as CPU, while SGLang reports host-pinned blocks as CPU_PINNED, so the docs now show both cpu and cpu_pinned, updated
| "pod-name-1.namespace.svc.cluster.local": "1703123456", | ||
| "pod-name-2.namespace.svc.cluster.local": "1703123789" | ||
| "pod-name-2.namespace.svc.cluster.local": "1703123789|GPU", | ||
| "pod-name-3.namespace.svc.cluster.local": "1703123900|GPU,CPU_PINNED" |
There was a problem hiding this comment.
good point sir, i was trying to show a pod/block being updated over time but that made the stored value look like multiple media at once. I removed it; the Redis value now stores one reported medium per update
| ``` | ||
|
|
||
| 1. **Tokenization**: Convert input text/messages to token sequences using model-specific tokenizers | ||
| 2. **Block Division**: Split tokens into fixed-size blocks (configurable, default 128) |
There was a problem hiding this comment.
sir, the old proposal text said 128, but the implementation default is 16, so now i updated the proposal to match the current code
| if isinstance(existing_value, bytes): | ||
| existing_value = existing_value.decode() | ||
| timestamp, _, medium_value = existing_value.partition("|") | ||
| mediums = [m for m in medium_value.split(",") if m and m != medium] |
There was a problem hiding this comment.
please explain why medium is not a single value
There was a problem hiding this comment.
I can see vllm only report GPU or CPU not sure sglang
There was a problem hiding this comment.
agreed, this was overcomplicated. I changed it back to a single medium value and overwrite the stored value on each block update
| return f"{cls.MAPPING_KEY_PREFIX}:{pod_identifier}@{engine_hash}" | ||
|
|
||
| @staticmethod | ||
| def _format_matrix_value(timestamp: str, medium: Optional[str] = None, |
There was a problem hiding this comment.
why call _format_matrix_value
There was a problem hiding this comment.
removed it, was unnecessary once we stopped merging media
| if isinstance(existing_value, bytes): | ||
| existing_value = existing_value.decode() | ||
|
|
||
| mediums = [] | ||
| if existing_value and "|" in existing_value: | ||
| mediums = [m for m in existing_value.split("|", 1)[1].split(",") if m] |
There was a problem hiding this comment.
Why donot you override the old value directly?
yes sir, Im on it and will get back, thankyou so much for the guidance. |
| bestWeight := 0.0 | ||
| found := false | ||
| for _, name := range strings.Split(medium, ",") { | ||
| weight, ok := t.tierWeights[strings.ToLower(strings.TrimSpace(name))] |
There was a problem hiding this comment.
weightForMedium("CPU_PINNED,DISK") returns the configured CPU weight because unknown entries are ignored once any known tier is found. The documented fallback gives an unknown medium weight 1.0, and the highest weight should win, so this combination should return 1.0. Please treat each unknown entry as weight 1.0 and add a mixed known/unknown test.
There was a problem hiding this comment.
fixed, weightForMedium now treats the stored medium as a single value nd so unknown or unconfigured media fall back to 1.0
8b3abfc to
7070f93
Compare
Signed-off-by: Avinash Kumar Deepak <avinash8655279@gmail.com>
7070f93 to
e0e3c77
Compare
yes took time, updated both the user guide and proposal. i checked the vLLM and SGLang event definitions and documented the supported media explicitly: vLLM uses GPU, CPU, FS, OBJ |
|
Hey @hzxuzhonghu PTAL, let me know if anything needs adjustment |
What type of PR is this?
/kind enhancement
What this PR does / why we need it:
Makes the
kvcache-awarescheduler plugin consider the storage medium of cached KV blocks when scoring pods. Cached blocks keep the existing timestamp behavior, while runtimes that report a medium can now let the router apply tier weights during longest-prefix scoring.Which issue(s) this PR fixes:
Fixes #1283
Special notes for your reviewer:
The Redis value format remains backward-compatible: existing timestamp-only entries continue to score with weight
1.0.Does this PR introduce a user-facing change?: