[Perf] Walk the radix tree by offset instead of re-slicing token storage (ported from #36507) (#37324)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khoa Pham
2026-09-03 11:13:03 +08:00
committed by GitHub
co-authored by Claude Opus 5
parent 57c26a84e0
commit cf3173aeb9
2 changed files with 36 additions and 14 deletions
+29 -8
View File
@@ -180,10 +180,18 @@ class RadixKey:
def match(self, other: RadixKey, page_size: int = 1) -> int: def match(self, other: RadixKey, page_size: int = 1) -> int:
"""Logical-unit prefix length shared with ``other``. Result is rounded down to ``page_size``.""" """Logical-unit prefix length shared with ``other``. Result is rounded down to ``page_size``."""
return self.match_at(other, offset=0, page_size=page_size)
def match_at(self, other: RadixKey, offset: int, page_size: int = 1) -> int:
"""Match without slicing while preserving bigram boundaries and limit semantics."""
self._check_compatible(other) self._check_compatible(other)
if self.is_bigram != other.is_bigram:
raise ValueError("RadixKey operations require matching bigram modes")
if offset < 0 or offset > len(other):
raise IndexError(f"RadixKey offset out of range: {offset}")
t0, t1 = self.token_ids, other.token_ids t0, t1 = self.token_ids, other.token_ids
assert type(t0) is type(t1), (type(t0), type(t1)) assert type(t0) is type(t1), (type(t0), type(t1))
n = min(len(t0), len(t1)) n = min(self._raw_len(), other._raw_len() - offset)
# Exponential search for the first diverging token: gallop in doubling # Exponential search for the first diverging token: gallop in doubling
# windows (one C-level slice compare each), then binary-search the window # windows (one C-level slice compare each), then binary-search the window
@@ -193,10 +201,10 @@ class RadixKey:
step = 1 step = 1
while lo < n: while lo < n:
hi = lo + step if lo + step < n else n hi = lo + step if lo + step < n else n
if t0[lo:hi] != t1[lo:hi]: if t0[lo:hi] != t1[offset + lo : offset + hi]:
while hi - lo > 1: while hi - lo > 1:
mid = (lo + hi) // 2 mid = (lo + hi) // 2
if t0[lo:mid] == t1[lo:mid]: if t0[lo:mid] == t1[offset + lo : offset + mid]:
lo = mid lo = mid
else: else:
hi = mid hi = mid
@@ -206,24 +214,37 @@ class RadixKey:
step *= 2 step *= 2
if self.is_bigram: if self.is_bigram:
matched = max(0, min(matched_tokens - 1, len(self), len(other))) matched = max(0, min(matched_tokens - 1, len(self), len(other) - offset))
return (matched // page_size) * page_size if page_size > 1 else matched return (matched // page_size) * page_size if page_size > 1 else matched
matched_tokens = min(matched_tokens, len(self), len(other)) matched_tokens = min(matched_tokens, len(self), len(other) - offset)
if page_size == 1: if page_size == 1:
return matched_tokens return matched_tokens
return (matched_tokens // page_size) * page_size return (matched_tokens // page_size) * page_size
def child_key(self, page_size: int = 1): def child_key(self, page_size: int = 1):
"""Hashable dict-key for the first ``page_size`` logical units, namespaced by ``extra_key``.""" """Hashable dict-key for the first ``page_size`` logical units, namespaced by ``extra_key``."""
return self.child_key_at(offset=0, page_size=page_size)
def child_key_at(self, offset: int, page_size: int = 1):
"""Hashable child key at ``offset`` without slicing token storage."""
if offset < 0 or offset + page_size > len(self):
raise IndexError(
f"RadixKey child range out of bounds: offset={offset}, "
f"page_size={page_size}, len={len(self)}"
)
t = self.token_ids t = self.token_ids
if self.is_bigram: if self.is_bigram:
if page_size == 1: if page_size == 1:
plain = (t[0], t[1]) plain = (t[offset], t[offset + 1])
else: else:
plain = tuple((t[j], t[j + 1]) for j in range(page_size)) plain = tuple(
(t[j], t[j + 1]) for j in range(offset, offset + page_size)
)
else: else:
plain = t[0] if page_size == 1 else tuple(t[:page_size]) plain = (
t[offset] if page_size == 1 else tuple(t[offset : offset + page_size])
)
if self.cache_salt is not None: if self.cache_salt is not None:
return ((self.extra_key, self.cache_salt), plain) return ((self.extra_key, self.cache_salt), plain)
return plain if self.extra_key is None else (self.extra_key, plain) return plain if self.extra_key is None else (self.extra_key, plain)
@@ -737,7 +737,8 @@ class UnifiedTreeCore(UnifiedTreeCoreInterface):
# nodes can also match, so we separately track the best device-resident # nodes can also match, so we separately track the best device-resident
# match for scheduler prefix indices and locking. # match for scheduler prefix indices and locking.
node = self.root_node node = self.root_node
child_key = key.child_key(self.page_size) key_offset = 0
child_key = key.child_key_at(key_offset, self.page_size)
value: list[torch.Tensor] = [] value: list[torch.Tensor] = []
best_match_node = node best_match_node = node
best_match_device_node = node best_match_device_node = node
@@ -778,14 +779,14 @@ class UnifiedTreeCore(UnifiedTreeCoreInterface):
best_match_device_value_len = len(value) best_match_device_value_len = len(value)
best_match_device_node = node best_match_device_node = node
while len(key) > 0 and child_key in node.children: while key_offset < len(key) and child_key in node.children:
child = node.children[child_key] child = node.children[child_key]
# HiCache: dead node (evicted + not backuped) — stop traversal # HiCache: dead node (evicted + not backuped) — stop traversal
if child.evicted and not child.backuped: if child.evicted and not child.backuped:
break break
prefix_len = child.key.match(key, page_size=self.page_size) prefix_len = child.key.match_at(key, key_offset, page_size=self.page_size)
full_kv_hit_length += prefix_len full_kv_hit_length += prefix_len
if prefix_len < len(child.key): if prefix_len < len(child.key):
node, action = self._split_node(child.key, child, prefix_len) node, action = self._split_node(child.key, child, prefix_len)
@@ -798,9 +799,9 @@ class UnifiedTreeCore(UnifiedTreeCoreInterface):
value.append(child.component_data[BASE_COMPONENT_TYPE].value) value.append(child.component_data[BASE_COMPONENT_TYPE].value)
node = child node = child
_update_best_if_valid(node) _update_best_if_valid(node)
key = key[prefix_len:] key_offset += prefix_len
if len(key): if key_offset < len(key):
child_key = key.child_key(self.page_size) child_key = key.child_key_at(key_offset, self.page_size)
return ( return (
value, value,