try to use merge transform for converting 3d to 2d

This commit is contained in:
root
2025-05-14 14:10:43 +00:00
parent f2b4d315e4
commit 727df8fe11
2 changed files with 175 additions and 67 deletions

View File

@@ -6,13 +6,13 @@
auto create_args(int argc, char* argv[])
{
ck_tile::ArgParser arg_parser;
arg_parser.insert("b", "4", "b dimension")
.insert("m", "10240", "m dimension")
.insert("n", "4096", "n dimension")
arg_parser.insert("b", "16", "b dimension")
.insert("m", "8192", "m dimension")
.insert("n", "8192", "n dimension")
.insert("v", "1", "cpu validation or not")
.insert("prec", "fp16", "precision")
.insert("warmup", "200", "cold iter")
.insert("repeat", "1000", "hot iter");
.insert("warmup", "1", "cold iter")
.insert("repeat", "2", "hot iter");
bool result = arg_parser.parse(argc, argv);
return std::make_tuple(result, arg_parser);
@@ -81,6 +81,20 @@ bool run(const ck_tile::ArgParser& arg_parser)
b,
m,
n));
// using Kernel = ck_tile::AddTemplate<Porblem, 4, 4096, 4096>;
// float ave_time = launch_kernel(ck_tile::stream_config{nullptr, true, 0, warmup, repeat},
// ck_tile::make_kernel<kBlockSize, kBlockPerCu>(
// Kernel{},
// kGridSize,
// kBlockSize,
// 0,
// static_cast<XDataType*>(x_buf_a.GetDeviceBuffer()),
// static_cast<XDataType*>(x_buf_b.GetDeviceBuffer()),
// static_cast<YDataType*>(y_buf.GetDeviceBuffer())
// ));
std::size_t num_btype = 2 * sizeof(XDataType) * b * m * n + sizeof(YDataType) * b * m * n;

View File

@@ -85,6 +85,126 @@ struct AddDefaultPolicy
}
};
// Templated implementation with compile-time dimensions
template <typename Problem_, index_t B_val, index_t M_val, index_t N_val, typename Policy_ = AddDefaultPolicy>
struct AddTemplate
{
using Problem = ck_tile::remove_cvref_t<Problem_>;
using Policy = ck_tile::remove_cvref_t<Policy_>;
using XDataType = ck_tile::remove_cvref_t<typename Problem::XDataType>;
using ComputeDataType = ck_tile::remove_cvref_t<typename Problem::ComputeDataType>;
using YDataType = ck_tile::remove_cvref_t<typename Problem::YDataType>;
CK_TILE_DEVICE void operator()(
const XDataType* p_x_a, const XDataType* p_x_b, YDataType* p_y) const
{
using S = typename Problem::BlockShape;
// Create 3D tensor views with compile-time dimensions
const auto x_b_m_n_a = make_naive_tensor_view<address_space_enum::global,
memory_operation_enum::set,
amd_buffer_coherence_enum::slc>(
p_x_a,
make_tuple(number<B_val>{}, number<M_val>{}, number<N_val>{}),
make_tuple(number<M_val * N_val>{}, number<N_val>{}, number<1>{}),
number<S::Vector_N>{},
number<1>{});
const auto x_b_m_n_b = make_naive_tensor_view<address_space_enum::global,
memory_operation_enum::set,
amd_buffer_coherence_enum::slc>(
p_x_b,
make_tuple(number<B_val>{}, number<M_val>{}, number<N_val>{}),
make_tuple(number<M_val * N_val>{}, number<N_val>{}, number<1>{}),
number<S::Vector_N>{},
number<1>{});
const auto y_b_m_n = make_naive_tensor_view<address_space_enum::global,
memory_operation_enum::set,
amd_buffer_coherence_enum::slc>(
p_y,
make_tuple(number<B_val>{}, number<M_val>{}, number<N_val>{}),
make_tuple(number<M_val * N_val>{}, number<N_val>{}, number<1>{}),
number<S::Vector_N>{},
number<1>{});
// Now can use make_merge_transform with compile-time constants
const auto x_m_n_a = transform_tensor_descriptor(
x_b_m_n_a,
make_tuple(
make_merge_transform(make_tuple(number<B_val>{}, number<M_val>{})),
make_pass_through_transform(number<N_val>{})
),
make_tuple(sequence<0, 1>{}, sequence<2>{}),
make_tuple(sequence<0>{}, sequence<1>{}));
const auto x_m_n_b = transform_tensor_descriptor(
x_b_m_n_b,
make_tuple(
make_merge_transform(make_tuple(number<B_val>{}, number<M_val>{})),
make_pass_through_transform(number<N_val>{})
),
make_tuple(sequence<0, 1>{}, sequence<2>{}),
make_tuple(sequence<0>{}, sequence<1>{}));
const auto y_m_n = transform_tensor_descriptor(
y_b_m_n,
make_tuple(
make_merge_transform(make_tuple(number<B_val>{}, number<M_val>{})),
make_pass_through_transform(number<N_val>{})
),
make_tuple(sequence<0, 1>{}, sequence<2>{}),
make_tuple(sequence<0>{}, sequence<1>{}));
// Calculate origin in flattened space
const auto iM = get_block_id() * S::Block_M;
// Create tile windows
auto x_window_a = make_tile_window(x_m_n_a,
make_tuple(number<S::Block_M>{}, number<S::Block_N>{}),
{iM, 0},
Policy::template MakeXBlockTileDistribution<Problem>());
auto x_window_b = make_tile_window(x_m_n_b,
make_tuple(number<S::Block_M>{}, number<S::Block_N>{}),
{iM, 0},
Policy::template MakeXBlockTileDistribution<Problem>());
auto y_window = make_tile_window(y_m_n,
make_tuple(number<S::Block_M>{}, number<S::Block_N>{}),
{iM, 0},
Policy::template MakeXBlockTileDistribution<Problem>());
// Calculate iterations needed
index_t num_n_tile_iteration =
__builtin_amdgcn_readfirstlane(integer_divide_ceil(N_val, S::Block_N));
// Process tiles
for(int iN = __builtin_amdgcn_readfirstlane(0); iN < num_n_tile_iteration; ++iN)
{
const auto xa = load_tile(x_window_a);
const auto xb = load_tile(x_window_b);
auto y_compute = load_tile(y_window);
constexpr auto spans = decltype(xa)::get_distributed_spans();
sweep_tile_span(spans[number<0>{}], [&](auto idx0) {
sweep_tile_span(spans[number<1>{}], [&](auto idx1) {
constexpr auto i_j_idx = ck_tile::make_tuple(idx0, idx1);
const auto x = ck_tile::type_convert<ComputeDataType>(xa[i_j_idx]);
const auto y = ck_tile::type_convert<ComputeDataType>(xb[i_j_idx]);
y_compute(i_j_idx) = x + y;
});
});
store_tile(y_window, cast_tile<YDataType>(y_compute));
move_tile_window(x_window_a, {0, S::Block_N});
move_tile_window(x_window_b, {0, S::Block_N});
move_tile_window(y_window, {0, S::Block_N});
}
}
};
template <typename Problem_, typename Policy_ = AddDefaultPolicy>
struct Add
{
@@ -100,81 +220,54 @@ struct Add
{
using S = typename Problem::BlockShape;
// Create 3D tensor views first
const auto x_b_m_n_a = make_naive_tensor_view<address_space_enum::global,
memory_operation_enum::set,
amd_buffer_coherence_enum::slc>(
p_x_a,
make_tuple(B, M, N),
make_tuple(M * N, N, 1),
number<S::Vector_N>{},
number<1>{});
const auto x_b_m_n_b = make_naive_tensor_view<address_space_enum::global,
memory_operation_enum::set,
amd_buffer_coherence_enum::slc>(
p_x_b,
make_tuple(B, M, N),
make_tuple(M * N, N, 1),
number<S::Vector_N>{},
number<1>{});
const auto y_b_m_n = make_naive_tensor_view<address_space_enum::global,
// Create flattened 2D view by combining B and M dimensions
const index_t M_flattened = B * M;
const auto x_m_n_a = make_naive_tensor_view<address_space_enum::global,
memory_operation_enum::set,
amd_buffer_coherence_enum::slc>(
p_y,
make_tuple(B, M, N),
make_tuple(M * N, N, 1),
p_x_a,
make_tuple(M_flattened, N),
make_tuple(N, 1),
number<S::Vector_N>{},
number<1>{}); // raw data, shape of tensor, stride of tensor, lastGarunteedVectorLength,
// lastGarunteedVectorStride
const auto x_m_n_b = make_naive_tensor_view<address_space_enum::global,
memory_operation_enum::set,
amd_buffer_coherence_enum::slc>(
p_x_b,
make_tuple(M_flattened, N),
make_tuple(N, 1),
number<S::Vector_N>{},
number<1>{});
// Now transform the 3D tensor views to 2D using make_merge_transform
// This merges the B and M dimensions
const auto x_m_n_a = transform_tensor_descriptor(
x_b_m_n_a,
make_tuple(
make_merge_transform(make_tuple(number<B>{}, number<M>{})),
make_pass_through_transform(number<N>{})
),
make_tuple(sequence<0, 1>{}, sequence<2>{}),
make_tuple(sequence<0>{}, sequence<1>{}));
const auto x_m_n_b = transform_tensor_descriptor(
x_b_m_n_b,
make_tuple(
make_merge_transform(make_tuple(number<B>{}, number<M>{})),
make_pass_through_transform(number<N>{})
),
make_tuple(sequence<0, 1>{}, sequence<2>{}),
make_tuple(sequence<0>{}, sequence<1>{}));
const auto y_m_n = transform_tensor_descriptor(
y_b_m_n,
make_tuple(
make_merge_transform(make_tuple(number<B>{}, number<M>{})),
make_pass_through_transform(number<N>{})
),
make_tuple(sequence<0, 1>{}, sequence<2>{}),
make_tuple(sequence<0>{}, sequence<1>{}));
const auto y_m_n = make_naive_tensor_view<address_space_enum::global,
memory_operation_enum::set,
amd_buffer_coherence_enum::slc>(
p_y,
make_tuple(M_flattened, N),
make_tuple(N, 1),
number<S::Vector_N>{},
number<1>{});
const auto iM = get_block_id() * S::Block_M; // origin of the block along
auto x_window_a = make_tile_window(x_m_n_a,
make_tuple(number<S::Block_M>{}, number<S::Block_N>{}),
{iM, 0},
Policy::template MakeXBlockTileDistribution<Problem>());
make_tuple(number<S::Block_M>{}, number<S::Block_N>{}),
{iM, 0},
Policy::template MakeXBlockTileDistribution<Problem>());
auto x_window_b = make_tile_window(x_m_n_b,
make_tuple(number<S::Block_M>{}, number<S::Block_N>{}),
{iM, 0},
Policy::template MakeXBlockTileDistribution<Problem>());
make_tuple(number<S::Block_M>{}, number<S::Block_N>{}),
{iM, 0},
Policy::template MakeXBlockTileDistribution<Problem>());
auto y_window = make_tile_window(y_m_n,
make_tuple(number<S::Block_M>{}, number<S::Block_N>{}),
{iM, 0},
Policy::template MakeXBlockTileDistribution<Problem>());
make_tuple(number<S::Block_M>{}, number<S::Block_N>{}),
{iM, 0},
Policy::template MakeXBlockTileDistribution<Problem>());
index_t num_n_tile_iteration =
__builtin_amdgcn_readfirstlane(integer_divide_ceil(N, S::Block_N));
@@ -200,6 +293,7 @@ struct Add
move_tile_window(x_window_b, {0, S::Block_N});
move_tile_window(y_window, {0, S::Block_N});
}
}
};