Skip to content

Commit ee2c35b

Browse files
[CK] Allow tensors larger than 2GB in grouped conv bwd weight (#3169)
* Take split_k into account when checking 2GB tensor limit. * Revert "Take split_k into account when checking 2GB tensor limit." This reverts commit adf35c9. * Optimize grouped conv bwd wei split_k off calc (cherry picked from commit 6f61dd5) * Update gridwise_gemm_xdl_cshuffle_conv_v3.hpp (cherry picked from commit b33877c) * Fix tensor descriptors and stride calculations * Don't miss half of the elements * Fix buffer size calculations * Disable hack if stride not divisible by k_batch * Clean up comments * Disallow hack in non-contiguous edge cases * Index -> Dim * Fix broken test * Refactor applicability checks into separate function * fix missed variable name * Fix variable name in info print * update V3 2GB check * No more regression, use templates instead * Code deduplication * Regression fix for cshuffle * arch-guarded atomic_add implementations for gfx11 * Similar for half(4|8)_t as well * Only use both offset hacks at the same time * Revert "arch-guarded atomic_add implementations for gfx11" This reverts commit 3883fe6. This reverts commit 5311ec6. * Reapply "arch-guarded atomic_add implementations for gfx11" This reverts commit 1972ade. * Only remove float4 atomic_add * Refactor to single flag * Consolidate template parameters * Consolidate flag in transformers --------- Co-authored-by: Bartlomiej Kocot <barkocot@amd.com>
1 parent bc497be commit ee2c35b

9 files changed

Lines changed: 1287 additions & 203 deletions

include/ck/tensor_operation/gpu/device/impl/device_grouped_conv_bwd_weight_two_stage_xdl_cshuffle.hpp

Lines changed: 135 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "ck/tensor_operation/gpu/device/impl/device_grouped_conv_utils.hpp"
2525
#include "ck/tensor_operation/gpu/device/impl/split_k_utils.hpp"
2626
#include "ck/tensor_operation/gpu/device/impl/split_k_arg.hpp"
27+
#include "ck/tensor_operation/gpu/device/impl/split_k_offset_utils.hpp"
2728
#include "ck/tensor_operation/gpu/element/element_wise_operation.hpp"
2829

2930
#include "ck/host_utility/device_prop.hpp"
@@ -60,13 +61,19 @@ __launch_bounds__(CK_MAX_THREAD_PER_BLOCK, MinimumOccupancy)
6061
[[maybe_unused]] const CGridDesc_MBlock_MPerBlock_NBlock_NPerBlock
6162
c_grid_desc_mblock_mperblock_nblock_nperblock,
6263
[[maybe_unused]] const ComputePtrOffsetOfBatch compute_ptr_offset_of_batch,
63-
[[maybe_unused]] const index_t num_k_per_block)
64+
[[maybe_unused]] const index_t num_k_per_block,
65+
const long_index_t split_k_stride_a,
66+
const long_index_t split_k_stride_b,
67+
bool split_k_offset_hack)
6468
{
6569
#if defined(__gfx9__) || defined(__gfx11__) || defined(__gfx12__)
6670
if constexpr(GridwiseGemm::template IsValidCompilationParameter<CGlobalMemoryDataOperation>())
6771
{
6872
const index_t g_idx = __builtin_amdgcn_readfirstlane(blockIdx.z * NumGroupsToMerge);
69-
const index_t k_idx = __builtin_amdgcn_readfirstlane(blockIdx.y * num_k_per_block);
73+
const index_t k_idx = __builtin_amdgcn_readfirstlane(blockIdx.y);
74+
75+
const long_index_t split_k_offset_a = split_k_offset_hack ? k_idx * split_k_stride_a : 0;
76+
const long_index_t split_k_offset_b = split_k_offset_hack ? k_idx * split_k_stride_b : 0;
7077

7178
const long_index_t a_batch_offset = amd_wave_read_first_lane(
7279
static_cast<long_index_t>(compute_ptr_offset_of_batch.GetAPtrOffset(g_idx)));
@@ -77,23 +84,29 @@ __launch_bounds__(CK_MAX_THREAD_PER_BLOCK, MinimumOccupancy)
7784

7885
__shared__ char p_shared[GridwiseGemm::GetSharedMemoryNumberOfByte()];
7986

80-
GridwiseGemm::template Run<AGridDesc_AK0_M_K1,
81-
BGridDesc_BK0_N_K1,
82-
CGridDesc_MBlock_MPerBlock_NBlock_NPerBlock,
83-
HasMainKBlockLoop,
84-
CGlobalMemoryDataOperation,
85-
TailNum>(karg.p_a_grid + a_batch_offset,
86-
karg.p_b_grid + b_batch_offset,
87-
karg.p_c_grid + e_batch_offset,
88-
p_shared,
89-
karg,
90-
a_grid_desc_ak0_m_ak1,
91-
b_grid_desc_bk0_n_bk1,
92-
c_grid_desc_mblock_mperblock_nblock_nperblock,
93-
k_idx);
87+
DispatchSplitKHack<GridwiseGemm,
88+
AGridDesc_AK0_M_K1,
89+
BGridDesc_BK0_N_K1,
90+
CGridDesc_MBlock_MPerBlock_NBlock_NPerBlock,
91+
HasMainKBlockLoop,
92+
CGlobalMemoryDataOperation,
93+
TailNum>(karg.p_a_grid + a_batch_offset + split_k_offset_a,
94+
karg.p_b_grid + b_batch_offset + split_k_offset_b,
95+
karg.p_c_grid + e_batch_offset,
96+
p_shared,
97+
karg,
98+
a_grid_desc_ak0_m_ak1,
99+
b_grid_desc_bk0_n_bk1,
100+
c_grid_desc_mblock_mperblock_nblock_nperblock,
101+
k_idx * num_k_per_block,
102+
gridDim.y,
103+
split_k_offset_hack);
94104
}
95105
#else
96106
ignore = karg;
107+
ignore = split_k_stride_a;
108+
ignore = split_k_stride_b;
109+
ignore = split_k_offset_hack;
97110
#endif // end of if (defined(__gfx9__))
98111
}
99112

@@ -118,14 +131,20 @@ __launch_bounds__(CK_MAX_THREAD_PER_BLOCK, MinimumOccupancy)
118131
[[maybe_unused]] const CGridDesc_MBlock_MPerBlock_NBlock_NPerBlock
119132
c_grid_desc_mblock_mperblock_nblock_nperblock,
120133
[[maybe_unused]] const ComputePtrOffsetOfBatch compute_ptr_offset_of_batch,
121-
[[maybe_unused]] const index_t num_k_per_block)
134+
[[maybe_unused]] const index_t num_k_per_block,
135+
const long_index_t split_k_stride_a,
136+
const long_index_t split_k_stride_b,
137+
bool split_k_offset_hack)
122138
{
123139
#if defined(__gfx9__) || defined(__gfx11__) || defined(__gfx12__)
124140
if constexpr(GridwiseGemm::template IsValidCompilationParameter<CGlobalMemoryDataOperation>())
125141
{
126142
// offset base pointer for each work-group
127143
const index_t g_idx = __builtin_amdgcn_readfirstlane(blockIdx.z * NumGroupsToMerge);
128-
const index_t k_idx = __builtin_amdgcn_readfirstlane(blockIdx.y * num_k_per_block);
144+
const index_t k_idx = __builtin_amdgcn_readfirstlane(blockIdx.y);
145+
146+
const long_index_t split_k_offset_a = split_k_offset_hack ? k_idx * split_k_stride_a : 0;
147+
const long_index_t split_k_offset_b = split_k_offset_hack ? k_idx * split_k_stride_b : 0;
129148

130149
const long_index_t a_batch_offset = amd_wave_read_first_lane(
131150
static_cast<long_index_t>(compute_ptr_offset_of_batch.GetAPtrOffset(g_idx)));
@@ -139,24 +158,30 @@ __launch_bounds__(CK_MAX_THREAD_PER_BLOCK, MinimumOccupancy)
139158
__shared__ char p_shared_0[GridwiseGemm::GetSharedMemoryNumberOfByte()];
140159
__shared__ char p_shared_1[GridwiseGemm::GetSharedMemoryNumberOfByte()];
141160

142-
GridwiseGemm::template Run_2Lds<AGridDesc_AK0_M_K1,
143-
BGridDesc_BK0_N_K1,
144-
CGridDesc_MBlock_MPerBlock_NBlock_NPerBlock,
145-
HasMainKBlockLoop,
146-
CGlobalMemoryDataOperation,
147-
TailNum>(karg.p_a_grid + a_batch_offset,
148-
karg.p_b_grid + b_batch_offset,
149-
karg.p_c_grid + e_batch_offset,
150-
p_shared_0,
151-
p_shared_1,
152-
karg,
153-
a_grid_desc_ak0_m_ak1,
154-
b_grid_desc_bk0_n_bk1,
155-
c_grid_desc_mblock_mperblock_nblock_nperblock,
156-
k_idx);
161+
DispatchSplitKHack_2Lds<GridwiseGemm,
162+
AGridDesc_AK0_M_K1,
163+
BGridDesc_BK0_N_K1,
164+
CGridDesc_MBlock_MPerBlock_NBlock_NPerBlock,
165+
HasMainKBlockLoop,
166+
CGlobalMemoryDataOperation,
167+
TailNum>(karg.p_a_grid + a_batch_offset + split_k_offset_a,
168+
karg.p_b_grid + b_batch_offset + split_k_offset_b,
169+
karg.p_c_grid + e_batch_offset,
170+
p_shared_0,
171+
p_shared_1,
172+
karg,
173+
a_grid_desc_ak0_m_ak1,
174+
b_grid_desc_bk0_n_bk1,
175+
c_grid_desc_mblock_mperblock_nblock_nperblock,
176+
k_idx * num_k_per_block,
177+
gridDim.y,
178+
split_k_offset_hack);
157179
}
158180
#else
159181
ignore = karg;
182+
ignore = split_k_offset_hack;
183+
ignore = split_k_stride_a;
184+
ignore = split_k_stride_b;
160185
#endif // end of if (defined(__gfx9__))
161186
}
162187

@@ -693,7 +718,8 @@ struct DeviceGroupedConvBwdWeightTwoStage_Xdl_CShuffle
693718
k_batch_ = split_k;
694719
}
695720

696-
const auto descs =
721+
// Create initial descriptors with hack=false to check compactness
722+
const auto descs_initial =
697723
conv_to_gemm_transformer_v2
698724
.template MakeABCGridDescriptor_A_K0_M_K1_B_K0_N_K1_C_M_N<NDimSpatial>(
699725
Conv_N_,
@@ -709,11 +735,9 @@ struct DeviceGroupedConvBwdWeightTwoStage_Xdl_CShuffle
709735
conv_filter_dilations,
710736
input_left_pads,
711737
input_right_pads,
712-
k_batch_);
713-
714-
a_grid_desc_k0_m_k1_ = descs[I0];
715-
b_grid_desc_k0_n_k1_ = descs[I1];
716-
ce_grid_desc_m_n_ = descs[I2];
738+
k_batch_,
739+
false, // hack=false for initial check
740+
true); // use_full_batch_kindex
717741

718742
ce_elementwise_grid_desc_m_n_ =
719743
conv_to_gemm_transformer_v1
@@ -733,6 +757,67 @@ struct DeviceGroupedConvBwdWeightTwoStage_Xdl_CShuffle
733757
input_right_pads,
734758
k_batch_)[I2];
735759

760+
split_k_offset_hack_ =
761+
SplitKHackEligibility<NDimSpatial, InLayout, WeiLayout, OutLayout>::Check(
762+
descs_initial[I0],
763+
descs_initial[I1],
764+
k_batch_,
765+
Conv_N_,
766+
output_spatial_lengths_,
767+
KPerBlock);
768+
769+
// Create final descriptors with correct hack flag
770+
const auto descs =
771+
conv_to_gemm_transformer_v2
772+
.template MakeABCGridDescriptor_A_K0_M_K1_B_K0_N_K1_C_M_N<NDimSpatial>(
773+
Conv_N_,
774+
Conv_K_,
775+
Conv_C_,
776+
input_spatial_lengths_,
777+
filter_spatial_lengths_,
778+
output_spatial_lengths_,
779+
b_g_n_c_wis_strides_transposed,
780+
e_g_k_c_xs_strides_transposed,
781+
a_g_n_k_wos_strides_transposed,
782+
conv_filter_strides,
783+
conv_filter_dilations,
784+
input_left_pads,
785+
input_right_pads,
786+
k_batch_,
787+
split_k_offset_hack_, // Use determined hack flag
788+
true); // use_full_batch_kindex
789+
790+
a_grid_desc_k0_m_k1_ = descs[I0];
791+
b_grid_desc_k0_n_k1_ = descs[I1];
792+
ce_grid_desc_m_n_ = descs[I2];
793+
794+
// Step 5: Calculate stride using CalculateOffset on FINAL descriptors
795+
if(split_k_offset_hack_)
796+
{
797+
const index_t k0_per_batch = a_grid_desc_k0_m_k1_.GetLength(I0) / k_batch_;
798+
const auto idx_start = make_multi_index(0, 0, 0);
799+
const auto idx_next = make_multi_index(k0_per_batch, 0, 0);
800+
split_k_stride_a_ = a_grid_desc_k0_m_k1_.CalculateOffset(idx_next) -
801+
a_grid_desc_k0_m_k1_.CalculateOffset(idx_start);
802+
}
803+
else
804+
{
805+
split_k_stride_a_ = a_grid_desc_k0_m_k1_.GetElementSpaceSize();
806+
}
807+
808+
if(split_k_offset_hack_)
809+
{
810+
const index_t k0_per_batch = b_grid_desc_k0_n_k1_.GetLength(I0) / k_batch_;
811+
const auto idx_start = make_multi_index(0, 0, 0);
812+
const auto idx_next = make_multi_index(k0_per_batch, 0, 0);
813+
split_k_stride_b_ = b_grid_desc_k0_n_k1_.CalculateOffset(idx_next) -
814+
b_grid_desc_k0_n_k1_.CalculateOffset(idx_start);
815+
}
816+
else
817+
{
818+
split_k_stride_b_ = b_grid_desc_k0_n_k1_.GetElementSpaceSize();
819+
}
820+
736821
const index_t GemmM = a_grid_desc_k0_m_k1_.GetLength(I1);
737822
const index_t GemmN = b_grid_desc_k0_n_k1_.GetLength(I1);
738823

@@ -869,6 +954,9 @@ struct DeviceGroupedConvBwdWeightTwoStage_Xdl_CShuffle
869954
const std::array<ck::index_t, NDimSpatial>& input_left_pads_;
870955
const std::array<ck::index_t, NDimSpatial>& input_right_pads_;
871956
long_index_t c_space_size_bytes;
957+
958+
bool split_k_offset_hack_;
959+
long_index_t split_k_stride_a_, split_k_stride_b_;
872960
};
873961

874962
// Invoker
@@ -971,7 +1059,10 @@ struct DeviceGroupedConvBwdWeightTwoStage_Xdl_CShuffle
9711059
arg.b_grid_desc_k0_n_k1_,
9721060
arg.c_grid_desc_mblock_mperblock_nblock_nperblock_,
9731061
arg.compute_ptr_offset_of_batch_,
974-
num_k_per_block);
1062+
num_k_per_block,
1063+
arg.split_k_stride_a_,
1064+
arg.split_k_stride_b_,
1065+
arg.split_k_offset_hack_);
9751066
}
9761067
else
9771068
{
@@ -987,7 +1078,10 @@ struct DeviceGroupedConvBwdWeightTwoStage_Xdl_CShuffle
9871078
arg.b_grid_desc_k0_n_k1_,
9881079
arg.c_grid_desc_mblock_mperblock_nblock_nperblock_,
9891080
arg.compute_ptr_offset_of_batch_,
990-
num_k_per_block);
1081+
num_k_per_block,
1082+
arg.split_k_stride_a_,
1083+
arg.split_k_stride_b_,
1084+
arg.split_k_offset_hack_);
9911085
}
9921086
};
9931087

@@ -1920,14 +2014,6 @@ struct DeviceGroupedConvBwdWeightTwoStage_Xdl_CShuffle
19202014
}
19212015
}
19222016

1923-
constexpr long_index_t TwoGB = (long_index_t{1} << 31);
1924-
if(!(arg.a_grid_desc_k0_m_k1_.GetElementSpaceSize() * sizeof(ADataType) <= TwoGB &&
1925-
arg.b_grid_desc_k0_n_k1_.GetElementSpaceSize() * sizeof(BDataType) <= TwoGB &&
1926-
arg.ce_grid_desc_m_n_.GetElementSpaceSize() * sizeof(EDataType) <= TwoGB))
1927-
{
1928-
return false;
1929-
}
1930-
19312017
return true;
19322018
}
19332019

0 commit comments

Comments
 (0)