-
Notifications
You must be signed in to change notification settings - Fork 2k
[Performance]Batch kvcache offloading via aclrtMemcpyBatchAsync #7819
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
3db2a33
fc2e5eb
ebf582d
5c17e15
f664dc9
1dc4c4f
86a785d
350834f
836064c
6eed37b
35f43dd
da2586c
3838709
9c21b19
cdbdd52
36e7020
6ef2a5d
ecd50c4
4520d63
4c6ce06
33bd8ab
a903f24
a09758a
9b31f4e
8f01044
fa05b23
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -93,6 +93,18 @@ def __init__( | |||||||
| ), | ||||||||
| ) | ||||||||
| ) | ||||||||
|
|
||||||||
| # Pre-compute base pointers and block sizes for batch copies. | ||||||||
| self._src_base_ptrs = np.array( | ||||||||
| [t.data_ptr() for t in self.src_tensors], dtype=np.int64 | ||||||||
| ) | ||||||||
| self._dst_base_ptrs = np.array( | ||||||||
| [t.data_ptr() for t in self.dst_tensors], dtype=np.int64 | ||||||||
| ) | ||||||||
| self._block_size_in_bytes_arr = np.array( | ||||||||
| self.tensor_block_size_in_bytes, dtype=np.int64 | ||||||||
| ) | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The attributes This logic for preparing base pointers and sizes should be moved into |
||||||||
|
|
||||||||
|
|
||||||||
| def transfer_async(self, job_id: int, spec: TransferSpec) -> bool: | ||||||||
| logger.info("start transfer_async...") | ||||||||
|
|
@@ -123,25 +135,38 @@ def transfer_async(self, job_id: int, spec: TransferSpec) -> bool: | |||||||
|
|
||||||||
| assert src_sub_block_count == dst_blocks.size * dst_block_size_factor - dst_sub_blocks_to_skip | ||||||||
|
|
||||||||
| src_to_dst = np.empty((src_sub_block_count, 2), dtype=np.int64) | ||||||||
| expand_block_ids(src_blocks, src_block_size_factor, src_to_dst[:, 0]) | ||||||||
| expand_block_ids( | ||||||||
| dst_blocks, | ||||||||
| dst_block_size_factor, | ||||||||
| src_to_dst[:, 1], | ||||||||
| skip_count=dst_sub_blocks_to_skip, | ||||||||
| ) | ||||||||
| src_to_dst_tensor = torch.from_numpy(src_to_dst) | ||||||||
| # src_to_dst = np.empty((src_sub_block_count, 2), dtype=np.int64) | ||||||||
| src_block_ids = np.empty(dst_sub_block_count, dtype=np.int64) | ||||||||
| dst_block_ids = np.empty(dst_sub_block_count, dtype=np.int64) | ||||||||
| expand_block_ids(src_blocks, src_block_size_factor, src_block_ids) | ||||||||
| expand_block_ids(dst_blocks, self.dst_block_size_factor, dst_block_ids) | ||||||||
|
|
||||||||
| # Build flat pointer arrays for all tensors × all block pairs. | ||||||||
| num_pairs = dst_sub_block_count | ||||||||
| num_tensors = len(self.src_tensors) | ||||||||
| total = num_pairs * num_tensors | ||||||||
|
|
||||||||
| all_src = np.empty(total, dtype=np.int64) | ||||||||
| all_dst = np.empty(total, dtype=np.int64) | ||||||||
| all_sizes = np.empty(total, dtype=np.int64) | ||||||||
|
|
||||||||
| for t_idx, bsz in enumerate(self._block_size_in_bytes_arr): | ||||||||
| start = t_idx * num_pairs | ||||||||
| end = start + num_pairs | ||||||||
| all_src[start:end] = self._src_base_ptrs[t_idx] + src_block_ids * bsz | ||||||||
| all_dst[start:end] = self._dst_base_ptrs[t_idx] + dst_block_ids * bsz | ||||||||
| all_sizes[start:end] = bsz | ||||||||
|
|
||||||||
| batch_src = torch.from_numpy(all_src) | ||||||||
| batch_dst = torch.from_numpy(all_dst) | ||||||||
| batch_sizes = torch.from_numpy(all_sizes) | ||||||||
|
|
||||||||
| event = self.events_pool.pop() if self.events_pool else torch.npu.Event() | ||||||||
| with torch.npu.stream(stream): | ||||||||
| for src_tensor, dst_tensor in zip(src_tensors, dst_tensors): | ||||||||
| src_key_cache, src_value_cache = src_tensor[0], src_tensor[1] | ||||||||
| dst_key_cache, dst_value_cache = dst_tensor[0], dst_tensor[1] | ||||||||
|
|
||||||||
| torch.ops._C_ascend.swap_blocks(src_key_cache, dst_key_cache, src_to_dst_tensor) | ||||||||
| torch.ops._C_ascend.swap_blocks(src_value_cache, dst_value_cache, src_to_dst_tensor) | ||||||||
|
|
||||||||
| torch.ops._C_ascend.swap_blocks_batch(src_key_cache, dst_key_cache, src_to_dst_tensor) | ||||||||
| torch.ops._C_ascend.swap_blocks_batch(src_value_cache, dst_value_cache, src_to_dst_tensor) | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The calls to The new batched implementation prepares Additionally, there are other errors in this block:
Suggested change
|
||||||||
|
|
||||||||
| event.record(stream) | ||||||||
|
|
||||||||
| self.transfer_events[job_id] = event | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function signature for
swap_blocks_batchusesconst torch::Tensor&forsrc_ptrsanddst_ptrs. However, the operator registration on line 881 (ops.def("swap_blocks_batch(Tensor! x, Tensor! y, Tensor z) -> ()");) marks these tensors as mutable (!). This mismatch forces the use ofconst_caston lines 167-172, which is unsafe and breaks theconstcontract.To fix this, the function signature should be updated to match the registration. This will also allow removing the
const_casts. Additionally, theconst_castforsize_datais unnecessary as theaclrtMemcpyBatchAsyncAPI expectsconst size_t*for size-related arguments.