3.6.0 update (#2005)

* 3.6.0 update

* doc and swap stuff

---------

Co-authored-by: yuzhai <yuzhai@nvidia.com>
Co-authored-by: Haicheng Wu <haichengw@nvidia.com>
This commit is contained in:
Yujia Zhai
2024-12-25 01:34:40 -05:00
committed by GitHub
co-authored by yuzhai Haicheng Wu
parent e1cd8c7866
commit 3d261a5974
258 changed files with 10863 additions and 3883 deletions
+80 -127
View File
@@ -26,52 +26,30 @@
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
add_custom_target(
cutlass_test_unit_gemm_device
DEPENDS
cutlass_test_unit_gemm_device_simt
cutlass_test_unit_gemm_device_tensorop_sm70
cutlass_test_unit_gemm_device_tensorop_sm75
cutlass_test_unit_gemm_device_tensorop_f16_sm80
cutlass_test_unit_gemm_device_tensorop_f32_sm80
cutlass_test_unit_gemm_device_tensorop_f32_tf32_sm80
cutlass_test_unit_gemm_device_tensorop_f64
cutlass_test_unit_gemm_device_tensorop_s32_sm80
cutlass_test_unit_gemm_device_wmma
cutlass_test_unit_gemm_device_tensorop_planar_complex
cutlass_test_unit_gemm_device_sparse_tensorop_sm80
cutlass_test_unit_gemv_device
cutlass_test_unit_gemm_device_tensorop_sm90
cutlass_test_unit_sparse_gemm_device_tensorop_sm90
cutlass_test_unit_gemm_device_tensorop_cluster_multicast_sm90
)
add_custom_target(cutlass_test_unit_gemm_device)
add_custom_target(test_unit_gemm_device)
add_custom_target(
test_unit_gemm_device
DEPENDS
test_unit_gemm_device_simt
test_unit_gemm_device_tensorop_sm70
test_unit_gemm_device_tensorop_sm75
test_unit_gemm_device_tensorop_f16_sm80
test_unit_gemm_device_tensorop_f32_sm80
test_unit_gemm_device_tensorop_f32_tf32_sm80
test_unit_gemm_device_tensorop_f64
test_unit_gemm_device_tensorop_s32_sm80
test_unit_gemm_device_wmma
test_unit_gemm_device_tensorop_planar_complex
test_unit_gemm_device_sparse_tensorop_sm80
test_unit_gemv_device
test_unit_gemm_device_tensorop_sm90
)
################################################################################
add_custom_target(
cutlass_test_unit_gemm_device_sm90
DEPENDS
cutlass_test_unit_gemm_device_tensorop_sm90
cutlass_test_unit_gemm_device_tensorop_cluster_multicast_sm90
)
function(cutlass_test_unit_gemm_device_add_deps NAME)
string(REGEX REPLACE "^cutlass_" "" TEST_NAME "${NAME}")
add_dependencies(cutlass_test_unit_gemm_device ${NAME})
add_dependencies(test_unit_gemm_device ${TEST_NAME})
endfunction()
cutlass_test_unit_add_executable(
function(cutlass_test_unit_gemm_device_add_executable NAME)
cutlass_test_unit_add_executable(${NAME} ${ARGN} DO_NOT_LOWERCASE_TEST_NAME)
cutlass_test_unit_gemm_device_add_deps(${NAME})
endfunction()
function(cutlass_test_unit_gemm_device_add_executable_split_file NAME)
cutlass_test_unit_add_executable_split_file(${NAME} ${ARGN} DO_NOT_LOWERCASE_TEST_NAME)
cutlass_test_unit_gemm_device_add_deps(${NAME})
endfunction()
################################################################################
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_simt
BATCH_SOURCES ON
@@ -126,7 +104,9 @@ cutlass_test_unit_add_executable(
gemm_splitk_simt_sm50.cu
)
cutlass_test_unit_add_executable(
list(APPEND CUTLASS_TEST_UNIT_GEMM_DEVICE_LIST cutlass_test_unit_gemm_device_simt)
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_simt_3x
BATCH_SOURCES ON
@@ -139,8 +119,7 @@ cutlass_test_unit_add_executable(
sm61_gemm_s8_s8_s32_simt.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_sm70
BATCH_SOURCES ON
@@ -159,7 +138,7 @@ cutlass_test_unit_add_executable(
gemm_splitk_tensor_op_sm70.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_sm75
BATCH_SOURCES ON
@@ -204,7 +183,7 @@ cutlass_test_unit_add_executable(
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_f16_sm80
BATCH_SOURCES ON
@@ -214,7 +193,7 @@ cutlass_test_unit_add_executable(
gemm_f16n_f16t_f16t_tensor_op_f16_slicedk_sm80.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_f32_sm80
BATCH_SOURCES ON
@@ -236,7 +215,7 @@ cutlass_test_unit_add_executable(
gemm_f16n_f16n_f16n_direct_store_tensor_op_f32_sm80.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_f32_sm80_3x
sm80_gemm_s8_s8_s32_tensor_op.cu
@@ -245,7 +224,7 @@ cutlass_test_unit_add_executable(
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_mixed_input_tensorop_sm80
BATCH_SOURCES ON
@@ -286,13 +265,14 @@ cutlass_test_unit_add_executable(
gemm_universal_s8t_s4n_s8t_mixed_input_tensor_op_s32_sm80.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_sm90
BATCH_SOURCES ON
BATCH_SIZE 4
sm90_gemm_f16_f16_f16_tensor_op.cu
sm90_gett_f16_f16_f16_tensor_op.cu
sm90_gemm_bf16_bf16_bf16_tensor_op_f32.cu
sm90_gemm_s8_s8_s8_tensor_op_s32.cu
sm90_gemm_tf32_tf32_f32_tensor_op_f32.cu
@@ -302,7 +282,7 @@ cutlass_test_unit_add_executable(
sm90_gemm_f8_f8_f8_tensor_op_fp32.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_sm90_stream_k
sm90_gemm_stream_k_scheduler.cu
@@ -311,7 +291,7 @@ cutlass_test_unit_add_executable(
)
# Alignment tests
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_alignx_sm90
BATCH_SOURCES ON
@@ -336,14 +316,14 @@ cutlass_test_unit_add_executable(
)
# Ptr Array test
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_sm90_ptr_array
sm90_gemm_f16_f16_f16_tensor_op_f32_ptr_array.cu
sm90_gemm_f16_f16_f16_tensor_op_f32_ptr_array_pingpong.cu
)
# Group Gemm test
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_sm90_group_gemm
sm90_gemm_f16_f16_f16_tensor_op_f32_group_gemm.cu
sm90_gemm_f16_f16_f16_tensor_op_f32_group_gemm_pingpong.cu
@@ -351,31 +331,25 @@ cutlass_test_unit_add_executable(
# Sparse tests
# Sparse kernels trigger an ICE in gcc 7.5
if (NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0))
cutlass_test_unit_add_executable(
cutlass_test_unit_sparse_gemm_device_tensorop_sm90
if (NOT (CUTLASS_GNU_HOST_COMPILE AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0))
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_sparse_gemm_device_tensorop_sm90
# No batching of source to control compiler memory usage
BATCH_SOURCES ON
BATCH_SIZE 1
sm90_sparse_gemm_s8_s8_s32_tensor_op_s32.cu
sm90_sparse_gemm_f8_f8_f32_tensor_op_f32.cu
sm90_sparse_gemm_f16_f16_f32_tensor_op_f32.cu
sm90_sparse_gemm_tf32_tf32_f32_tensor_op_f32.cu
)
# No batching of source to control compiler memory usage
BATCH_SOURCES ON
BATCH_SIZE 1
sm90_sparse_gemm_s8_s8_s32_tensor_op_s32.cu
sm90_sparse_gemm_f8_f8_f32_tensor_op_f32.cu
sm90_sparse_gemm_f16_f16_f32_tensor_op_f32.cu
sm90_sparse_gemm_tf32_tf32_f32_tensor_op_f32.cu
)
else()
cutlass_test_unit_add_executable(
cutlass_test_unit_sparse_gemm_device_tensorop_sm90
# No batching of source to control compiler memory usage
BATCH_SOURCES ON
BATCH_SIZE 1
)
endif()
# Fused epilogue tests
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_epilogue_fusion_sm90
BATCH_SOURCES ON
@@ -400,7 +374,7 @@ cutlass_test_unit_add_executable(
sm90_gemm_f8_f8_bf16_tensor_op_fp32_evt.cu
sm90_gemm_f8_f8_f32_tensor_op_f32_cluster_warpspecialized_cooperative_evt.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_cluster_multicast_sm90
BATCH_SOURCES ON
@@ -412,7 +386,7 @@ cutlass_test_unit_add_executable(
sm90_gemm_f16_f16_f16_tensor_op_f32_cluster_warpspecialized_cooperative.cu
sm90_gemm_f8_f8_f32_tensor_op_f32_cluster_warpspecialized_cooperative.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_gmma_rs_warpspecialized_sm90
BATCH_SOURCES ON
@@ -423,7 +397,7 @@ cutlass_test_unit_add_executable(
sm90_gemm_f16_f16_f32_tensor_op_f32_rs_cluster_warpspecialized_cooperative.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_f32_tf32_sm80
BATCH_SOURCES ON
@@ -443,7 +417,7 @@ cutlass_test_unit_add_executable(
sm80_gemm_f16_f16_f32_tensor_op_f32.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_f64
BATCH_SOURCES ON
@@ -471,7 +445,7 @@ cutlass_test_unit_add_executable(
gemm_cf64t_cf64n_cf64t_tensor_op_f64_gaussian_sm90.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_s32_sm80
BATCH_SOURCES ON
@@ -493,7 +467,7 @@ cutlass_test_unit_add_executable(
gemm_s4n_s4t_s4n_tensor_op_s32_sm80.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_wmma
BATCH_SOURCES ON
@@ -551,7 +525,7 @@ cutlass_test_unit_add_executable(
gemm_f16t_f16n_f32t_singlestage_wmma_tensor_op_f32_sm70.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_planar_complex
BATCH_SOURCES ON
@@ -562,7 +536,7 @@ cutlass_test_unit_add_executable(
gemm_planar_complex_f16_f16_f32_tensor_op_sm80.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_tensorop_sm89
BATCH_SOURCES ON
@@ -574,7 +548,7 @@ cutlass_test_unit_add_executable(
# gemm_f8t_f8n_f8t_tensor_op_f32_sparse_sm89.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_grouped
BATCH_SOURCES ON
@@ -583,7 +557,7 @@ cutlass_test_unit_add_executable(
gemm_grouped_sm80.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_grouped_scheduler
BATCH_SOURCES ON
@@ -592,7 +566,7 @@ cutlass_test_unit_add_executable(
gemm_grouped_scheduler_sm80.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_grouped_rank_2k_scheduler
BATCH_SOURCES ON
@@ -601,7 +575,7 @@ cutlass_test_unit_add_executable(
rank_2k_grouped_scheduler_sm80.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_sparse_tensorop_sm80
BATCH_SOURCES ON
@@ -622,7 +596,7 @@ cutlass_test_unit_add_executable(
gemm_s4t_s4n_s32t_tensor_op_s32_sparse_sm80.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemv_device
BATCH_SOURCES ON
@@ -631,42 +605,22 @@ cutlass_test_unit_add_executable(
gemv.cu
)
if (NOT CUDA_COMPILER MATCHES "[Cc]lang")
if (CUTLASS_NVCC_DEVICE_COMPILE)
add_dependencies(
cutlass_test_unit_gemm_device
cutlass_test_unit_gemm_device_gemm_with_fused_epilogue_tensorop
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_gemm_with_fused_epilogue_tensorop
gemm_with_reduction_f16n_f16n_f16n_tensorop_f32_sm75.cu
gemm_with_broadcast_f16n_f16n_f16n_tensorop_f32_sm75.cu
gemm_with_reduction_f16t_f16n_f16n_tensorop_f32_sm80.cu
)
add_dependencies(
test_unit_gemm_device
test_unit_gemm_device_gemm_with_fused_epilogue_tensorop
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_gemm_with_fused_epilogue_tensorop
gemm_with_reduction_f16n_f16n_f16n_tensorop_f32_sm75.cu
gemm_with_broadcast_f16n_f16n_f16n_tensorop_f32_sm75.cu
gemm_with_reduction_f16t_f16n_f16n_tensorop_f32_sm80.cu
)
endif()
if (NOT CUDA_COMPILER MATCHES "[Cc]lang")
if (CUTLASS_NVCC_DEVICE_COMPILE)
add_dependencies(
cutlass_test_unit_gemm_device
cutlass_test_unit_gemm_device_blas3
)
add_dependencies(
test_unit_gemm_device
test_unit_gemm_device_blas3
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_blas3
BATCH_SOURCES ON
@@ -833,7 +787,7 @@ cutlass_test_unit_add_executable(
hemm_cf64_cf64_cf64_tensor_op_f64_sm90.cu
)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_grouped_blas3
BATCH_SOURCES ON
@@ -858,13 +812,12 @@ cutlass_test_unit_add_executable(
endif()
if (NOT CUDA_COMPILER MATCHES "[Cc]lang")
if (CUTLASS_NVCC_DEVICE_COMPILE)
cutlass_test_unit_add_executable(
cutlass_test_unit_gemm_device_broadcast
gemm_f16t_f16n_f16t_tensor_op_f16_broadcast_sm80.cu
)
cutlass_test_unit_gemm_device_add_executable(
cutlass_test_unit_gemm_device_broadcast
gemm_f16t_f16n_f16t_tensor_op_f16_broadcast_sm80.cu
)
endif()
+33 -4
View File
@@ -39,6 +39,7 @@
#include <sstream>
#include <algorithm>
#include <random>
#include <numeric> // std::lcm
#include "../../common/cutlass_unit_test.h"
#include "cutlass/util/host_tensor.h"
@@ -55,6 +56,7 @@
#include "cutlass/complex.h"
#include "cutlass/transform/device/transform_universal_adapter.hpp"
#include "cutlass/transform/kernel/sparse_gemm_compressor.hpp"
#include "cutlass/detail/collective.hpp"
#include "testbed_utils.h"
@@ -151,6 +153,12 @@ struct ElementScalarType<Gemm, Default, std::void_t<typename Gemm::EpilogueOutpu
using Type = typename Gemm::EpilogueOutputOp::ElementScalar;
};
template<class CollectiveEpilogue, class = void>
struct IsSfdEpi : cute::false_type {};
template<class CollectiveEpilogue>
struct IsSfdEpi<CollectiveEpilogue, cute::void_t<typename CollectiveEpilogue::FusionCallbacks::Operation::GmemLayoutTagScalefactor>> : cute::true_type {};
// The maximum swizzle size to use
//
// This class, like Splits above makes it harder to confuse
@@ -1140,7 +1148,6 @@ struct HostCollectiveEpilogue {
static constexpr bool IsAbsMaxEnabledAux = IsAuxOutEnabled && FusionOp::IsAbsMaxSupported &&
(cute::is_same_v<ElementAux, cutlass::float_e4m3_t> ||
cute::is_same_v<ElementAux, cutlass::float_e5m2_t>);
using Arguments = typename Gemm::GemmKernel::EpilogueArguments;
/// Initialization
@@ -1454,6 +1461,22 @@ struct HostCollectiveEpilogue {
bool passed = equality_check(reference_D.host_view(), tensor_D.host_view());
if(!passed) {
#if 0
auto [M, N, K, L] = problem_shape_MNKL;
auto ref = cute::make_tensor(detail::make_iterator(reference_D.host_data()),
cute::make_layout(cute::make_shape(M, N, L), stride_d));
auto comp = cute::make_tensor(detail::make_iterator(tensor_D.host_data()),
cute::make_layout(cute::make_shape(M, N, L), stride_d));
for(int i=0; i<M; i++) {
for(int j=0; j<N; j++) {
for(int l=0; l<L; l++) {
if(static_cast<float>(ElementD(ref(i, j, l))) != static_cast<float>((ElementD(comp(i, j, l))))) {
printf("<m %d, n %d, l %d> ref: %f comp: %f\n", i, j, l, static_cast<float>(ElementD(ref(i, j, l))), static_cast<float>((ElementD(comp(i, j, l)))));
}
}
}
}
#endif
std::cout<<"D is incorrect"<<std::endl;
}
@@ -1575,9 +1598,12 @@ struct HostCollectiveEpilogue {
}
else {
fusion_args.alpha = alpha.at(coord_0);
fusion_args.beta = beta.at(coord_0);
fusion_args.alpha_ptr = alpha.device_data();
fusion_args.beta_ptr = beta.device_data(); // if vector_scale_mode is true this is nullptr
// Only initializing beta/beta_ptr for non-void source
if constexpr (not cute::is_void_v<typename kernel::ElementC>) {
fusion_args.beta = beta.at(coord_0);
fusion_args.beta_ptr = beta.device_data(); // if vector_scale_mode is true this is nullptr
}
if constexpr (IsPerRowScaleEnabled) {
int32_t m_stride = vector_scale_mode == VectorScale::ENABLED ? 1 : 0;
@@ -1620,6 +1646,7 @@ struct HostCollectiveEpilogue {
// example of how to set kernel activation arguments
// see ActivationFunctor::Arguments in activation.h for definition
// if Arguments doesn't exist then fusion_args.activation is empty
if constexpr (cute::is_same_v<ActivationFunctor, cutlass::epilogue::thread::ScaledGELU_taylor<ElementCompute>>) {
fusion_args.activation.scale = ElementCompute(1);
}
@@ -1713,6 +1740,7 @@ struct HostCollectiveEpilogue {
decltype(Vbeta),
ActivationFunctor,
cutlass::plus<ElementCompute>
, false /*PerColumnBias_*/
> epilogue_params{};
epilogue_params.C = C;
@@ -1779,6 +1807,7 @@ struct TestbedImpl {
using ScheduleType = typename Gemm::GemmKernel::CollectiveMainloop::DispatchPolicy::Schedule;
// All Collective MMA operands are defined by HostCollectiveMainloopType based on the schedule type
using HostCollectiveMainloopType = HostCollectiveMainloop<ScheduleType, Gemm, ElementA, ElementB>;
using CollectiveEpilogue = cute::conditional_t<IsDefaultEpilogue<typename Gemm::GemmKernel::CollectiveEpilogue>::value || force_legacy_epilogue,
HostCollectiveDefaultEpilogue<Gemm>,
HostCollectiveEpilogue<Gemm>>;
@@ -2004,7 +2033,7 @@ struct TestbedImpl {
return false;
}
}
catch (std::exception const& e) {
catch ([[maybe_unused]] std::exception const& e) {
CUTLASS_TRACE_HOST("TestbedImpl::run: this->initialize threw an exception: " << e.what());
throw;
}
@@ -346,7 +346,7 @@ struct HostCollectiveMainloop {
stride_b_host.clear();
auto [M, N, K, L] = cute::append<4>(problem_shapes.get_host_problem_shape(0), 1);
L = max(problem_shapes.groups(), L);
L = cutlass::platform::max(problem_shapes.groups(), L);
for(int32_t i = 0; i < L; ++i) {
auto [M, N, K, mock_L] = cute::append<4>(problem_shapes.get_host_problem_shape(i), 1);
@@ -380,7 +380,7 @@ struct HostCollectiveMainloop {
Arguments to_args(ProblemShapeType problem_shapes) {
auto [M, N, K, L] = cute::append<4>(problem_shapes.get_host_problem_shape(0), 1);
L = max(problem_shapes.groups(), L);
L = cutlass::platform::max(problem_shapes.groups(), L);
std::vector<ElementA *> ptr_A_host(L);
std::vector<ElementB *> ptr_B_host(L);
@@ -587,7 +587,7 @@ struct HostCollectiveDefaultEpilogue {
stride_d_host.clear();
auto [M, N, K, L] = cute::append<4>(problem_shapes.get_host_problem_shape(0), 1);
L = max(problem_shapes.groups(), L);
L = cutlass::platform::max(problem_shapes.groups(), L);
for (int32_t i = 0; i < L; ++i) {
auto [M, N, K, mock_L] = cute::append<4>(problem_shapes.get_host_problem_shape(i), 1);
@@ -649,7 +649,7 @@ struct HostCollectiveDefaultEpilogue {
ElementScalar beta,
int batch) {
auto [M, N, K, L] = cute::append<4>(problem_shapes.get_host_problem_shape(0), 1);
L = max(problem_shapes.groups(), L);
L = cutlass::platform::max(problem_shapes.groups(), L);
tensors_D[batch].sync_host();
EXPECT_GT(cutlass::reference::host::TensorNorm(tensors_C[batch].host_view()), 0);
@@ -678,7 +678,7 @@ struct HostCollectiveDefaultEpilogue {
Arguments to_args(ProblemShapeType problem_shapes) {
auto [M, N, K, L] = cute::append<4>(problem_shapes.get_host_problem_shape(0), 1);
L = max(problem_shapes.groups(), L);
L = cutlass::platform::max(problem_shapes.groups(), L);
std::vector<ElementC *> ptr_C_host(L);
std::vector<ElementD *> ptr_D_host(L);
@@ -724,8 +724,8 @@ struct HostCollectiveDefaultEpilogue {
//
// Allocate the GEMM workspace
//
auto [M, N, K, L] = cute::append<4>(problem_shapes.get_host_problem_shape(0), 1);
L = max(problem_shapes.groups(), L);
auto [M, N, K, L] = cute::append<4>(problem_shapes.get_host_problem_shape(batch), 1);
L = std::max(problem_shapes.groups(), L);
auto coord_0 = cutlass::make_Coord(0);
auto C = cute::make_tensor(detail::make_iterator(tensors_C[batch].host_data()),
@@ -905,9 +905,8 @@ struct HostCollectiveEpilogue {
references_D.clear();
stride_c_host.clear();
stride_d_host.clear();
auto [M, N, K, L] = cute::append<4>(problem_shapes.get_host_problem_shape(0), 1);
L = max(problem_shapes.groups(), L);
L = std::max(problem_shapes.groups(), L);
for (int32_t i = 0; i < L; ++i) {
auto [M, N, K, mock_L] = cute::append<4>(problem_shapes.get_host_problem_shape(i), 1);
@@ -1118,7 +1117,6 @@ struct HostCollectiveEpilogue {
passed &= tmp;
}
}
return passed;
}
@@ -1189,7 +1187,7 @@ struct HostCollectiveEpilogue {
Arguments to_args(ProblemShapeType problem_shapes) {
auto coord_0 = cutlass::make_Coord(0);
auto [M, N, K, L] = cute::append<4>(problem_shapes.get_host_problem_shape(0), 1);
L = max(problem_shapes.groups(), L);
L = std::max(problem_shapes.groups(), L);
std::vector<ElementC *> ptr_C_host(L);
std::vector<ElementD *> ptr_D_host(L);
@@ -1220,19 +1218,22 @@ struct HostCollectiveEpilogue {
device_tensors_Aux.copy_from_host(ptr_Aux_host.data());
}
auto device_tensors_C_ptr = cute::is_void_v<typename kernel::ElementC> ? nullptr :
reinterpret_cast<typename kernel::ElementC const**>(device_tensors_C.get());
Arguments arguments;
if constexpr (IsGroupGemm) {
arguments =
{
{},
device_tensors_C.get(), stride_c_device.get(), device_tensors_D.get(), stride_d_device.get()
device_tensors_C_ptr, stride_c_device.get(), device_tensors_D.get(), stride_d_device.get()
};
}
else {
arguments =
{
{},
device_tensors_C.get(), stride_c_host[0], device_tensors_D.get(), stride_d_host[0]
device_tensors_C_ptr, stride_c_host[0], device_tensors_D.get(), stride_d_host[0]
};
}
@@ -1252,7 +1253,9 @@ struct HostCollectiveEpilogue {
fusion_args.beta = beta.at(coord_0);
fusion_args.alpha_ptr = alpha.device_data();
fusion_args.beta_ptr = beta.device_data();
// can_implement requires beta_ptr to not be set if its voidC
fusion_args.beta_ptr = cute::is_void_v<typename kernel::ElementC> ? nullptr :
beta.device_data();
if constexpr (IsScaleFactorEnabled) {
fusion_args.scale_a = scale_A.at(coord_0);
@@ -1316,7 +1319,8 @@ struct HostCollectiveEpilogue {
//
// Allocate the GEMM workspace
//
auto [M, N, K, L] = cute::append<4>(problem_shapes.get_host_problem_shape(batch), 1);
auto problem_shape_MNKL = cute::append<4>(problem_shapes.get_host_problem_shape(batch), 1);
auto [M, N, K, L] = problem_shape_MNKL;
auto coord_0 = cutlass::make_Coord(0);
auto C = cute::make_tensor(detail::make_iterator(tensors_C[batch].host_data()),
cute::make_layout(cute::make_shape(M, N, 1), stride_c_host[batch]));
@@ -1338,7 +1342,6 @@ struct HostCollectiveEpilogue {
cute::make_layout(cute::make_shape(M, N, cute::_1{}), cute::make_stride(cute::_1{}, cute::_0{}, M)));
auto Vbeta = cute::make_tensor(detail::make_iterator(beta.host_data()),
cute::make_layout(cute::make_shape(M, N, cute::_1{}), cute::make_stride(cute::_1{}, cute::_0{}, N)));
cutlass::reference::host::GettEpilogueParams<
ElementScalar,
ElementScalar,
@@ -1518,7 +1521,7 @@ struct TestbedImpl {
{
using namespace cute;
auto [M, N, K, L] = cute::append<4>(problem_shapes.get_host_problem_shape(0), 1);
L = max(problem_shapes.groups(), L);
L = std::max(problem_shapes.groups(), L);
bool passed = true;
for (int32_t i = 0; i < L; ++i) {
@@ -1760,7 +1763,7 @@ bool TestAll(double alpha = 1.0, double beta = 0.0, CheckEquality check_relative
cutlass::DeviceAllocation<typename ProblemShapeType::UnderlyingProblemShape> problem_sizes_device;
for (int i = 0; i < batch; ++i) {
problem_sizes_host.push_back({m, n, k});
problem_sizes_host.push_back({m * ((i % 3) + 1), n * ((i % 4) + 1), k * ((i % 5) + 1)});
}
problem_sizes_device.reset(problem_sizes_host.size());
@@ -0,0 +1,184 @@
/***************************************************************************************************
* Copyright (c) 2017 - 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************************************/
/*! \file
\brief Tests for device-wide GEMM interface
*/
#include <iostream>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include "cutlass/cutlass.h"
#include "cute/tensor.hpp"
#include "cute/atom/mma_atom.hpp"
#include "cutlass/numeric_types.h"
#include "cutlass/gemm/device/gemm_universal_adapter.h"
#include "cutlass/gemm/kernel/gemm_universal.hpp"
#include "cutlass/epilogue/collective/collective_builder.hpp"
#include "cutlass/gemm/collective/collective_builder.hpp"
#include "cutlass/epilogue/collective/sm70_epilogue_vectorized.hpp"
#include "cutlass/epilogue/collective/default_epilogue.hpp"
#include "cutlass/epilogue/thread/linear_combination.h"
#include "../../common/cutlass_unit_test.h"
#include "cutlass/util/reference/device/gett.hpp"
#include "cutlass/util/reference/device/tensor_compare.h"
#if defined(CUTLASS_ARCH_MMA_SM90_SUPPORTED)
using namespace cute;
/////////////////////////////////////////////////////////////////////////////////////////////////
TEST(SM90_Device_Gett_f16t_f16n_f16n_tensor_op_gmma_f16, 8x8x8x8x8x8) {
using BatModeStrides = int;
using RowModeStridesA = cute::Stride<int, int>;
using RedModeStrides = cute::Stride<cute::_1, int>;
using ColModeStridesB = cute::Stride<int, int>;
using RowModeStridesC = cute::Stride<cute::_1, int>;
using ColModeStridesC = cute::Stride<int, int>;
using StrideA = cute::Stride<RowModeStridesA, RedModeStrides, BatModeStrides>;
using StrideB = cute::Stride<ColModeStridesB, RedModeStrides, BatModeStrides>;
using StrideC = cute::Stride<RowModeStridesC, ColModeStridesC, BatModeStrides>;
using StrideD = StrideC;
using TileShape = Shape<Shape<_8, _8>, Shape<_8, _8>, Shape<_8, _8>>;
using CollectiveOp = typename cutlass::gemm::collective::CollectiveBuilder<
cutlass::arch::Sm90, cutlass::arch::OpClassTensorOp,
cutlass::half_t, StrideA, 8,
cutlass::half_t, StrideB, 8,
cutlass::half_t,
TileShape, Shape<_1,_1,_1>,
cutlass::gemm::collective::StageCountAuto,
cutlass::gemm::collective::KernelScheduleAuto
>::CollectiveOp;
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
cutlass::arch::Sm90, cutlass::arch::OpClassTensorOp,
TileShape, Shape<_1,_1,_1>,
cutlass::epilogue::collective::EpilogueTileAuto,
cutlass::half_t, cutlass::half_t,
cutlass::half_t, StrideC, 8,
cutlass::half_t, StrideC, 8,
cutlass::epilogue::collective::EpilogueScheduleAuto
>::CollectiveOp;
using GettKernel = cutlass::gemm::kernel::GemmUniversal<
Shape<Shape<int,int>,
Shape<int,int>,
Shape<int,int>,
int>,
CollectiveOp,
CollectiveEpilogue
>;
using Gett = cutlass::gemm::device::GemmUniversalAdapter<GettKernel>;
auto problem_shape = make_shape(
make_shape(32,8),
make_shape(32,4),
make_shape(32,2),
1
);
auto [M, N, K, L] = problem_shape;
StrideA dA = make_stride(make_stride(64, 2048), make_stride(_1{}, 32), size(M) * size(K));
StrideB dB = make_stride(make_stride(64, 2048), make_stride(_1{}, 32), size(N) * size(K));
StrideC dC = make_stride(make_stride(_1{}, 32), make_stride(256, 8192), size(M) * size(N));
StrideD dD = dC;
cutlass::half_t alpha = cutlass::half_t(1.0f);
cutlass::half_t beta = cutlass::half_t(1.0f);
thrust::host_vector<cutlass::half_t> A_h(size(M) * size(K) * size(L));
thrust::host_vector<cutlass::half_t> B_h(size(N) * size(K) * size(L));
thrust::host_vector<cutlass::half_t> C_h(size(M) * size(N) * size(L));
thrust::host_vector<cutlass::half_t> D_h(size(M) * size(N) * size(L));
thrust::host_vector<cutlass::half_t> D_h_ref(size(M) * size(N) * size(L));
for (auto& a : A_h) a = cutlass::half_t(static_cast<int>(4 * (rand() / double(RAND_MAX) - 1)));
for (auto& b : B_h) b = cutlass::half_t(static_cast<int>(4 * (rand() / double(RAND_MAX) - 1)));
for (auto& c : C_h) c = cutlass::half_t(static_cast<int>(4 * (rand() / double(RAND_MAX) - 1)));
for (auto& d : D_h) d = cutlass::half_t(-1);
for (auto& d : D_h_ref) d = cutlass::half_t(-1);
thrust::device_vector<cutlass::half_t> A = A_h;
thrust::device_vector<cutlass::half_t> B = B_h;
thrust::device_vector<cutlass::half_t> C = C_h;
thrust::device_vector<cutlass::half_t> D = D_h;
thrust::device_vector<cutlass::half_t> D_ref = D_h_ref;
typename Gett::Arguments args {
cutlass::gemm::GemmUniversalMode::kBatched,
problem_shape,
{A.data().get(), dA, B.data().get(), dB},
{ {alpha, beta}, C.data().get(), dC, D.data().get(), dD}
};
Gett gett;
auto status = gett(args);
EXPECT_TRUE(status == cutlass::Status::kSuccess);
auto cuda_err = cudaDeviceSynchronize();
EXPECT_TRUE(cuda_err == cudaSuccess);
cutlass::reference::device::gett(
problem_shape,
A.data().get(), dA,
B.data().get(), dB,
cutlass::half_t(0.0f),
C.data().get(), dC,
D_ref.data().get(), dD,
alpha, beta);
cuda_err = cudaDeviceSynchronize();
EXPECT_TRUE(cuda_err == cudaSuccess);
bool passed = cutlass::reference::device::BlockCompareEqual(
D.data().get(), D_ref.data().get(), D_ref.size());
EXPECT_TRUE(passed);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
#endif // defined(CUTLASS_ARCH_MMA_SM90_SUPPORTED)