|
112 | 112 |
|
113 | 113 | half* k_full = nullptr; |
114 | 114 | half* v_full = nullptr; |
| 115 | + bool used_eager_scratch = false; |
115 | 116 | if (cap_replay) { |
116 | 117 | k_full = chunk_capture_k_; |
117 | 118 | v_full = chunk_capture_v_; |
118 | 119 | } else { |
119 | | - cudaMallocAsync(&k_full, full_bytes, stream); |
120 | | - cudaMallocAsync(&v_full, full_bytes, stream); |
| 120 | + // Persistent gather scratch (grow-only, 64 MiB steps so a |
| 121 | + // growing ctx doesn't re-allocate every chunk). Falls back to |
| 122 | + // the per-call alloc when the grow fails. |
| 123 | + if (chunk_eager_bytes_ < full_bytes) { |
| 124 | + constexpr size_t kGrowStep = 64u << 20; |
| 125 | + const size_t cap = ((full_bytes + kGrowStep - 1) / kGrowStep) * kGrowStep; |
| 126 | + if (chunk_eager_k_) { cudaFreeAsync(chunk_eager_k_, stream); chunk_eager_k_ = nullptr; } |
| 127 | + if (chunk_eager_v_) { cudaFreeAsync(chunk_eager_v_, stream); chunk_eager_v_ = nullptr; } |
| 128 | + chunk_eager_bytes_ = 0; |
| 129 | + if (cudaMallocAsync(&chunk_eager_k_, cap, stream) == cudaSuccess && |
| 130 | + cudaMallocAsync(&chunk_eager_v_, cap, stream) == cudaSuccess) { |
| 131 | + chunk_eager_bytes_ = cap; |
| 132 | + } else { |
| 133 | + if (chunk_eager_k_) { cudaFreeAsync(chunk_eager_k_, stream); chunk_eager_k_ = nullptr; } |
| 134 | + if (chunk_eager_v_) { cudaFreeAsync(chunk_eager_v_, stream); chunk_eager_v_ = nullptr; } |
| 135 | + } |
| 136 | + } |
| 137 | + if (chunk_eager_bytes_ >= full_bytes) { |
| 138 | + k_full = chunk_eager_k_; |
| 139 | + v_full = chunk_eager_v_; |
| 140 | + used_eager_scratch = true; |
| 141 | + } else { |
| 142 | + cudaMallocAsync(&k_full, full_bytes, stream); |
| 143 | + cudaMallocAsync(&v_full, full_bytes, stream); |
| 144 | + } |
121 | 145 | } |
122 | 146 |
|
123 | 147 | // Gather past KV [0, q_offset) directly into k_full[0..q_offset], v_full[0..q_offset]. |
|
254 | 278 | cfg.attn_logit_softcap, stream, runtime_config(), q_offset); |
255 | 279 | } |
256 | 280 |
|
257 | | - if (!cap_replay) { |
| 281 | + if (!cap_replay && !used_eager_scratch) { |
258 | 282 | cudaFreeAsync(k_full, stream); |
259 | 283 | cudaFreeAsync(v_full, stream); |
260 | 284 | } |
|
0 commit comments