Skip to content

Add get_tier_prefix_hit_rate(cpu only) - #20

Open
myliu569 wants to merge 1 commit into
touch869:llm-routerfrom
myliu569:feat/get_tier_prefix_hit_rate
Open

Add get_tier_prefix_hit_rate(cpu only)#20
myliu569 wants to merge 1 commit into
touch869:llm-routerfrom
myliu569:feat/get_tier_prefix_hit_rate

Conversation

@myliu569

@myliu569 myliu569 commented Jun 26, 2026

Copy link
Copy Markdown

What does this PR do?

Add concise overview of what this PR aims to achieve or accomplish. Reference related GitHub issues and PRs that help with the review.

Checklist Before Starting

  • Search for similar PRs or issues and paste at least one relevant link here: ...
  • Format the PR title as [{modules}] {type}: {description} (checked by CI)
    • {modules} may include core, interaction, model, env, tools, deployment, reward, dashboard, docs, examples, data, train, ci, build, deps, misc
    • If this PR involves multiple modules, separate them with , like [interaction, tools, docs]
    • {type} must be one of feat, fix, refactor, chore, test
    • If this PR breaks an API, config contract, workflow, or other compatibility boundary, add [BREAKING] to the beginning of the title
    • For a stacked PR series, you may prepend a progress marker such as [1/N]
    • Example: [BREAKING][deployment, docs] feat: simplify runtime env configuration

Test

List the checks you ran. If CI coverage is not practical for this change, describe the manual validation or experiment results.

--ut
image

--st-gpu
image

--st-cpu
image

--e2e
image

API and Usage Example

Show any public interface changes or updated usage examples if relevant.

# Add a short example here when the PR changes public behavior

Design & Code Changes

Summarize the approach for non-trivial changes and call out important implementation details or trade-offs.

Checklist Before Submitting

  • Read the Contribute Guide
  • Run pre-commit install && pre-commit run --all-files --show-diff-on-failure --color=always
  • Add or update docs/examples for user-facing changes
  • Add tests or explain why tests are not practical
  • Confirm the PR title matches the required format
  • Confirm the placeholder text in this template has been replaced with real content

@myliu569
myliu569 force-pushed the feat/get_tier_prefix_hit_rate branch from 58ab026 to 865f4f5 Compare June 29, 2026 09:06
Comment thread examples/agent_interaction/parallel_infer.py Outdated
@myliu569
myliu569 force-pushed the feat/get_tier_prefix_hit_rate branch from bc2b3ff to ddcd635 Compare July 8, 2026 08:25
@myliu569
myliu569 changed the base branch from archived-llm-router-dev to llm-router July 8, 2026 08:29
Comment thread uni_agent/llm_router/collectors/decoder/vllm/kv.py Outdated
Comment thread uni_agent/llm_router/collectors/collector.py Outdated
Comment thread uni_agent/llm_router/collectors/decoder/vllm/kv.py Outdated
Comment thread uni_agent/llm_router/collectors/decoder/vllm/kv.py Outdated
Comment thread examples/llm_router/parallel_infer.py Outdated
Comment thread uni_agent/llm_router/collectors/decoder/vllm/kv.py Outdated
@myliu569
myliu569 force-pushed the feat/get_tier_prefix_hit_rate branch from ddcd635 to e082697 Compare July 11, 2026 16:46
Comment thread uni_agent/llm_router/collectors/decoder/vllm/kv.py
Comment thread uni_agent/llm_router/collectors/decoder/vllm/kv.py
Comment thread uni_agent/llm_router/collectors/decoder/vllm/kv.py
Comment thread uni_agent/llm_router/collectors/decoder/vllm/kv.py
Comment on lines +149 to +150
raw_medium = cls._opt_str(fields, 5) # vLLM medium: "GPU" / "cpu"
medium = raw_medium.lower() if raw_medium is not None else None

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

为什么要全小写,而不是直接保留原始的字符串。如果只是为了方便转化为Layer枚举没有必要

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

确认了一下,KVCacheEvent.medium 当前只用于转换为 Layer 和输出 unsupported-medium 日志。由于 _medium_to_layer() 已经通过 medium.lower() 处理大小写,这里提前转小写是重复的。

已经移除解析阶段的 .lower()处理,并修改对应的单元测试断言

medium = cls._opt_str(fields, 1)
block_hashes = [_normalize_block_hash(bh) for bh in fields[0]]
raw_medium = cls._opt_str(fields, 1)
medium = raw_medium.lower() if raw_medium is not None else None

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

同上

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

修改同上

Comment thread uni_agent/llm_router/store/kv_cache_store.py Outdated
Comment thread uni_agent/llm_router/store/kv_cache_store.py Outdated
Comment on lines +108 to +131
def get_layer_prefix_hit_rate(self, node_id: str, prompt_ids: list[int],
layer: Layer = Layer.GPU) -> float:
"""Prefix-cache hit rate for a node at a layer, ∈ [0.0, 1.0].

GPU: walk the local reverse index (``replicas_by_block``) along the
prompt's prefix-hash chain until a hash isn't cached on this node.
CPU/SSD: placeholder 0.0 (mooncake /batch_query not wired yet).
"""
def get_layer_prefix_hit_rate(
self,
node_id: str,
prompt_ids: list[int],
layer: Layer = Layer.GPU,
) -> float:
"""Return the node's longest contiguous prefix hit rate for a layer."""
normalized_layer = self._normalize_layer(layer)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

去除不必要的格式化

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

已去除

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

这个会不会也是和前面一样,是precommit做的

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

是的🫪,运行precommit自动格式化的

self.block_size: int | None = None
self.replicas_by_block: dict[str, set[str]] = {}
# Per-layer per-replica block counts, maintained alongside replicas_by_block.
self._replicas_by_layer: dict[Layer, dict[str, set[str]]] = {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

self._replicas_by_layer 这个变量的意义是什么

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

该变量用于把原来的 GPU-only block 反向索引扩展为 GPU/CPU/SSD 分层索引,从而支持按层查询和增删,避免不同缓存层相互影响。GPU 层仍复用 replicas_by_block,主要是为了保持原有replicas_by_block调用兼容。这里是可以不额外加这个的,直接修改replicas_by_block的数据结构也行。

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

block-hash的str作为key,一次查询,获取所有Layer的结果

Comment on lines +76 to +90
self._on_all_blocks_cleared(event, update)
self._on_all_blocks_cleared(update)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

保留这个参数把,后面可能要改为表驱动

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

已恢复

self._block_size = event.block_size
update.set_block_size(event.block_size)
elif layer == Layer.CPU:
local_hashes = self._translate_cpu_offload_hashes(event, update.node_id)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

整体排查下,不要出现cpu-offload字样和概念,这个event事件不跟cpu-offload绑定

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

已经排查并修改

to locally-computed prefix hash (str). Used for chained
hash computation.
_block_size: Learned block size from first event.
Remote block hashes are scoped by cache layer and node so CPU offload

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

不跟cpu-offload绑定

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

上一条修改已经处理这里

"""Normalize vLLM event block hashes across GPU and CPU events.

GPU KV events publish the low 64 bits of the internal SHA256 block hash as
an int. Native CPU offload events can publish the raw internal bytes hash.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

不跟cpu-offload绑定

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

已经去掉相关描述

"""Translate token-less CPU offload hashes through the GPU mapping."""
local_hashes: list[str] = []
for remote_hash in event.block_hashes:
local_hash = self._get_remote_mapping(Layer.GPU, node_id, remote_hash)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

为什么这个方法名叫_get_remote_mapping。本意应该是自己计算的hash和vllm计算的hash。引入remote这个概念有歧义,不利于可读性。全局排查下remote这个概念

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

这里的 remote 意思是:

  • remote_hash:vLLM 进程计算并通过 ZMQ event 发来的 block hash。
  • local_hash:router 根据 token IDs 用 compute_hash() 计算的 prefix hash。

_get_remote_mapping() 实际不是“获取远端 mapping”,而是在 decoder 本地字典中,用 vLLM hash 查找对应的 router prefix hash。

这个看起来确实是有歧义的,我把这个命名改一下。

Comment thread uni_agent/llm_router/collectors/decoder/vllm/kv.py
)
return

if event.token_ids is not None:

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

这个判断很诡异,如果是可hash计算条件判断,那么这个判断条件是不足的。如果是按照gpu cpu判断,那不如直接判断layer即可

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

这里不是按 GPU/CPU 分支,而是想区分“能够通过 token IDs 计算 local hash”和“只能复用已有 mapping”两种事件形态。不过 token_ids is not None 确实不足以完整表达可计算条件(没有验证 block 数量和 parent mapping)。计划将其封装为显式的 _can_compute_local_hashes() 判断,并在条件不满足时走 mapping 解析路径。

@myliu569
myliu569 force-pushed the feat/get_tier_prefix_hit_rate branch from e082697 to 130f20c Compare July 15, 2026 01:56
Comment on lines -38 to +36
self.remote_to_local_block_hash: dict[str, str] = {}
self.vllm_to_local_block_hash: dict[tuple[Layer, str, str], str] = {}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

为什么要把node_id加入key

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

只查询 GPU 命中率时,vllm_block_hash 到本地 prefix hash 的映射主要用于单一缓存层,且事件处理默认处在同一个 vLLM 实例上下文中,因此没有显式加入 node_id;增加 CPU 命中率查询后,同一个 block 会在不同 replica 以及 GPU、CPU 层之间迁移,而 BlockRemoved、AllBlocksCleared 等事件只对其来源实例生效,所以必须将 node_id 加入映射 key,用来隔离不同 vLLM replica 的 hash 命名空间和缓存生命周期,避免一个实例的删除或清空事件误删其他实例仍在使用的映射

self.block_size: int | None = None
self.replicas_by_block: dict[str, set[str]] = {}
# Per-layer per-replica block counts, maintained alongside replicas_by_block.
self._replicas_by_layer: dict[Layer, dict[str, set[str]]] = {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

block-hash的str作为key,一次查询,获取所有Layer的结果

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