Skip to content

Commit 5ae6ec8

Browse files
q10facebook-github-bot
authored andcommitted
Add grid-stride + ROCm cap to padded_fp8_rowwise quantize kernels
Summary: Guard the padded-FP8 rowwise quantize kernels against the HIP 2^32 threads-per-launch limit on ROCm (OverflowOnly cap; no-op on CUDA): - _float_to_paddedFP8rowwise_cuda_kernel (flat, 1-D and 2-D branches): cap the launch grid; add a grid-stride over rows/buckets with a unified bound (num_items = nrows == 1 ? num_buckets : nrows); the branch early-returns become `continue`. - _get_padding_value_kernel (flat): cap the launch grid; add a grid-stride. - _PaddedFP8rowwise_to_float_2d_cuda_kernel (flat): cap the launch grid; add a grid-stride over rows. Added the cuda_utilities.cuh include. NOTE: _PaddedFP8rowwise_to_float_1d_cuda_kernel is one CUDA block per bucket (row = blockIdx.x, grid.x == num_buckets), so capping it safely needs a num_buckets parameter; left unchanged for now (1-D dequant path, block-per-row; total threads = num_buckets * min(1024, row_dim), negligible 2^32 risk). Reviewed By: henrylhtsang Differential Revision: D113375952
1 parent 7a53560 commit 5ae6ec8

1 file changed

Lines changed: 129 additions & 74 deletions

File tree

fbgemm_gpu/src/quantize_ops/quantize_padded_fp8_rowwise.cu

Lines changed: 129 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
#include "common.cuh"
10+
#include "fbgemm_gpu/utils/cuda_utilities.cuh"
1011

1112
using Tensor = at::Tensor;
1213

@@ -35,78 +36,115 @@ __global__ inline void _float_to_paddedFP8rowwise_cuda_kernel(
3536
const int output_columns =
3637
ncols_aligned + (ncols + row_dim - 1) / row_dim * 8;
3738

39+
// On ROCm the launch caps the grid (HIP 2^32 threads-per-launch limit); grid-
40+
// stride over rows/buckets. On CUDA the grid is not capped and the loop runs
41+
// exactly once.
42+
const int64_t num_items =
43+
(nrows == 1) ? ((ncols + row_dim - 1) / row_dim) : nrows;
44+
#ifdef USE_ROCM
45+
for (int64_t row =
46+
static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
47+
row < num_items;
48+
row += static_cast<int64_t>(gridDim.x) * blockDim.x) {
49+
#else
3850
const int64_t row =
3951
static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
40-
// for 1D case, unsqueezing needed
41-
if (nrows == 1) {
42-
const auto threads = (ncols + row_dim - 1) / row_dim;
43-
if (row >= threads) {
52+
#endif
53+
// for 1D case, unsqueezing needed
54+
if (nrows == 1) {
55+
const auto threads = (ncols + row_dim - 1) / row_dim;
56+
if (row >= threads) {
57+
#ifdef USE_ROCM
58+
continue;
59+
#else
4460
return;
45-
}
46-
const input_t* const input_row = input + row * row_dim;
47-
std::uint8_t* output_row = output + row * row_ext;
48-
int last_buc_idx = row - (threads - 1);
49-
float* output_row_scale = reinterpret_cast<float*>(output_row + row_dim);
50-
const auto range = (row == threads - 1) ? row_dim - pad : row_dim;
51-
float minimum_element = fbgemm_gpu::min(input_row, input_row + range);
52-
float maximum_element = fbgemm_gpu::max(input_row, input_row + range);
53-
auto scale =
54-
max_pos / (kEpsilon + fmaxf(maximum_element, -minimum_element));
55-
output_row_scale[0] = scale;
56-
// if no padding, the pad value is negative to indicate where the next
57-
// non-zero pad value is for output size counting in host
58-
output_row_scale[1] =
59-
*reinterpret_cast<float*>((row == threads - 1) ? &pad : &last_buc_idx);
60-
for (int col = 0; col < range; col += 1) {
61-
output_row[col] =
62-
float_to_hfp8(to_float(input_row[col]) * scale, ebit, bias, max_pos);
63-
}
61+
#endif
62+
}
63+
const input_t* const input_row = input + row * row_dim;
64+
std::uint8_t* output_row = output + row * row_ext;
65+
int last_buc_idx = row - (threads - 1);
66+
float* output_row_scale = reinterpret_cast<float*>(output_row + row_dim);
67+
const auto range = (row == threads - 1) ? row_dim - pad : row_dim;
68+
float minimum_element = fbgemm_gpu::min(input_row, input_row + range);
69+
float maximum_element = fbgemm_gpu::max(input_row, input_row + range);
70+
auto scale =
71+
max_pos / (kEpsilon + fmaxf(maximum_element, -minimum_element));
72+
output_row_scale[0] = scale;
73+
// if no padding, the pad value is negative to indicate where the next
74+
// non-zero pad value is for output size counting in host
75+
output_row_scale[1] = *reinterpret_cast<float*>(
76+
(row == threads - 1) ? &pad : &last_buc_idx);
77+
for (int col = 0; col < range; col += 1) {
78+
output_row[col] = float_to_hfp8(
79+
to_float(input_row[col]) * scale, ebit, bias, max_pos);
80+
}
81+
#ifdef USE_ROCM
82+
continue;
83+
#else
6484
return;
65-
}
66-
// for 2D case
85+
#endif
86+
}
87+
// for 2D case
6788

68-
if (row >= nrows) {
89+
if (row >= nrows) {
90+
#ifdef USE_ROCM
91+
continue;
92+
#else
6993
return;
70-
}
71-
const input_t* input_row = input + row * ncols;
72-
std::uint8_t* output_row = output + row * output_columns;
73-
for (int col = 0; col < ncols; col += row_dim) {
74-
int col_offset = col / row_dim * 8;
75-
int last_buc_idx = (ncols - col) / row_dim * -1;
76-
float* output_row_scale =
77-
reinterpret_cast<float*>(output_row + col + col_offset + row_dim);
78-
int buc_end = (row_dim < ncols - col) ? row_dim : ncols - col;
79-
float minimum_element =
80-
fbgemm_gpu::min(input_row + col, input_row + buc_end + col);
81-
float maximum_element =
82-
fbgemm_gpu::max(input_row + col, input_row + buc_end + col);
83-
auto scale =
84-
max_pos / (kEpsilon + fmaxf(maximum_element, -minimum_element));
85-
output_row_scale[0] = scale;
86-
output_row_scale[1] = *reinterpret_cast<float*>(
87-
(ncols - col > row_dim) ? &last_buc_idx : &pad);
88-
for (int bi = 0; bi < std::min(row_dim, (int)(ncols - col)); ++bi) {
89-
output_row[col + bi + col_offset] = float_to_hfp8(
90-
to_float(input_row[col + bi]) * scale, ebit, bias, max_pos);
94+
#endif
9195
}
92-
}
96+
const input_t* input_row = input + row * ncols;
97+
std::uint8_t* output_row = output + row * output_columns;
98+
for (int col = 0; col < ncols; col += row_dim) {
99+
int col_offset = col / row_dim * 8;
100+
int last_buc_idx = (ncols - col) / row_dim * -1;
101+
float* output_row_scale =
102+
reinterpret_cast<float*>(output_row + col + col_offset + row_dim);
103+
int buc_end = (row_dim < ncols - col) ? row_dim : ncols - col;
104+
float minimum_element =
105+
fbgemm_gpu::min(input_row + col, input_row + buc_end + col);
106+
float maximum_element =
107+
fbgemm_gpu::max(input_row + col, input_row + buc_end + col);
108+
auto scale =
109+
max_pos / (kEpsilon + fmaxf(maximum_element, -minimum_element));
110+
output_row_scale[0] = scale;
111+
output_row_scale[1] = *reinterpret_cast<float*>(
112+
(ncols - col > row_dim) ? &last_buc_idx : &pad);
113+
for (int bi = 0; bi < std::min(row_dim, (int)(ncols - col)); ++bi) {
114+
output_row[col + bi + col_offset] = float_to_hfp8(
115+
to_float(input_row[col + bi]) * scale, ebit, bias, max_pos);
116+
}
117+
}
118+
#ifdef USE_ROCM
119+
} // for row (grid-stride loop, ROCm only)
120+
#endif
93121
}
94122

95123
__global__ inline void _get_padding_value_kernel(
96124
const int ncols,
97125
const int row_dim,
98126
const std::uint8_t* const __restrict__ input,
99127
int* const __restrict__ offsets) {
100-
const int64_t row =
101-
static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
102128
const int row_ext = row_dim + 8;
103129
const auto threads = (ncols + row_ext - 1) / row_ext;
130+
#ifdef USE_ROCM
131+
for (int64_t row =
132+
static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
133+
row < threads;
134+
row += static_cast<int64_t>(gridDim.x) * blockDim.x) {
135+
#else
136+
const int64_t row =
137+
static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
104138
if (row >= threads)
105139
return;
106-
const std::uint8_t* const input_row = input + row * row_ext;
107-
int pad = *reinterpret_cast<const int*>(input_row + row_dim + 4);
108-
pad = (pad > 0) ? pad : 0;
109-
offsets[row] = pad;
140+
#endif
141+
const std::uint8_t* const input_row = input + row * row_ext;
142+
int pad = *reinterpret_cast<const int*>(input_row + row_dim + 4);
143+
pad = (pad > 0) ? pad : 0;
144+
offsets[row] = pad;
145+
#ifdef USE_ROCM
146+
} // for row (grid-stride loop, ROCm only)
147+
#endif
110148
}
111149

112150
__global__ inline void _single_thread_sum_padding_kernel(
@@ -183,28 +221,38 @@ __global__ inline void _PaddedFP8rowwise_to_float_2d_cuda_kernel(
183221
const int ebit = forward ? 4 : 5;
184222
const int bias = forward ? 15 : 31;
185223

224+
#ifdef USE_ROCM
225+
for (int64_t row =
226+
static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
227+
row < nrows;
228+
row += static_cast<int64_t>(gridDim.x) * blockDim.x) {
229+
#else
186230
const int64_t row =
187231
static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
188232
if (row >= nrows) {
189233
return;
190234
}
191-
const std::uint8_t* const input_row = input + row * ncols;
192-
output_t* output_row = output + row * output_columns;
193-
int col_offset = 0;
194-
for (int col = 0; col < ncols; col = col + row_ext) {
195-
const float* input_row_scale =
196-
reinterpret_cast<const float*>(input_row + col + row_ext - 8);
197-
int pad = *reinterpret_cast<const int*>(&input_row_scale[1]);
198-
// if pad is negative it's used to indidate indices of the next padded
199-
// bucket
200-
pad = ::max(0, ::min(pad, row_dim));
201-
for (int bi = 0; bi < row_dim - pad; ++bi) {
202-
const auto output_ =
203-
hfp8_to_float(input_row[col + bi], ebit, bias) / input_row_scale[0];
204-
quantize_float_store(&output_row[col + bi - col_offset], output_);
235+
#endif
236+
const std::uint8_t* const input_row = input + row * ncols;
237+
output_t* output_row = output + row * output_columns;
238+
int col_offset = 0;
239+
for (int col = 0; col < ncols; col = col + row_ext) {
240+
const float* input_row_scale =
241+
reinterpret_cast<const float*>(input_row + col + row_ext - 8);
242+
int pad = *reinterpret_cast<const int*>(&input_row_scale[1]);
243+
// if pad is negative it's used to indidate indices of the next padded
244+
// bucket
245+
pad = ::max(0, ::min(pad, row_dim));
246+
for (int bi = 0; bi < row_dim - pad; ++bi) {
247+
const auto output_ =
248+
hfp8_to_float(input_row[col + bi], ebit, bias) / input_row_scale[0];
249+
quantize_float_store(&output_row[col + bi - col_offset], output_);
250+
}
251+
col_offset = col_offset + 8 + pad;
205252
}
206-
col_offset = col_offset + 8 + pad;
207-
}
253+
#ifdef USE_ROCM
254+
} // for row (grid-stride loop, ROCm only)
255+
#endif
208256
}
209257

210258
} // namespace
@@ -247,8 +295,12 @@ Tensor _float_to_paddedFP8rowwise_gpu_t(
247295
}
248296

249297
constexpr int threads_per_block = 256;
250-
const auto num_blocks = cuda_calc_xblock_count(
251-
nrows == 1 ? (ncols + row_dim - 1) / row_dim : nrows, threads_per_block);
298+
const auto num_blocks = utils::cuda::cap_grid_dim_x(
299+
cuda_calc_xblock_count(
300+
nrows == 1 ? (ncols + row_dim - 1) / row_dim : nrows,
301+
threads_per_block),
302+
threads_per_block,
303+
at::cuda::getCurrentCUDAStream());
252304

253305
FBGEMM_DISPATCH_FLOATING_TYPES(
254306
input.scalar_type(), "_float_to_FP8rowwise_cuda_kernel", [&] {
@@ -306,8 +358,11 @@ Tensor _paddedFP8rowwise_to_float_gpu_t(
306358
auto output_dims = input_sizes.vec();
307359

308360
constexpr int threads_per_block = 256;
309-
const auto num_blocks = cuda_calc_xblock_count(
310-
(nrows == 1) ? num_buckets : nrows, threads_per_block);
361+
const auto num_blocks = utils::cuda::cap_grid_dim_x(
362+
cuda_calc_xblock_count(
363+
(nrows == 1) ? num_buckets : nrows, threads_per_block),
364+
threads_per_block,
365+
at::cuda::getCurrentCUDAStream());
311366
Tensor offsets = at::empty(
312367
(nrows == 1) ? num_buckets : 0, input.options().dtype(at::kInt));
313368
int total_pad = 0;

0 commit comments

Comments
 (0)