Skip to content

Commit 55192e7

Browse files
jeffdailyfacebook-github-bot
authored andcommitted
add kWarpSizeHost() for host-side launch configs (#6024)
Summary: X-link: facebookresearch/FBGEMM#2934 Host-side launch configurations compute block/grid dims from `kWarpSize`. On ROCm, `kWarpSize` is a device-pass constant: during the host compilation pass it is a placeholder 64 (so `__global__` kernel bodies parse), which is wrong for sizing host-side `dim3` / grid quotients on a multi-arch wheel that runs on a wave32 arch (e.g. gfx1100), where the launch would use 64 lanes per warp instead of 32. Add `kWarpSizeHost()` in `cuda_prelude.cuh`: - CUDA: constexpr function returning 32 (usable as a template argument). - ROCm: inline function returning `at::cuda::warp_size()`, a cached device-properties lookup of the active device's warp size. Switch host-side `dim3` / quotient sites in the non-cache, non-TBE-codegen kernels (sparse, jagged, permute, quantize, input_combine, layout_transform, embedding_inplace, bounds_check) to `kWarpSizeHost()`. Device code keeps `kWarpSize`, which is per-arch correct via the device pass. Cache-geometry and TBE codegen sites are converted in later PRs in this chain. Second in the chain splitting #5804 into reviewable pieces; stacked on #6014. Authored with assistance from Claude (Anthropic). Reviewed By: henrylhtsang Differential Revision: D112414352 Pulled By: q10
1 parent ba003b8 commit 55192e7

18 files changed

Lines changed: 99 additions & 66 deletions

fbgemm_gpu/codegen/utils/embedding_bounds_check_v1.cu

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,10 @@ void _bounds_check_indices_cuda_v1(
202202
: bounds_check_indices_kernel_v1<index_t, false>);
203203
FBGEMM_LAUNCH_DSA_KERNEL(
204204
bounds_check_kernel,
205-
div_round_up(max_B_ * T, kNumThreads / fbgemm_gpu::kWarpSize),
206-
dim3(fbgemm_gpu::kWarpSize, kNumThreads / fbgemm_gpu::kWarpSize),
205+
div_round_up(max_B_ * T, kNumThreads / fbgemm_gpu::kWarpSizeHost()),
206+
dim3(
207+
fbgemm_gpu::kWarpSizeHost(),
208+
kNumThreads / fbgemm_gpu::kWarpSizeHost()),
207209
0,
208210
at::cuda::getCurrentCUDAStream(),
209211
PTA_B(rows_per_table, int64_t, 1, 32),

fbgemm_gpu/codegen/utils/embedding_bounds_check_v2.cu

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ void _bounds_check_indices_cuda_v2(
240240

241241
constexpr size_t kNumThreads = 1024;
242242
auto grid_dim = fbgemm_gpu::utils::cuda::cap_grid_dim_x(
243-
cuda_calc_xblock_count(total_B, kNumThreads / fbgemm_gpu::kWarpSize),
243+
cuda_calc_xblock_count(
244+
total_B, kNumThreads / fbgemm_gpu::kWarpSizeHost()),
244245
kNumThreads,
245246
at::cuda::getCurrentCUDAStream(),
246247
fbgemm_gpu::utils::cuda::BlockCapPolicy::Always);
@@ -251,33 +252,34 @@ void _bounds_check_indices_cuda_v2(
251252
grid_dim = std::min<uint32_t>(grid_dim, PREFETCH_KERNEL_MAX_BLOCKS);
252253
}
253254

254-
#define INVOKE_BOUNDS_CHECK_INDICES(MODE) \
255-
if (bounds_check_mode == MODE) { \
256-
AT_DISPATCH_INDEX_TYPES( \
257-
indices.scalar_type(), "bounds_check_indices_cuda", [&] { \
258-
[[maybe_unused]] const auto func_name = \
259-
"bounds_check_indices_cuda_v2"; \
260-
const auto bounds_check_kernel = \
261-
(vbe ? bounds_check_indices_kernel_v2<index_t, true, MODE> \
262-
: bounds_check_indices_kernel_v2<index_t, false, MODE>); \
263-
FBGEMM_LAUNCH_DSA_KERNEL( \
264-
bounds_check_kernel, \
265-
grid_dim, \
266-
dim3( \
267-
fbgemm_gpu::kWarpSize, kNumThreads / fbgemm_gpu::kWarpSize), \
268-
0, \
269-
at::cuda::getCurrentCUDAStream(), \
270-
PTA_B(rows_per_table, int64_t, 1, 32), \
271-
PTA_B(indices, index_t, 1, 32), \
272-
PTA_B(offsets, index_t, 1, 32), \
273-
vbe ? B_offsets.value().data_ptr<int32_t>() : nullptr, \
274-
PTA_B(warning, int64_t, 1, 32), \
275-
FixedDivisor(B), \
276-
vbe ? b_t_map.value().data_ptr<int32_t>() : nullptr, \
277-
info_B_num_bits, \
278-
info_B_mask, \
279-
disable_offsets_adjustment); \
280-
}); \
255+
#define INVOKE_BOUNDS_CHECK_INDICES(MODE) \
256+
if (bounds_check_mode == MODE) { \
257+
AT_DISPATCH_INDEX_TYPES( \
258+
indices.scalar_type(), "bounds_check_indices_cuda", [&] { \
259+
[[maybe_unused]] const auto func_name = \
260+
"bounds_check_indices_cuda_v2"; \
261+
const auto bounds_check_kernel = \
262+
(vbe ? bounds_check_indices_kernel_v2<index_t, true, MODE> \
263+
: bounds_check_indices_kernel_v2<index_t, false, MODE>); \
264+
FBGEMM_LAUNCH_DSA_KERNEL( \
265+
bounds_check_kernel, \
266+
grid_dim, \
267+
dim3( \
268+
fbgemm_gpu::kWarpSizeHost(), \
269+
kNumThreads / fbgemm_gpu::kWarpSizeHost()), \
270+
0, \
271+
at::cuda::getCurrentCUDAStream(), \
272+
PTA_B(rows_per_table, int64_t, 1, 32), \
273+
PTA_B(indices, index_t, 1, 32), \
274+
PTA_B(offsets, index_t, 1, 32), \
275+
vbe ? B_offsets.value().data_ptr<int32_t>() : nullptr, \
276+
PTA_B(warning, int64_t, 1, 32), \
277+
FixedDivisor(B), \
278+
vbe ? b_t_map.value().data_ptr<int32_t>() : nullptr, \
279+
info_B_num_bits, \
280+
info_B_mask, \
281+
disable_offsets_adjustment); \
282+
}); \
281283
}
282284

283285
INVOKE_BOUNDS_CHECK_INDICES(BoundsCheckMode::FATAL)

fbgemm_gpu/include/fbgemm_gpu/utils/cuda_prelude.cuh

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,16 @@ namespace fbgemm_gpu {
6060

6161
#define DIV_ROUND_UP(a, b) (a + b - 1) / b
6262

63-
// Warp size
63+
// Warp size -- device-pass constant
6464
//
6565
// Device code: per-arch constexpr. __GFX9__ is defined by HIP-Clang during
6666
// device compilation for gfx9xx targets (warpSize 64); it is undefined for
6767
// warpSize 32 targets. HIP-Clang runs the device-code backend once per
6868
// --offload-arch, so the same source produces correct per-arch device code.
6969
//
70-
// Host code on ROCm: warpSize is only known at runtime. This 64 is a
71-
// stop-gap constexpr. Host-side launches that must size thread blocks for
72-
// the active device should call at::cuda::warp_size() directly.
70+
// Host code on ROCm: warpSize is only known at runtime. The 64 below is a
71+
// stop-gap so __global__ kernel bodies parse on the host pass; never rely
72+
// on it in host-side computation. Use kWarpSizeHost (below) instead.
7373
#if !defined(USE_ROCM)
7474
static constexpr int32_t kWarpSize = 32;
7575
#elif defined(__GFX9__)
@@ -80,6 +80,32 @@ static constexpr int32_t kWarpSize = 32;
8080
static constexpr int32_t kWarpSize = 64;
8181
#endif
8282

83+
// Host-side warp size
84+
//
85+
// Use this in host code anywhere kWarpSize would be wrong on a ROCm
86+
// multi-arch build (block-dim computations, grid sizing, etc.). It is:
87+
// * CUDA: a constexpr function returning 32. Usable as a template
88+
// argument and in static_assert.
89+
// * ROCm: an inline function returning at::cuda::warp_size() -- a runtime
90+
// query of the active device. NOT constexpr; do not use as a template
91+
// argument. Cheap (a cached device-properties array lookup).
92+
//
93+
// Always invoke with parentheses (kWarpSizeHost()) so the same call shape
94+
// works under both back-ends and inside namespace-qualified call sites.
95+
//
96+
// Do not use in __device__ code: on ROCm the at::cuda::warp_size() call
97+
// is not callable from device. Use kWarpSize there, which is per-arch
98+
// correct via the device pass.
99+
#if defined(USE_ROCM)
100+
inline int32_t kWarpSizeHost() {
101+
return at::cuda::warp_size();
102+
}
103+
#else
104+
inline constexpr int32_t kWarpSizeHost() {
105+
return 32;
106+
}
107+
#endif
108+
83109
// Max thread num in one thread block
84110
static constexpr int32_t kMaxThreads = 1024;
85111

fbgemm_gpu/src/embedding_inplace_ops/embedding_inplace_update.cu

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ void embedding_inplace_update_cuda(
240240
}
241241
TORCH_CHECK_EQ(N, update_table_idx.numel());
242242

243-
const int32_t warpsPerBlock = kMaxThreads / kWarpSize;
243+
const int32_t warpsPerBlock = kMaxThreads / kWarpSizeHost();
244244

245245
auto lxu_cache_weights_value = lxu_cache_weights.value_or(
246246
at::empty({0, 0}, dev_weights.options().dtype(at::kByte)));
@@ -261,7 +261,7 @@ void embedding_inplace_update_cuda(
261261
FBGEMM_LAUNCH_KERNEL(
262262
(embedding_inplace_update_kernel_1<index_t>),
263263
blocks, // number of blocks needed
264-
dim3(kWarpSize, warpsPerBlock), // shape of each block
264+
dim3(kWarpSizeHost(), warpsPerBlock), // shape of each block
265265
0,
266266
at::cuda::getCurrentCUDAStream(),
267267

@@ -316,7 +316,7 @@ void embedding_inplace_update_single_placement_cuda(
316316
}
317317
TORCH_CHECK_EQ(N, update_table_idx.numel());
318318

319-
const int32_t warpsPerBlock = kMaxThreads / kWarpSize;
319+
const int32_t warpsPerBlock = kMaxThreads / kWarpSizeHost();
320320

321321
auto lxu_cache_weights_value = lxu_cache_weights.value_or(
322322
at::empty({0, 0}, dev_weights.options().dtype(at::kByte)));
@@ -336,7 +336,7 @@ void embedding_inplace_update_single_placement_cuda(
336336
FBGEMM_LAUNCH_KERNEL(
337337
(embedding_inplace_update_kernel_2<index_t>),
338338
blocks, // number of blocks needed
339-
dim3(kWarpSize, warpsPerBlock), // shape of each block
339+
dim3(kWarpSizeHost(), warpsPerBlock), // shape of each block
340340
0,
341341
at::cuda::getCurrentCUDAStream(),
342342

fbgemm_gpu/src/input_combine_ops/input_combine.cu

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,9 @@ std::tuple<Tensor, Tensor, Tensor> tbe_input_combine_with_length_cuda(
149149
#else
150150
constexpr uint32_t VEC_WIDTH = 8;
151151
#endif
152-
constexpr uint32_t NUM_WARPS_PER_BLOCK = kMaxThreads / kWarpSize;
152+
const uint32_t NUM_WARPS_PER_BLOCK = kMaxThreads / kWarpSizeHost();
153153
const auto num_warps_per_list =
154-
div_round_up(max_list_size, kWarpSize * VEC_WIDTH);
154+
div_round_up(max_list_size, kWarpSizeHost() * VEC_WIDTH);
155155
const auto total_warp_work = num_warps_per_list * num_lists;
156156
// HIP enforces a hard limit of 2^32 total threads per launch.
157157
// tbe_input_combine_with_length_kernel grid-strides over warps, so capping
@@ -170,7 +170,7 @@ std::tuple<Tensor, Tensor, Tensor> tbe_input_combine_with_length_cuda(
170170
FBGEMM_LAUNCH_KERNEL(
171171
(tbe_input_combine_with_length_kernel<VEC_WIDTH, IS_LONG_NUM_BITS>),
172172
num_blocks,
173-
dim3(kWarpSize, NUM_WARPS_PER_BLOCK),
173+
dim3(kWarpSizeHost(), NUM_WARPS_PER_BLOCK),
174174
0,
175175
at::cuda::getCurrentCUDAStream(),
176176
combined_indices.data_ptr<int32_t>(),

fbgemm_gpu/src/jagged_tensor_ops/batched_dense_vec_jagged_2d_mul_backward.cu

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ std::tuple<Tensor, Tensor> batched_dense_vec_jagged_2d_mul_backward(
114114
"dense_vec_jagged_2d_bmm_backward_kernel_2",
115115
[&] {
116116
int block_dim_x = std::min(
117-
div_round_up(max_L, kWarpSize) * kWarpSize, kMaxThreads);
117+
div_round_up(max_L, kWarpSizeHost()) * kWarpSizeHost(), kMaxThreads);
118118
int block_dim_y = kMaxThreads / block_dim_x;
119119

120120
// HIP enforces a hard limit of 2^32 total threads per launch
@@ -141,7 +141,7 @@ std::tuple<Tensor, Tensor> batched_dense_vec_jagged_2d_mul_backward(
141141
PTA_B(v_grad, scalar_t, 2, 32));
142142

143143
block_dim_x = std::min(
144-
div_round_up(D, kWarpSize) * kWarpSize, kMaxThreads);
144+
div_round_up(D, kWarpSizeHost()) * kWarpSizeHost(), kMaxThreads);
145145
block_dim_y = kMaxThreads / block_dim_x;
146146

147147
// HIP 2^32 cap. outer_prod_jagged_2d_output grid-strides

fbgemm_gpu/src/jagged_tensor_ops/batched_dense_vec_jagged_2d_mul_forward.cu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ Tensor batched_dense_vec_jagged_2d_mul_forward(
7171

7272
if (B > 0 && D > 0) {
7373
const int block_dim_x =
74-
std::min(div_round_up(D, kWarpSize) * kWarpSize, kMaxThreads);
74+
std::min(div_round_up(D, kWarpSizeHost()) * kWarpSizeHost(), kMaxThreads);
7575
const int block_dim_y = kMaxThreads / block_dim_x;
7676

7777
// HIP enforces a hard limit of 2^32 total threads per launch (unlike CUDA,

fbgemm_gpu/src/jagged_tensor_ops/common.cuh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,10 @@ inline std::tuple<dim3, dim3, StackArray<int64_t>> check_shape_and_partition_(
222222
const int jagged_folded_size =
223223
dense_tensor.numel() / (outer_dense_size * inner_dense_size);
224224

225-
const int threads_x =
226-
inner_dense_size >= kWarpSize / 2 ? kWarpSize : inner_dense_size;
227-
const int threads_y = kMaxThreads / kWarpSize;
225+
const int threads_x = inner_dense_size >= kWarpSizeHost() / 2
226+
? kWarpSizeHost()
227+
: inner_dense_size;
228+
const int threads_y = kMaxThreads / kWarpSizeHost();
228229
const dim3 blocks(
229230
div_round_up(outer_dense_size * jagged_folded_size, threads_y));
230231

fbgemm_gpu/src/layout_transform_ops/layout_transform_ops.cu

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,12 @@ Tensor recat_embedding_grad_output_mixed_D_batch_cuda(
138138
const auto dim_sum = grad_output.size(1);
139139

140140
const dim3 threads(
141-
fbgemm_gpu::kWarpSize, fbgemm_gpu::kMaxThreads / fbgemm_gpu::kWarpSize);
141+
fbgemm_gpu::kWarpSizeHost(),
142+
fbgemm_gpu::kMaxThreads / fbgemm_gpu::kWarpSizeHost());
142143
const dim3 blocks(
143144
fbgemm_gpu::div_round_up(
144145
(B_local * dim_num),
145-
fbgemm_gpu::kMaxThreads / fbgemm_gpu::kWarpSize));
146+
fbgemm_gpu::kMaxThreads / fbgemm_gpu::kWarpSizeHost()));
146147

147148
FBGEMM_DISPATCH_FLOAT_AND_HALF(
148149
grad_output.scalar_type(), "recat_embedding_gradients", [&] {

fbgemm_gpu/src/permute_multi_embedding_ops/permute_multi_embedding_ops.cu

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,9 @@ std::vector<Tensor> permute_multi_embedding_function_gpu(
272272
// blocks. The grid z dimension is also used by batch_size in case it's
273273
// greater than 65535.
274274
const int32_t warp_per_block =
275-
fbgemm_gpu::kMaxThreads / fbgemm_gpu::kWarpSize;
275+
fbgemm_gpu::kMaxThreads / fbgemm_gpu::kWarpSizeHost();
276276
const int32_t max_grid_dim = 32768; // The CUDA maximum is 65535, not 1<<N.
277-
const dim3 block_dim(fbgemm_gpu::kWarpSize, warp_per_block);
277+
const dim3 block_dim(fbgemm_gpu::kWarpSizeHost(), warp_per_block);
278278
const dim3 grid_dim(
279279
fbgemm_gpu::div_round_up(permute_size, warp_per_block),
280280
std::min(static_cast<int32_t>(batch_size), max_grid_dim),

0 commit comments

Comments
 (0)