from __future__ import annotations import logging from typing import TYPE_CHECKING from sglang.jit_kernel.utils import cache_once, load_jit, make_cpp_args if TYPE_CHECKING: import torch from tvm_ffi.module import Module DEFAULT_BLOCK_QUOTA = 2 @cache_once def _jit_hicache_module(*, element_size: int, unroll: int, block_quota: int) -> Module: num_threads, occupancy = 1024, 1 args = make_cpp_args( element_size, unroll, block_quota, num_threads, occupancy, ) return load_jit( "hicache", *args, cuda_files=["hicache.cuh"], cuda_wrappers=[ ("launch_one", f"&HiCacheKernel<{args}>::run_one"), ("launch_all", f"&HiCacheKernel<{args}>::run_all"), ], ) def can_use_hicache_jit_kernel( *, element_size: int, unroll: int | None = None, # can be tuned for performance block_quota: int | None = None, # can be tuned for less interference ) -> bool: try: unroll = unroll or _default_unroll(element_size) block_quota = block_quota or DEFAULT_BLOCK_QUOTA _jit_hicache_module( element_size=element_size, unroll=unroll, block_quota=block_quota, ) return True except Exception as e: logger = logging.getLogger(__name__) logger.warning(f"Failed to load JIT HiCache kernel: {e}") return False def _default_unroll(element_size: int) -> int: if element_size <= 512: return 4 if element_size <= 1024: return 2 # fallback: no unroll return 1 def transfer_hicache_one_layer( k_cache_dst: torch.Tensor, v_cache_dst: torch.Tensor, indices_dst: torch.Tensor, k_cache_src: torch.Tensor, v_cache_src: torch.Tensor, indices_src: torch.Tensor, *, element_dim: int | None = None, unroll: int | None = None, # can be tuned for performance block_quota: int | None = None, # can be tuned for less interference ) -> None: element_dim = element_dim or k_cache_dst.size(-1) k_cache_src = k_cache_src.view(-1, element_dim) v_cache_src = v_cache_src.view(-1, element_dim) k_cache_dst = k_cache_dst.view(-1, element_dim) v_cache_dst = v_cache_dst.view(-1, element_dim) element_size = element_dim * k_cache_dst.element_size() block_quota = block_quota or DEFAULT_BLOCK_QUOTA unroll = unroll or _default_unroll(element_size) module = _jit_hicache_module( element_size=element_size, unroll=unroll, block_quota=block_quota, ) module.launch_one( k_cache_dst, v_cache_dst, indices_dst, k_cache_src, v_cache_src, indices_src, ) def transfer_hicache_all_layer( k_ptr_dst: torch.Tensor, v_ptr_dst: torch.Tensor, indices_dst: torch.Tensor, k_ptr_src: torch.Tensor, v_ptr_src: torch.Tensor, indices_src: torch.Tensor, *, kv_cache_src_stride_bytes: int, kv_cache_dst_stride_bytes: int, element_size: int | None = None, unroll: int | None = None, # can be tuned for performance block_quota: int | None = None, # can be tuned for less interference ) -> None: if element_size is None: # assume both contiguous assert kv_cache_dst_stride_bytes == kv_cache_src_stride_bytes element_size = kv_cache_dst_stride_bytes block_quota = block_quota or DEFAULT_BLOCK_QUOTA unroll = unroll or _default_unroll(element_size) module = _jit_hicache_module( element_size=element_size, unroll=unroll, block_quota=block_quota, ) module.launch_all( k_ptr_dst, v_ptr_dst, indices_dst, k_ptr_src, v_ptr_src, indices_src, kv_cache_src_stride_bytes, kv_cache_dst_stride_bytes, )