from __future__ import annotations import torch import triton import triton.language as tl @triton.jit def write_req_to_token_pool_triton( req_to_token_ptr, # [max_batch, max_context_len] req_pool_indices, prefix_tensors, pre_lens, seq_lens, extend_lens, out_cache_loc, req_to_token_ptr_stride: tl.constexpr, ): BLOCK_SIZE: tl.constexpr = 512 pid = tl.program_id(0) req_pool_index = tl.load(req_pool_indices + pid) pre_len = tl.load(pre_lens + pid) seq_len = tl.load(seq_lens + pid) prefix_tensor = tl.load(prefix_tensors + pid).to(tl.pointer_type(tl.int64)) # write prefix num_loop = tl.cdiv(pre_len, BLOCK_SIZE) for i in range(num_loop): offset = tl.arange(0, BLOCK_SIZE) + i * BLOCK_SIZE mask = offset < pre_len value = tl.load(prefix_tensor + offset, mask=mask) tl.store( req_to_token_ptr + req_pool_index * req_to_token_ptr_stride + offset, value, mask=mask, ) # NOTE: This can be slow for large bs cumsum_start = tl.cast(0, tl.int64) for i in range(pid): cumsum_start += tl.load(extend_lens + i) num_loop = tl.cdiv(seq_len - pre_len, BLOCK_SIZE) for i in range(num_loop): offset = tl.arange(0, BLOCK_SIZE) + i * BLOCK_SIZE mask = offset < (seq_len - pre_len) value = tl.load(out_cache_loc + cumsum_start + offset, mask=mask) tl.store( req_to_token_ptr + req_pool_index * req_to_token_ptr_stride + offset + pre_len, value, mask=mask, ) @triton.jit def _get_last_loc_safe_kernel( req_to_token, req_pool_indices_tensor, prefix_lens_tensor, result_i32, num_tokens, req_to_token_stride, BLOCK_SIZE: tl.constexpr, PREFIX_DTYPE_IS_I64: tl.constexpr, ): pid = tl.program_id(0) offset = tl.arange(0, BLOCK_SIZE) + pid * BLOCK_SIZE mask = offset < num_tokens if PREFIX_DTYPE_IS_I64: prefix_lens = tl.load(prefix_lens_tensor + offset, mask=mask, other=0) req_pool_indices = tl.load(req_pool_indices_tensor + offset, mask=mask, other=0) token_index = req_pool_indices * req_to_token_stride + (prefix_lens - 1) else: prefix_lens = tl.load(prefix_lens_tensor + offset, mask=mask, other=0) req_pool_indices = tl.load(req_pool_indices_tensor + offset, mask=mask, other=0) token_index = req_pool_indices.to(tl.int64) * req_to_token_stride + ( prefix_lens.to(tl.int64) - 1 ) token_mask = mask & (prefix_lens > 0) tokens = tl.load(req_to_token + token_index, mask=token_mask, other=-1) # Result stays int32 (req_to_token dtype); caller promotes after return. tl.store(result_i32 + offset, tokens, mask=mask) def get_last_loc_triton_safe( req_to_token: torch.Tensor, req_pool_indices_tensor: torch.Tensor, prefix_lens_tensor: torch.Tensor, ) -> torch.Tensor: """Fused `last_loc` Triton kernel whose in-kernel result buffer is int32 (the dtype of req_to_token). The consumer-dtype promotion happens in torch after the kernel returns, so Triton never issues a mixed-width store -- avoiding the HIP int32->int64 store bug hit by the legacy kernel. """ num_tokens = prefix_lens_tensor.shape[0] BLOCK_SIZE = 256 result_i32 = torch.empty( num_tokens, dtype=torch.int32, device=prefix_lens_tensor.device ) grid = (triton.cdiv(num_tokens, BLOCK_SIZE),) _get_last_loc_safe_kernel[grid]( req_to_token, req_pool_indices_tensor, prefix_lens_tensor, result_i32, num_tokens, req_to_token.stride(0), BLOCK_SIZE=BLOCK_SIZE, PREFIX_DTYPE_IS_I64=(prefix_lens_tensor.dtype == torch.int64), ) return result_i32.to(prefix_lens_tensor.dtype) @triton.jit def get_last_loc_kernel( req_to_token, req_pool_indices_tensor, prefix_lens_tensor, result, num_tokens, req_to_token_stride, BLOCK_SIZE: tl.constexpr, ): pid = tl.program_id(0) offset = tl.arange(0, BLOCK_SIZE) + pid * BLOCK_SIZE mask = offset < num_tokens prefix_lens = tl.load(prefix_lens_tensor + offset, mask=mask, other=0) req_pool_indices = tl.load(req_pool_indices_tensor + offset, mask=mask, other=0) token_mask = prefix_lens > 0 token_index = req_pool_indices * req_to_token_stride + (prefix_lens - 1) tokens = tl.load(req_to_token + token_index, mask=token_mask, other=-1) tl.store(result + offset, tokens, mask=mask) def get_last_loc_triton( req_to_token: torch.Tensor, req_pool_indices_tensor: torch.Tensor, prefix_lens_tensor: torch.Tensor, ) -> torch.Tensor: BLOCK_SIZE = 256 num_tokens = prefix_lens_tensor.shape[0] result = torch.empty_like(prefix_lens_tensor) grid = (triton.cdiv(num_tokens, BLOCK_SIZE),) get_last_loc_kernel[grid]( req_to_token, req_pool_indices_tensor, prefix_lens_tensor, result, num_tokens, req_to_token.stride(0), BLOCK_SIZE, ) return result