| 476 | } |
| 477 | |
| 478 | void KVCache::remove_token_range(size_t start, size_t count) { |
| 479 | if (count == 0 || start >= current_seq_len || start + count > current_seq_len) return; |
| 480 | |
| 481 | size_t tail_tokens = current_seq_len - start - count; |
| 482 | |
| 483 | auto erase_bytes = [](std::vector<uint8_t>& buf, size_t offset, size_t remove, size_t tail) { |
| 484 | std::memmove(buf.data() + offset, buf.data() + offset + remove, tail); |
| 485 | buf.resize(buf.size() - remove); |
| 486 | }; |
| 487 | |
| 488 | auto erase_floats = [](std::vector<float>& buf, size_t offset, size_t remove, size_t tail) { |
| 489 | std::memmove(buf.data() + offset, buf.data() + offset + remove, tail * sizeof(float)); |
| 490 | buf.resize(buf.size() - remove); |
| 491 | }; |
| 492 | |
| 493 | for (size_t i = 0; i < layer_caches.size(); i++) { |
| 494 | size_t dim = get_layer_head_dim(i); |
| 495 | if (dim == 0) continue; |
| 496 | auto& layer = layer_caches[i]; |
| 497 | size_t num_kv_heads = get_layer_kv_heads(i); |
| 498 | size_t bytes_per_tok = num_kv_heads * dim * element_size; |
| 499 | |
| 500 | erase_bytes(layer.keys, start * bytes_per_tok, count * bytes_per_tok, tail_tokens * bytes_per_tok); |
| 501 | erase_bytes(layer.values, start * bytes_per_tok, count * bytes_per_tok, tail_tokens * bytes_per_tok); |
| 502 | |
| 503 | if (precision == Precision::INT8 && !layer.key_scales.empty()) { |
| 504 | size_t scaler_per_tok = num_kv_heads * dim / KV_QUANT_GROUP_SIZE; |
| 505 | erase_floats(layer.key_scales, start * scaler_per_tok, count * scaler_per_tok, tail_tokens * scaler_per_tok); |
| 506 | erase_floats(layer.value_scales, start * scaler_per_tok, count * scaler_per_tok, tail_tokens * scaler_per_tok); |
| 507 | } |
| 508 | } |
| 509 | |
| 510 | current_seq_len -= count; |
| 511 | total_seq_len -= count; |
| 512 | } |
| 513 | |
| 514 | void KVCache::compact_to_windows(const std::vector<size_t>& target_windows) { |
| 515 | for (size_t i = 0; i < layer_caches.size(); i++) { |
no test coverage detected