Skip to content

Commit d0b9b26

Browse files
authored
Fix ultra-long context kernel launch issue for indexed moe forward (#94)
* Fix extra-long context kernel launch issue for indexed moe forward * Fix all entries for input quant with quantize_q8_1
1 parent 5e6c385 commit d0b9b26

1 file changed

Lines changed: 78 additions & 31 deletions

File tree

candle-core/src/quantized/cuda.rs

Lines changed: 78 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,59 @@ fn pad(p: usize, q: usize) -> usize {
4444
}
4545

4646
fn quantize_q8_1(
47-
src: &CudaView<f32>,
47+
src: &CudaSlice<f32>,
4848
dst: &mut CudaSlice<u8>,
49-
elem_count: usize,
49+
k: usize,
5050
ky: usize,
5151
dev: &CudaDevice,
5252
) -> Result<()> {
53-
let kx = elem_count;
54-
let kx_padded = pad(kx, MATRIX_ROW_PADDING);
53+
let kx_padded = pad(k, MATRIX_ROW_PADDING);
5554
let num_blocks = ceil_div(kx_padded, CUDA_QUANTIZE_BLOCK_SIZE);
55+
56+
let total_rows = ky;
57+
// Get Q8_1 metadata.
58+
let q8_1_block_size = GgmlDType::Q8_1.block_size();
59+
let q8_1_type_size = GgmlDType::Q8_1.type_size();
60+
61+
// Calculate the size of the output buffer in bytes.
62+
let num_blocks_per_row = kx_padded / q8_1_block_size;
63+
let dst_row_size_bytes = num_blocks_per_row * q8_1_type_size;
64+
65+
const CHUNK_SIZE: usize = 65535; // gridDim.y limit
5666
let func = dev.get_or_load_func("quantize_q8_1", &candle_kernels::QUANTIZED)?;
57-
let cfg = cudarc::driver::LaunchConfig {
58-
grid_dim: (num_blocks as u32, ky as u32, 1),
59-
block_dim: (CUDA_QUANTIZE_BLOCK_SIZE as u32, 1, 1),
60-
shared_mem_bytes: 0,
61-
};
62-
let mut builder = func.builder();
63-
builder.arg(src);
64-
builder.arg(dst);
65-
barg!(builder, kx as i32, kx_padded as i32);
66-
unsafe { builder.launch(cfg) }.w()?;
67+
68+
let mut rows_processed = 0;
69+
while rows_processed < total_rows {
70+
// --- calculate the number of rows for this chunk ---
71+
let remaining_rows = total_rows - rows_processed;
72+
// This is our gridDim.y, now <= 65535
73+
let rows_in_chunk = std::cmp::min(CHUNK_SIZE, remaining_rows);
74+
75+
// --- slice the source (f32) tensor by elements ---
76+
let src_start_elem = rows_processed * k;
77+
let src_num_elems = rows_in_chunk * k;
78+
let src_chunk = src.slice(src_start_elem..(src_start_elem + src_num_elems));
79+
80+
// --- slice the destination (u8) tensor by bytes ---
81+
let dst_start_byte = rows_processed * dst_row_size_bytes;
82+
let dst_num_bytes = rows_in_chunk * dst_row_size_bytes;
83+
let dst_chunk = dst.slice(dst_start_byte..(dst_start_byte + dst_num_bytes));
84+
85+
let cfg = cudarc::driver::LaunchConfig {
86+
grid_dim: (num_blocks as u32, rows_in_chunk as u32, 1),
87+
block_dim: (CUDA_QUANTIZE_BLOCK_SIZE as u32, 1, 1),
88+
shared_mem_bytes: 0,
89+
};
90+
91+
let mut builder = func.builder();
92+
builder.arg(&src_chunk);
93+
builder.arg(&dst_chunk);
94+
barg!(builder, k as i32, kx_padded as i32);
95+
unsafe { builder.launch(cfg) }.w()?;
96+
97+
rows_processed += rows_in_chunk;
98+
}
99+
67100
Ok(())
68101
}
69102

@@ -189,7 +222,7 @@ fn dequantize_f16(
189222

190223
fn dequantize_mul_mat_vec(
191224
data: &PaddedCudaSlice,
192-
y: &CudaView<f32>,
225+
y: &CudaSlice<f32>,
193226
dtype: GgmlDType,
194227
ncols: usize,
195228
nrows: usize,
@@ -235,7 +268,7 @@ fn dequantize_mul_mat_vec(
235268

236269
fn mul_mat_vec_via_q8_1(
237270
data: &PaddedCudaSlice,
238-
y: &CudaView<f32>,
271+
y: &CudaSlice<f32>,
239272
dtype: GgmlDType,
240273
ncols: usize,
241274
nrows: usize,
@@ -306,7 +339,7 @@ fn mul_mat_vec_via_q8_1(
306339
#[allow(clippy::too_many_arguments)]
307340
fn mul_mat_via_q8_1(
308341
data: &PaddedCudaSlice,
309-
y: &CudaView<f32>,
342+
y: &CudaSlice<f32>,
310343
dtype: GgmlDType,
311344
x_rows: usize,
312345
x_cols: usize,
@@ -377,7 +410,7 @@ fn indexed_moe_forward_fused_q8_1_input(
377410
weight: &CudaView<u8>,
378411
w_shape: &crate::Shape, //[num_experts, n, k]
379412
w_dtype: GgmlDType,
380-
input: &CudaView<f32>,
413+
input: &CudaSlice<f32>,
381414
in_shape: &crate::Shape, //[batch, topk or 1, k]
382415
ids: &CudaView<u32>,
383416
idx_shape: &crate::Shape, //[batch, topk]
@@ -391,11 +424,19 @@ fn indexed_moe_forward_fused_q8_1_input(
391424
assert!(batch == idx_shape.dims()[0], "batch dim not match!");
392425

393426
//quant input into q8_1
427+
let total_rows = batch * input_dim1;
394428
let k_padded = pad(k, MATRIX_ROW_PADDING);
395-
let y_size_in_bytes =
396-
batch * input_dim1 * k_padded * GgmlDType::Q8_1.type_size() / GgmlDType::Q8_1.block_size();
429+
// Get Q8_1 metadata.
430+
let q8_1_block_size = GgmlDType::Q8_1.block_size();
431+
let q8_1_type_size = GgmlDType::Q8_1.type_size();
432+
433+
// Calculate the size of the output buffer in bytes.
434+
let num_blocks_per_row = k_padded / q8_1_block_size;
435+
let dst_row_size_bytes = num_blocks_per_row * q8_1_type_size;
436+
let y_size_in_bytes = total_rows * dst_row_size_bytes;
397437
let mut input_quant = unsafe { dev.alloc::<u8>(y_size_in_bytes)? };
398-
quantize_q8_1(input, &mut input_quant, k, batch * input_dim1, dev)?;
438+
439+
quantize_q8_1(&input, &mut input_quant, k, total_rows, dev)?;
399440

400441
// output buffer
401442
let outsize = batch * topk * n;
@@ -469,7 +510,7 @@ impl QCudaStorage {
469510
&self.data.inner.slice(0..),
470511
self_shape, //[num_experts, n, k]
471512
self.dtype(),
472-
&input_storage.slice(0..),
513+
&input_storage,
473514
input_l.shape(), //[batch, topk or 1, k]
474515
&ids_storage.slice(0..),
475516
ids_l.shape(), //[batch, topk]
@@ -711,8 +752,11 @@ impl QCudaStorage {
711752
) -> Result<(CudaStorage, crate::Shape)> {
712753
let (nrows, ncols) = self_shape.dims2()?;
713754
let rhs = rhs.as_cuda_slice::<f32>()?;
714-
let rhs = match rhs_l.contiguous_offsets() {
715-
Some((o1, o2)) => rhs.slice(o1..o2),
755+
match rhs_l.contiguous_offsets() {
756+
Some((o1, _)) => assert!(
757+
o1 == 0,
758+
"sliced input is not supported in quantized matmul!"
759+
),
716760
None => Err(crate::Error::RequiresContiguous { op: "dmmv" }.bt())?,
717761
};
718762
let (b_size, k) = match rhs_l.shape().dims() {
@@ -766,8 +810,11 @@ impl QCudaStorage {
766810
storage.matmul(&data_f32, (b, m, n, k), layout, &rhs_l)?
767811
} else {
768812
let storage = storage.as_cuda_slice::<f32>()?;
769-
let storage = match layout.contiguous_offsets() {
770-
Some((o1, o2)) => storage.slice(o1..o2),
813+
match layout.contiguous_offsets() {
814+
Some((o1, _)) => assert!(
815+
o1 == 0,
816+
"sliced input is not supported in quantized matmul!"
817+
),
771818
None => Err(crate::Error::RequiresContiguous {
772819
op: "quantized-matmul",
773820
}
@@ -826,7 +873,7 @@ mod test {
826873
let mut y_q8_1 = unsafe { dev.alloc::<u8>(y_size_in_bytes)? };
827874
let vs: Vec<f32> = (0..el).map(|v| v as f32).collect();
828875
let y = dev.memcpy_stod(&vs)?;
829-
quantize_q8_1(&y.slice(..), &mut y_q8_1, el, 1, &dev)?;
876+
quantize_q8_1(&y, &mut y_q8_1, el, 1, &dev)?;
830877
Ok(())
831878
}
832879

@@ -840,7 +887,7 @@ mod test {
840887
xs.quantize(&CudaStorage::wrap_cuda_slice(y.clone(), dev.clone()))?;
841888
let cuda_storage = mul_mat_vec_via_q8_1(
842889
&xs.data,
843-
&y.slice(..),
890+
&y,
844891
/* dtype */ GgmlDType::Q4_0,
845892
/* ncols */ ncols,
846893
/* nrows */ 1,
@@ -856,7 +903,7 @@ mod test {
856903

857904
let cuda_storage = dequantize_mul_mat_vec(
858905
&xs.data,
859-
&y.slice(..),
906+
&y,
860907
/* dtype */ GgmlDType::Q4_0,
861908
/* ncols */ ncols,
862909
/* nrows */ 1,
@@ -879,7 +926,7 @@ mod test {
879926
xs.quantize(&CudaStorage::wrap_cuda_slice(y.clone(), dev.clone()))?;
880927
let cuda_storage = mul_mat_via_q8_1(
881928
&xs.data,
882-
&y.slice(..),
929+
&y,
883930
/* dtype */ GgmlDType::Q4_0,
884931
/* x_rows */ 4,
885932
/* x_cols */ ncols,
@@ -920,7 +967,7 @@ mod test {
920967
xs.quantize(&CudaStorage::wrap_cuda_slice(y.clone(), dev.clone()))?;
921968
let cuda_storage = mul_mat_via_q8_1(
922969
&xs.data,
923-
&y.slice(..),
970+
&y,
924971
/* dtype */ GgmlDType::Q4_0,
925972
/* x_rows */ x_rows,
926973
/* x_cols */ ncols,

0 commit comments

Comments
 (0)