[HiMambaTree]: Optimize mamba host lock mechanism (#21750)
This commit is contained in:
@@ -511,13 +511,22 @@ class HiMambaRadixCache(MambaRadixCache):
|
|||||||
self.cache_controller.storage_backend.get_stats()
|
self.cache_controller.storage_backend.get_stats()
|
||||||
)
|
)
|
||||||
|
|
||||||
def _protect_host_node(self, node: TreeNode):
|
def _protect_host_node(self, node: TreeNode, protect_mamba: bool = True):
|
||||||
node.protect_host()
|
node.protect_host()
|
||||||
self.evictable_full_host_leaves.discard(node)
|
self.evictable_full_host_leaves.discard(node)
|
||||||
|
if protect_mamba:
|
||||||
|
node.protect_host_mamba()
|
||||||
|
if self.mamba_host_lru_list.in_list(node):
|
||||||
|
self.mamba_host_lru_list.remove_node(node)
|
||||||
|
|
||||||
def _release_host_node(self, node: TreeNode):
|
def _release_host_node(self, node: TreeNode, release_mamba: bool = True):
|
||||||
node.release_host()
|
node.release_host()
|
||||||
if node.host_ref_counter == 0:
|
if release_mamba:
|
||||||
|
node.release_host_mamba()
|
||||||
|
if node.host_mamba_ref_counter == 0 and node.mamba_host_value is not None:
|
||||||
|
if not self.mamba_host_lru_list.in_list(node):
|
||||||
|
self.mamba_host_lru_list.insert_mru(node)
|
||||||
|
if node.host_ref_counter == 0 and node.host_mamba_ref_counter == 0:
|
||||||
self._update_full_host_leaf_status(node)
|
self._update_full_host_leaf_status(node)
|
||||||
|
|
||||||
def _discard_from_leaf_sets(self, node: TreeNode):
|
def _discard_from_leaf_sets(self, node: TreeNode):
|
||||||
@@ -544,6 +553,7 @@ class HiMambaRadixCache(MambaRadixCache):
|
|||||||
or not node.backuped
|
or not node.backuped
|
||||||
or node == self.root_node
|
or node == self.root_node
|
||||||
or node.host_ref_counter > 0
|
or node.host_ref_counter > 0
|
||||||
|
or node.host_mamba_ref_counter > 0
|
||||||
):
|
):
|
||||||
self.evictable_full_host_leaves.discard(node)
|
self.evictable_full_host_leaves.discard(node)
|
||||||
return
|
return
|
||||||
@@ -632,7 +642,10 @@ class HiMambaRadixCache(MambaRadixCache):
|
|||||||
assert node.mamba_value is None, f"has device mamba, {node.id=}"
|
assert node.mamba_value is None, f"has device mamba, {node.id=}"
|
||||||
assert (
|
assert (
|
||||||
node.host_ref_counter == 0
|
node.host_ref_counter == 0
|
||||||
), f"in use, {node.id=} {node.host_ref_counter=}"
|
), f"host kv in use, {node.id=} {node.host_ref_counter=}"
|
||||||
|
assert (
|
||||||
|
node.host_mamba_ref_counter == 0
|
||||||
|
), f"host mamba in use, {node.id=} {node.host_mamba_ref_counter=}"
|
||||||
|
|
||||||
full_num_evicted = self.cache_controller.evict_host(node.host_value)
|
full_num_evicted = self.cache_controller.evict_host(node.host_value)
|
||||||
node.host_value = None
|
node.host_value = None
|
||||||
@@ -665,7 +678,11 @@ class HiMambaRadixCache(MambaRadixCache):
|
|||||||
|
|
||||||
self._discard_from_leaf_sets(node)
|
self._discard_from_leaf_sets(node)
|
||||||
|
|
||||||
if node.backuped and node.host_ref_counter == 0:
|
if (
|
||||||
|
node.backuped
|
||||||
|
and node.host_ref_counter == 0
|
||||||
|
and node.host_mamba_ref_counter == 0
|
||||||
|
):
|
||||||
self.cache_controller.evict_host(node.host_value)
|
self.cache_controller.evict_host(node.host_value)
|
||||||
node.host_value = None
|
node.host_value = None
|
||||||
|
|
||||||
@@ -782,15 +799,21 @@ class HiMambaRadixCache(MambaRadixCache):
|
|||||||
num_evicted = 0
|
num_evicted = 0
|
||||||
while num_evicted < num_mamba_hosts and self.mamba_host_lru_list.in_list(x):
|
while num_evicted < num_mamba_hosts and self.mamba_host_lru_list.in_list(x):
|
||||||
x_next = self.mamba_host_lru_list.get_prev_no_lock(x)
|
x_next = self.mamba_host_lru_list.get_prev_no_lock(x)
|
||||||
if x.host_ref_counter > 0:
|
|
||||||
x = x_next
|
|
||||||
continue
|
|
||||||
|
|
||||||
if x in self.evictable_full_host_leaves:
|
if x in self.evictable_full_host_leaves:
|
||||||
|
# Leaf: evictable_full_host_leaves guarantees both counters == 0
|
||||||
|
assert (
|
||||||
|
x.host_ref_counter == 0
|
||||||
|
), f"evict host leaf: host_ref_counter != 0 with {x.id=} {x.host_ref_counter=}"
|
||||||
|
assert (
|
||||||
|
x.host_mamba_ref_counter == 0
|
||||||
|
), f"evict host leaf: host_mamba_ref_counter != 0 with {x.id=} {x.host_mamba_ref_counter=}"
|
||||||
self._evict_host_leaf(x)
|
self._evict_host_leaf(x)
|
||||||
num_evicted += 1
|
num_evicted += 1
|
||||||
else:
|
else:
|
||||||
# internal host node: free host mamba only (tombstone)
|
# Internal host node
|
||||||
|
assert (
|
||||||
|
x.host_mamba_ref_counter == 0
|
||||||
|
), f"evict host mamba internal: host_mamba_ref_counter != 0 with {x.id=} {x.host_mamba_ref_counter=}"
|
||||||
self.mamba_host_lru_list.remove_node(x)
|
self.mamba_host_lru_list.remove_node(x)
|
||||||
self.mamba_pool_host.free(x.mamba_host_value)
|
self.mamba_pool_host.free(x.mamba_host_value)
|
||||||
x.mamba_host_value = None
|
x.mamba_host_value = None
|
||||||
@@ -830,7 +853,7 @@ class HiMambaRadixCache(MambaRadixCache):
|
|||||||
# Leaf: evict KV + mamba atomically
|
# Leaf: evict KV + mamba atomically
|
||||||
assert (
|
assert (
|
||||||
x.full_lock_ref == 0
|
x.full_lock_ref == 0
|
||||||
), f"evict leaf node invalid with {x.id=} {x.full_lock_ref=}"
|
), f"evict device leaf: full_lock_ref mismatch with {x.id=} {x.full_lock_ref=} {x.mamba_lock_ref=}"
|
||||||
|
|
||||||
x_next = self.mamba_lru_list.get_prev_no_lock(x)
|
x_next = self.mamba_lru_list.get_prev_no_lock(x)
|
||||||
_, mamba_evicted = self._evict_device_leaf(x)
|
_, mamba_evicted = self._evict_device_leaf(x)
|
||||||
@@ -1467,9 +1490,10 @@ class HiMambaRadixCache(MambaRadixCache):
|
|||||||
logger.exception("Force release pending prefetch ops failed.")
|
logger.exception("Force release pending prefetch ops failed.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for ack_id, node in list(self.ongoing_backup.items()):
|
for ack_id, entry in list(self.ongoing_backup.items()):
|
||||||
try:
|
try:
|
||||||
self._release_host_node(node)
|
node, mamba_host_protected = entry
|
||||||
|
self._release_host_node(node, release_mamba=mamba_host_protected)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception(
|
logger.exception(
|
||||||
"Failed to release host protection for backup op %s", ack_id
|
"Failed to release host protection for backup op %s", ack_id
|
||||||
@@ -1521,7 +1545,8 @@ class HiMambaRadixCache(MambaRadixCache):
|
|||||||
ack_id = operation.id
|
ack_id = operation.id
|
||||||
entry = self.ongoing_backup.pop(ack_id, None)
|
entry = self.ongoing_backup.pop(ack_id, None)
|
||||||
if entry is not None:
|
if entry is not None:
|
||||||
self._release_host_node(entry)
|
node, mamba_host_protected = entry
|
||||||
|
self._release_host_node(node, release_mamba=mamba_host_protected)
|
||||||
if log_metrics and self.enable_storage_metrics:
|
if log_metrics and self.enable_storage_metrics:
|
||||||
self.storage_metrics_collector.log_backuped_tokens(
|
self.storage_metrics_collector.log_backuped_tokens(
|
||||||
operation.completed_tokens
|
operation.completed_tokens
|
||||||
@@ -1721,8 +1746,9 @@ class HiMambaRadixCache(MambaRadixCache):
|
|||||||
prefix_keys,
|
prefix_keys,
|
||||||
extra_pools=extra_pools,
|
extra_pools=extra_pools,
|
||||||
)
|
)
|
||||||
self.ongoing_backup[operation_id] = node
|
mamba_host_protected = extra_pools is not None
|
||||||
self._protect_host_node(node)
|
self.ongoing_backup[operation_id] = (node, mamba_host_protected)
|
||||||
|
self._protect_host_node(node, protect_mamba=mamba_host_protected)
|
||||||
|
|
||||||
def prefetch_from_storage(
|
def prefetch_from_storage(
|
||||||
self,
|
self,
|
||||||
@@ -1743,7 +1769,7 @@ class HiMambaRadixCache(MambaRadixCache):
|
|||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
self._protect_host_node(last_host_node)
|
self._protect_host_node(last_host_node, protect_mamba=False)
|
||||||
|
|
||||||
# Allocate host KV memory
|
# Allocate host KV memory
|
||||||
host_indices = self._alloc_with_evict(
|
host_indices = self._alloc_with_evict(
|
||||||
@@ -1752,16 +1778,21 @@ class HiMambaRadixCache(MambaRadixCache):
|
|||||||
self.evict_host,
|
self.evict_host,
|
||||||
)
|
)
|
||||||
if host_indices is None:
|
if host_indices is None:
|
||||||
self._release_host_node(last_host_node)
|
self._release_host_node(last_host_node, release_mamba=False)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Allocate host mamba slot
|
# Allocate host mamba slot
|
||||||
extra_pools = self.mamba_prefetch_alloc(new_input_tokens, last_hash)
|
extra_pools = self.mamba_prefetch_alloc(new_input_tokens, last_hash)
|
||||||
if extra_pools is None:
|
if extra_pools is None:
|
||||||
self.cache_controller.mem_pool_host.free(host_indices)
|
self.cache_controller.mem_pool_host.free(host_indices)
|
||||||
self._release_host_node(last_host_node)
|
self._release_host_node(last_host_node, release_mamba=False)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# mamba is also being loaded, protect host mamba as well
|
||||||
|
last_host_node.protect_host_mamba()
|
||||||
|
if self.mamba_host_lru_list.in_list(last_host_node):
|
||||||
|
self.mamba_host_lru_list.remove_node(last_host_node)
|
||||||
|
|
||||||
operation = self.cache_controller.prefetch(
|
operation = self.cache_controller.prefetch(
|
||||||
req_id,
|
req_id,
|
||||||
host_indices,
|
host_indices,
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ class TreeNode:
|
|||||||
|
|
||||||
self.hit_count = 0
|
self.hit_count = 0
|
||||||
self.host_ref_counter = 0
|
self.host_ref_counter = 0
|
||||||
|
self.host_mamba_ref_counter = 0
|
||||||
# store the host indices of KV cache
|
# store the host indices of KV cache
|
||||||
self.host_value = None
|
self.host_value = None
|
||||||
# store hash values of each pages
|
# store hash values of each pages
|
||||||
@@ -122,16 +123,27 @@ class TreeNode:
|
|||||||
return self.mamba_host_value is not None
|
return self.mamba_host_value is not None
|
||||||
|
|
||||||
def protect_host(self):
|
def protect_host(self):
|
||||||
"""Protect the host value from eviction."""
|
"""Protect the host KV value from eviction."""
|
||||||
self.host_ref_counter += 1
|
self.host_ref_counter += 1
|
||||||
|
|
||||||
def release_host(self):
|
def release_host(self):
|
||||||
"""Release the host value, allowing it to be evicted."""
|
"""Release the host KV value, allowing it to be evicted."""
|
||||||
if self.host_ref_counter > 0:
|
if self.host_ref_counter > 0:
|
||||||
self.host_ref_counter -= 1
|
self.host_ref_counter -= 1
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Host reference counter is already zero.")
|
raise RuntimeError("Host reference counter is already zero.")
|
||||||
|
|
||||||
|
def protect_host_mamba(self):
|
||||||
|
"""Protect the host mamba value from eviction."""
|
||||||
|
self.host_mamba_ref_counter += 1
|
||||||
|
|
||||||
|
def release_host_mamba(self):
|
||||||
|
"""Release the host mamba value, allowing it to be evicted."""
|
||||||
|
if self.host_mamba_ref_counter > 0:
|
||||||
|
self.host_mamba_ref_counter -= 1
|
||||||
|
else:
|
||||||
|
raise RuntimeError("Host mamba reference counter is already zero.")
|
||||||
|
|
||||||
def get_last_hash_value(self) -> Optional[str]:
|
def get_last_hash_value(self) -> Optional[str]:
|
||||||
"""Returns the hash value of the last page in this node."""
|
"""Returns the hash value of the last page in this node."""
|
||||||
if self.hash_value is None or len(self.hash_value) == 0:
|
if self.hash_value is None or len(self.hash_value) == 0:
|
||||||
|
|||||||
Reference in New Issue
Block a user