Skip to content

Commit fcf6670

Browse files
levendleefacebook-github-bot
authored andcommitted
Gather/Scatter. (pytorch#3743)
Summary: X-link: facebookresearch/FBGEMM#824 Minor improvements. Differential Revision: D70226730
1 parent 3d0e302 commit fcf6670

2 files changed

Lines changed: 57 additions & 26 deletions

File tree

fbgemm_gpu/experimental/gen_ai/src/gather_scatter/gather_scatter.cu

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,12 @@ __global__ static void gather_or_scatter_along_first_dim_kernel(
5454
int M = cute::get<0>(problem_shape);
5555
int N = cute::get<1>(problem_shape);
5656
int K = cute::get<2>(problem_shape);
57+
int L = cute::get<3>(problem_shape);
5758

5859
static_assert(cute::is_static<TileShape>::value);
5960
constexpr int kBlkNOrM = cute::size<0>(tile_shape);
6061
constexpr int kBlkK = cute::size<1>(tile_shape);
62+
constexpr int kBlkL = cute::size<2>(tile_shape);
6163

6264
using SmemT = SharedStorage<kBlkNOrM, DataType, IndexType, SmemLayout>;
6365
constexpr int kPipeMax = SmemT::kPipeMax;
@@ -79,15 +81,17 @@ __global__ static void gather_or_scatter_along_first_dim_kernel(
7981

8082
if (threadIdx.x == 0) {
8183
// Tensors on HBM.
82-
cute::Tensor gA = tma_load_input.get_tma_tensor(cute::make_shape(M, K));
83-
cute::Tensor gB = tma_store_output.get_tma_tensor(cute::make_shape(N, K));
84+
cute::Tensor gA = tma_load_input.get_tma_tensor(cute::make_shape(M, K, L));
85+
cute::Tensor gB =
86+
tma_store_output.get_tma_tensor(cute::make_shape(N, K, L));
8487
// Tensors on SMEM.
8588
cute::Tensor sA = cute::make_tensor(
8689
cute::make_smem_ptr(smem.data.data()), cute::group<0, 2>(SmemLayout{}));
8790

88-
constexpr int kTmaTransactionBytes = kBlkK * sizeof(DataType);
91+
constexpr int kTmaTransactionBytes = kBlkK * kBlkL * sizeof(DataType);
8992
const int kNumKTiles = ((K + kBlkK - 1) / kBlkK);
90-
const int kNumNOrMKTiles = kBlkNOrM * kNumKTiles;
93+
const int kNumNOrMKTiles =
94+
std::min(kBlkNOrM, indexing_dim - n_or_m_offset) * kNumKTiles;
9195
const int kNumIterations = kNumNOrMKTiles + kPipeMax - 1;
9296

9397
for (int iteration = 0; iteration < kNumIterations; ++iteration) {
@@ -110,12 +114,12 @@ __global__ static void gather_or_scatter_along_first_dim_kernel(
110114

111115
cute::Tensor tAgA = cute::local_tile(
112116
gA,
113-
cute::Tile<cute::_1, cute::Int<kBlkK>>{},
114-
cute::make_coord(m, k));
117+
cute::Tile<cute::_1, cute::Int<kBlkK>, cute::Int<kBlkL>>{},
118+
cute::make_coord(m, k, 0));
115119
cute::Tensor tAsA = cute::local_tile(
116120
sA,
117-
cute::Tile<cute::_1, cute::Int<kBlkK>>{},
118-
cute::make_coord(load_pipe, 0));
121+
cute::Tile<cute::_1, cute::Int<kBlkK>, cute::Int<kBlkL>>{},
122+
cute::make_coord(load_pipe, 0, 0));
119123

120124
auto& tma_load_mbar = smem.tma_load_barrier[load_pipe];
121125
cute::initialize_barrier(smem.tma_load_barrier[load_pipe], 1);
@@ -149,12 +153,12 @@ __global__ static void gather_or_scatter_along_first_dim_kernel(
149153

150154
cute::Tensor tAgB = cute::local_tile(
151155
gB,
152-
cute::Tile<cute::_1, cute::Int<kBlkK>>{},
153-
cute::make_coord(n, k));
156+
cute::Tile<cute::_1, cute::Int<kBlkK>, cute::Int<kBlkL>>{},
157+
cute::make_coord(n, k, 0));
154158
cute::Tensor tAsA = cute::local_tile(
155159
sA,
156-
cute::Tile<cute::_1, cute::Int<kBlkK>>{},
157-
cute::make_coord(store_pipe, 0));
160+
cute::Tile<cute::_1, cute::Int<kBlkK>, cute::Int<kBlkL>>{},
161+
cute::make_coord(store_pipe, 0, 0));
158162

159163
auto tma_store_per_cta = tma_store_output.get_slice(0);
160164
cute::copy(
@@ -205,36 +209,51 @@ void gather_or_scatter_along_first_dim(
205209
assert(dst.dtype() == TorchDTypeTrait<DataType>::dtype());
206210
assert(index.dtype() == TorchDTypeTrait<IndexType>::dtype());
207211

212+
constexpr int L = 256;
208213
const int M = src.size(0);
209-
const int K = src.size(1);
210214
const int N = dst.size(0);
215+
const int K = src.size(1) / L;
211216

212-
auto src_gmem_layout =
213-
cute::make_layout(cute::make_shape(M, K), cute::make_stride(K, 1));
217+
auto src_gmem_layout = cute::make_layout(
218+
cute::make_shape(M, K, L), cute::make_stride(K * L, L, 1));
214219
auto src_gmem_tensor = cute::make_tensor(
215220
cute::make_gmem_ptr(reinterpret_cast<DataType*>(src.data_ptr())),
216221
src_gmem_layout);
217222

218-
auto dst_gmem_layout =
219-
cute::make_layout(cute::make_shape(N, K), cute::make_stride(K, 1));
223+
auto dst_gmem_layout = cute::make_layout(
224+
cute::make_shape(N, K, L), cute::make_stride(K * L, L, 1));
220225
auto dst_gmem_tensor = cute::make_tensor(
221226
cute::make_gmem_ptr(reinterpret_cast<DataType*>(dst.data_ptr())),
222227
dst_gmem_layout);
223228

224229
constexpr int kBlkNOrM = 1;
225-
constexpr int kBlkK = 256;
226-
constexpr int kPipeMax = 4;
230+
constexpr int kBlkK = 4;
231+
constexpr int kBlkL = L;
232+
constexpr int kPipeMax = 3;
227233

228234
auto smem_layout = cute::make_layout(
229-
cute::make_shape(cute::Int<kPipeMax>{}, cute::_1{}, cute::Int<kBlkK>{}),
230-
cute::make_stride(cute::Int<kBlkK>{}, cute::Int<kBlkK>{}, cute::_1{}));
235+
cute::make_shape(
236+
cute::Int<kPipeMax>{},
237+
cute::_1{},
238+
cute::Int<kBlkK>{},
239+
cute::Int<kBlkL>{}),
240+
cute::make_stride(
241+
cute::Int<kBlkK * kBlkL>{},
242+
cute::Int<kBlkK * kBlkL>{},
243+
cute::Int<kBlkL>{},
244+
cute::_1{}));
231245
auto tma_load = cute::make_tma_copy(
232-
cute::SM90_TMA_LOAD{}, src_gmem_tensor, smem_layout(0, cute::_, cute::_));
246+
cute::SM90_TMA_LOAD{},
247+
src_gmem_tensor,
248+
smem_layout(0, cute::_, cute::_, cute::_));
233249
auto tma_store = cute::make_tma_copy(
234-
TMAStoreInst{}, dst_gmem_tensor, smem_layout(0, cute::_, cute::_));
250+
TMAStoreInst{},
251+
dst_gmem_tensor,
252+
smem_layout(0, cute::_, cute::_, cute::_));
235253

236-
auto problem_shape = cute::make_shape(M, N, K);
237-
auto tile_shape = cute::make_shape(cute::Int<kBlkNOrM>{}, cute::Int<kBlkK>{});
254+
auto problem_shape = cute::make_shape(M, N, K, L);
255+
auto tile_shape = cute::make_shape(
256+
cute::Int<kBlkNOrM>{}, cute::Int<kBlkK>{}, cute::Int<kBlkL>{});
238257

239258
using SmemT =
240259
SharedStorage<kBlkNOrM, DataType, IndexType, decltype(smem_layout)>;

fbgemm_gpu/experimental/gen_ai/test/gather_scatter/gather_scatter_test.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ def ref_fn():
7878
_test_gather_along_first_dim(1024, 1024, 1024)
7979
_test_gather_along_first_dim(1024, 1024, 1024, compile=True)
8080

81+
_test_gather_along_first_dim(1, 1, 5120)
82+
_test_gather_along_first_dim(128, 128, 5120)
83+
_test_gather_along_first_dim(2048, 2048, 5120)
84+
_test_gather_along_first_dim(4096, 4096, 5120)
85+
_test_gather_along_first_dim(8192, 8192, 5120)
86+
8187
def test_scatter_add_along_first_dim(self) -> None:
8288
def _test_scatter_add_along_first_dim(
8389
M: int, N: int, K: int, compile: bool = False
@@ -101,7 +107,7 @@ def _test_scatter_add_along_first_dim(
101107
logger.info("Running PyTorch")
102108
ref_dst.scatter_add_(0, indices_2d, src)
103109

104-
torch.testing.assert_close(test_dst, ref_dst, atol=1e-3, rtol=2e-2)
110+
torch.testing.assert_close(test_dst, ref_dst, atol=1e-3, rtol=2.1e-2)
105111

106112
def fn():
107113
op = torch.ops.fbgemm.scatter_add_along_first_dim
@@ -137,6 +143,12 @@ def ref_fn():
137143
_test_scatter_add_along_first_dim(1024, 1024, 1024)
138144
_test_scatter_add_along_first_dim(1024, 1024, 1024, compile=True)
139145

146+
_test_scatter_add_along_first_dim(1, 1, 5120)
147+
_test_scatter_add_along_first_dim(128, 128, 5120)
148+
_test_scatter_add_along_first_dim(2048, 2048, 5120)
149+
_test_scatter_add_along_first_dim(4096, 4096, 5120)
150+
_test_scatter_add_along_first_dim(8192, 8192, 5120)
151+
140152

141153
if __name__ == "__main__":
142154
unittest.main()

0 commit comments

Comments
 (0)