CUTLASS 3.5.0 (#1411)

This commit is contained in:
Vijay Thakkar
2024-03-19 17:51:04 -04:00
committed by GitHub
parent ffa34e7075
commit 629f4653c3
468 changed files with 48729 additions and 7252 deletions
@@ -218,6 +218,84 @@ struct DefaultGemm<ElementA, LayoutA, kAlignmentA, ElementB, LayoutB, kAlignment
////////////////////////////////////////////////////////////////////////////////
/// Partial specialization for Ada Architecture
template <
/// Element type for A matrix operand
typename ElementA,
/// Layout type for A matrix operand
typename LayoutA,
/// Access granularity of A matrix in units of elements
int kAlignmentA,
/// Element type for B matrix operand
typename ElementB,
/// Layout type for B matrix operand
typename LayoutB,
/// Access granularity of A matrix in units of elements
int kAlignmentB,
/// Element type for C and D matrix operands
typename ElementC,
/// Element type for internal accumulation
typename ElementAccumulator,
/// Threadblock-level tile size (concept: GemmShape)
typename ThreadblockShape,
/// Warp-level tile size (concept: GemmShape)
typename WarpShape,
/// Warp-level tile size (concept: GemmShape)
typename InstructionShape,
/// Epilogue output operator
typename EpilogueOutputOp,
/// Threadblock-level swizzling operator
typename ThreadblockSwizzle,
/// Number of stages used in the pipelined mainloop
int Stages,
/// If true, kernel is configured to support serial reduction in the
/// epilogue
bool SplitKSerial,
/// Operation performed by GEMM
typename Operator,
/// Use zfill or predicate for out-of-bound cp.async
SharedMemoryClearOption SharedMemoryClear,
/// Gather operand A by using an index array
bool GatherA,
/// Gather operand B by using an index array
bool GatherB,
/// Scatter result D by using an index array
bool ScatterD,
/// Permute result D
typename PermuteDLayout,
/// Permute operand A
typename PermuteALayout,
/// Permute operand B
typename PermuteBLayout
>
struct DefaultGemm<ElementA, LayoutA, kAlignmentA, ElementB, LayoutB, kAlignmentB, ElementC,
layout::RowMajor, ElementAccumulator, arch::OpClassTensorOp,
arch::Sm89, ThreadblockShape, WarpShape, InstructionShape,
EpilogueOutputOp, ThreadblockSwizzle, Stages, SplitKSerial,
Operator, SharedMemoryClear, GatherA, GatherB, ScatterD,
PermuteDLayout, PermuteALayout, PermuteBLayout> {
/// Define the threadblock-scoped matrix multiply-accumulate
using Mma = typename cutlass::gemm::threadblock::DefaultMma<
ElementA, LayoutA, kAlignmentA, ElementB, LayoutB, kAlignmentB,
ElementAccumulator, layout::RowMajor, arch::OpClassTensorOp, arch::Sm89,
ThreadblockShape, WarpShape, InstructionShape, Stages,
Operator, false, SharedMemoryClear, GatherA, GatherB,
PermuteALayout, PermuteBLayout>::ThreadblockMma;
static const int kPartitionsK = ThreadblockShape::kK / WarpShape::kK;
/// Define the epilogue
using Epilogue =
typename cutlass::epilogue::threadblock::DefaultEpilogueTensorOp<
ThreadblockShape, typename Mma::Operator, kPartitionsK, EpilogueOutputOp,
EpilogueOutputOp::kCount, ScatterD, PermuteDLayout>::Epilogue;
/// Define the kernel-level GEMM operator.
using GemmKernel = kernel::Gemm<Mma, Epilogue, ThreadblockSwizzle, SplitKSerial>;
};
////////////////////////////////////////////////////////////////////////////////
/// Partial specialization for Ampere Architecture
template <
/// Element type for A matrix operand
@@ -183,6 +183,67 @@ struct DefaultSparseGemm<ElementA, LayoutA, kAlignmentA, ElementB, LayoutB, kAli
using GemmKernel = kernel::SparseGemm<Mma, Epilogue, ThreadblockSwizzle, SplitKSerial>;
};
///////////////////////////////////////////////////////////////////////////////
/// Partial specialization for Ada Architecture
template <
/// Element type for A matrix operand
typename ElementA,
/// Layout type for A matrix operand
typename LayoutA,
/// Access granularity of A matrix in units of elements
int kAlignmentA,
/// Element type for B matrix operand
typename ElementB,
/// Layout type for B matrix operand
typename LayoutB,
/// Access granularity of A matrix in units of elements
int kAlignmentB,
/// Element type for C and D matrix operands
typename ElementC,
/// Element type for internal accumulation
typename ElementAccumulator,
/// Threadblock-level tile size (concept: GemmShape)
typename ThreadblockShape,
/// Warp-level tile size (concept: GemmShape)
typename WarpShape,
/// Warp-level tile size (concept: GemmShape)
typename InstructionShape,
/// Epilogue output operator
typename EpilogueOutputOp,
/// Threadblock-level swizzling operator
typename ThreadblockSwizzle,
/// Number of stages used in the pipelined mainloop
int Stages,
/// If true, kernel is configured to support serial reduction in the
/// epilogue
bool SplitKSerial,
/// Operation performed by GEMM
typename Operator>
struct DefaultSparseGemm<ElementA, LayoutA, kAlignmentA, ElementB, LayoutB, kAlignmentB, ElementC,
layout::RowMajor, ElementAccumulator, arch::OpClassTensorOp,
arch::Sm89, ThreadblockShape, WarpShape, InstructionShape,
EpilogueOutputOp, ThreadblockSwizzle, Stages, SplitKSerial,
Operator> {
/// Define the threadblock-scoped matrix multiply-accumulate
using Mma = typename cutlass::gemm::threadblock::DefaultSparseMma<
ElementA, LayoutA, kAlignmentA, ElementB, LayoutB, kAlignmentB,
ElementAccumulator, layout::RowMajor, arch::OpClassTensorOp, arch::Sm89,
ThreadblockShape, WarpShape, InstructionShape, Stages,
Operator>::ThreadblockMma;
static const int kPartitionsK = ThreadblockShape::kK / WarpShape::kK;
/// Define the epilogue
using Epilogue =
typename cutlass::epilogue::threadblock::DefaultEpilogueTensorOp<
ThreadblockShape, typename Mma::Operator, kPartitionsK, EpilogueOutputOp,
EpilogueOutputOp::kCount>::Epilogue;
/// Define the kernel-level GEMM operator.
using GemmKernel = kernel::SparseGemm<Mma, Epilogue, ThreadblockSwizzle, SplitKSerial>;
};
////////////////////////////////////////////////////////////////////////////////
} // namespace kernel
@@ -0,0 +1,157 @@
/***************************************************************************************************
* Copyright (c) 2024 - 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
Default configuration for a sparse GEMM with fused absolute-maximum calculations and scaling
*/
#pragma once
#include "cutlass/cutlass.h"
#include "cutlass/layout/matrix.h"
#include "cutlass/numeric_types.h"
#include "cutlass/arch/wmma.h"
#include "cutlass/epilogue/threadblock/epilogue.h"
#include "cutlass/epilogue/thread/linear_combination.h"
#include "cutlass/gemm/gemm.h"
#include "cutlass/gemm/kernel/gemm.h"
#include "cutlass/gemm/kernel/sparse_gemm_with_absmax.h"
#include "cutlass/gemm/kernel/default_gemm_sparse.h"
#include "cutlass/gemm/kernel/gemm_pipelined.h"
#include "cutlass/gemm/threadblock/default_mma_core_sm75.h"
#include "cutlass/gemm/threadblock/default_mma_core_sm70.h"
#include "cutlass/gemm/threadblock/default_mma_core_sm80.h"
#include "cutlass/gemm/threadblock/default_mma_core_sparse_sm80.h"
#include "cutlass/gemm/threadblock/default_sparse_mma.h"
#include "cutlass/gemm/threadblock/default_mma_core_simt.h"
#include "cutlass/gemm/threadblock/threadblock_swizzle.h"
#include "cutlass/epilogue/threadblock/default_epilogue_with_absmax.h"
#include "cutlass/epilogue/threadblock/default_epilogue_tensor_op.h"
#include "cutlass/epilogue/threadblock/default_epilogue_volta_tensor_op.h"
#include "cutlass/epilogue/threadblock/default_epilogue_simt.h"
#include "cutlass/transform/threadblock/predicated_tile_iterator.h"
#if defined(CUTLASS_ARCH_WMMA_ENABLED)
#include "cutlass/epilogue/threadblock/default_epilogue_wmma_tensor_op.h"
#endif //CUTLASS_ARCH_WMMA_ENABLED
////////////////////////////////////////////////////////////////////////////////
namespace cutlass {
namespace gemm {
namespace kernel {
////////////////////////////////////////////////////////////////////////////////
template <
/// Element type for A matrix operand
typename ElementA_,
/// Layout type for A matrix operand
typename LayoutA_,
/// Access granularity of A matrix in units of elements
int kAlignmentA,
/// Element type for B matrix operand
typename ElementB_,
/// Layout type for B matrix operand
typename LayoutB_,
/// Access granularity of B matrix in units of elements
int kAlignmentB,
/// Element type for C and D matrix operands
typename ElementC_,
/// Layout type for C and D matrix operands
typename LayoutC_,
/// Element type for internal accumulation
typename ElementAccumulator,
/// Operator class tag
typename OperatorClass,
/// Tag indicating architecture to tune for
typename ArchTag,
/// Threadblock-level tile size (concept: GemmShape)
typename ThreadblockShape,
/// Warp-level tile size (concept: GemmShape)
typename WarpShape,
/// Warp-level tile size (concept: GemmShape)
typename InstructionShape,
/// Epilogue output operator
typename EpilogueOutputOp,
/// Threadblock-level swizzling operator
typename ThreadblockSwizzle,
/// Number of stages used in the pipelined mainloop
int Stages,
/// If true, kernel is configured to support serial reduction in the
/// epilogue
bool SplitKSerial,
/// Operation performed by GEMM
typename Operator>
struct DefaultSparseGemmWithAbsmax {
using GemmBase = typename DefaultSparseGemm<
ElementA_, LayoutA_, kAlignmentA,
ElementB_, LayoutB_, kAlignmentB,
ElementC_, LayoutC_, ElementAccumulator,
OperatorClass,
ArchTag,
ThreadblockShape,
WarpShape,
InstructionShape,
EpilogueOutputOp,
ThreadblockSwizzle,
Stages,
SplitKSerial,
Operator
>::GemmKernel;
// Define epilogue
using Epilogue = typename cutlass::epilogue::threadblock::DefaultEpilogueWithAbsMax<
typename GemmBase::Epilogue::Shape,
typename GemmBase::Epilogue::WarpMmaOperator,
GemmBase::Epilogue::kPartitionsK,
ElementC_,
typename EpilogueOutputOp::ElementAuxOutput,
ElementC_,
EpilogueOutputOp,
GemmBase::Epilogue::kElementsPerAccess
>::Epilogue;
/// Define the kernel-level GEMM operator.
using GemmKernel = kernel::SparseGemmWithAbsmax<typename GemmBase::Mma, Epilogue, ThreadblockSwizzle, SplitKSerial>;
};
////////////////////////////////////////////////////////////////////////////////
} // namespace kernel
} // namespace gemm
} // namespace cutlass
@@ -0,0 +1,143 @@
/***************************************************************************************************
* Copyright (c) 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
Default configuration for a GEMM with fused absolute-maximum calculations and scaling
*/
#pragma once
#include "cutlass/cutlass.h"
#include "cutlass/gemm/kernel/gemm_with_absmax.h"
#include "cutlass/gemm/kernel/default_gemm_universal.h"
#include "cutlass/epilogue/threadblock/default_epilogue_with_absmax.h"
#include "cutlass/epilogue/threadblock/epilogue_with_absmax.h"
/////////////////////////////////////////////////////////////////////////////////////////////////
namespace cutlass {
namespace gemm {
namespace kernel {
/////////////////////////////////////////////////////////////////////////////////////////////////
template <
/// Element type for A matrix operand
typename ElementA_,
/// Layout type for A matrix operand
typename LayoutA_,
/// Complex elementwise transformation on A operand
ComplexTransform TransformA,
/// Access granularity of A matrix in units of elements
int kAlignmentA,
/// Element type for B matrix operand
typename ElementB_,
/// Layout type for B matrix operand
typename LayoutB_,
/// Complex elementwise transformation on B operand
ComplexTransform TransformB,
/// Access granularity of B matrix in units of elements
int kAlignmentB,
/// Element type for C and D matrix operands
typename ElementC_,
/// Layout type for C and D matrix operands
typename LayoutC_,
/// Element type for internal accumulation
typename ElementAccumulator,
/// Operator class tag
typename OperatorClass,
/// Tag indicating architecture to tune for
typename ArchTag,
/// Threadblock-level tile size (concept: GemmShape)
typename ThreadblockShape,
/// Warp-level tile size (concept: GemmShape)
typename WarpShape,
/// Warp-level tile size (concept: GemmShape)
typename InstructionShape,
/// Epilogue output operator
typename EpilogueOutputOp,
/// Threadblock-level swizzling operator
typename ThreadblockSwizzle,
/// Number of stages used in the pipelined mainloop
int Stages,
/// Operation performed by GEMM
typename Operator,
///
typename Enable = void
>
struct DefaultGemmWithAbsMax {
using GemmBase = typename DefaultGemmUniversal<
ElementA_, LayoutA_, TransformA, kAlignmentA,
ElementB_, LayoutB_, TransformB, kAlignmentB,
ElementC_, LayoutC_, ElementAccumulator,
OperatorClass,
ArchTag,
ThreadblockShape,
WarpShape,
InstructionShape,
EpilogueOutputOp,
ThreadblockSwizzle,
Stages,
Operator
>::GemmKernel;
// Define epilogue
using Epilogue = typename cutlass::epilogue::threadblock::DefaultEpilogueWithAbsMax<
typename GemmBase::Epilogue::Shape,
typename GemmBase::Epilogue::WarpMmaOperator,
GemmBase::Epilogue::kPartitionsK,
ElementC_,
typename EpilogueOutputOp::ElementAuxOutput,
ElementC_,
EpilogueOutputOp,
GemmBase::Epilogue::kElementsPerAccess
>::Epilogue;
// Compose the GEMM kernel
using GemmKernel = GemmWithAbsMax<
typename GemmBase::Mma,
Epilogue,
ThreadblockSwizzle
>;
};
/////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace kernel
} // namespace gemm
} // namespace cutlass
/////////////////////////////////////////////////////////////////////////////////////////////////
@@ -165,7 +165,7 @@ struct DefaultRank2KGrouped<ElementA, LayoutA, TransformA, kAlignmentA,
FillModeC, ElementAccumulator, OperatorClass, ArchTag, ThreadblockShape,
WarpShape, InstructionShape, EpilogueOutputOp,
ThreadblockSwizzle, Stages, Operator, BlasMode_, GroupScheduleMode_,
typename std::enable_if< ! cutlass::is_complex<ElementAccumulator>::value>::type
typename platform::enable_if< ! cutlass::is_complex<ElementAccumulator>::value>::type
> {
// If true, we must construct a 'transposed-and-exchanged' Rank2K operator.
static bool const kInternalTranspose = platform::is_same<LayoutC, layout::ColumnMajor>::value;
@@ -283,7 +283,7 @@ struct DefaultRank2KGrouped<ElementA, LayoutA, TransformA, kAlignmentA,
FillModeC, ElementAccumulator, OperatorClass, ArchTag, ThreadblockShape,
WarpShape, InstructionShape, EpilogueOutputOp,
ThreadblockSwizzle, Stages, Operator, BlasMode_, GroupScheduleMode_,
typename std::enable_if<cutlass::is_complex<ElementAccumulator>::value>::type
typename platform::enable_if<cutlass::is_complex<ElementAccumulator>::value>::type
> {
// If true, we must construct a 'transposed-and-exchanged' Rank2K operator.
static bool const kInternalTranspose = platform::is_same<LayoutC, layout::ColumnMajor>::value;
@@ -183,7 +183,7 @@ struct DefaultRank2KUniversal<
SplitKSerial,
Operator,
BlasMode::kSymmetric,
typename std::enable_if< ! cutlass::is_complex<ElementAccumulator>::value>::type
typename platform::enable_if< ! cutlass::is_complex<ElementAccumulator>::value>::type
> {
using DefaultRank2Kkernel = typename kernel::DefaultRank2K<
@@ -301,7 +301,7 @@ struct DefaultRank2KUniversal<
SplitKSerial,
Operator,
kBlasMode,
typename std::enable_if<cutlass::is_complex<ElementAccumulator>::value>::type
typename platform::enable_if<cutlass::is_complex<ElementAccumulator>::value>::type
> {
using DefaultRank2Kkernel = typename kernel::DefaultRank2KComplex<
@@ -165,7 +165,7 @@ struct DefaultRankKUniversal<
SplitKSerial,
Operator,
BlasMode::kSymmetric,
typename std::enable_if< ! cutlass::is_complex<ElementAccumulator>::value>::type
typename platform::enable_if< ! cutlass::is_complex<ElementAccumulator>::value>::type
> {
using DefaultRankKkernel = typename kernel::DefaultRankK<
@@ -265,7 +265,7 @@ struct DefaultRankKUniversal<
SplitKSerial,
Operator,
kBlasMode,
typename std::enable_if<cutlass::is_complex<ElementAccumulator>::value>::type
typename platform::enable_if<cutlass::is_complex<ElementAccumulator>::value>::type
> {
using DefaultRankKkernel = typename kernel::DefaultRankKComplex<
@@ -182,7 +182,7 @@ struct DefaultSymmUniversal<
SplitKSerial,
Operator,
BlasMode::kSymmetric,
typename std::enable_if< ! cutlass::is_complex<ElementAccumulator>::value>::type
typename platform::enable_if< ! cutlass::is_complex<ElementAccumulator>::value>::type
> {
using DefaultSymmkernel = typename kernel::DefaultSymm<
@@ -298,7 +298,7 @@ struct DefaultSymmUniversal<
SplitKSerial,
Operator,
kBlasMode,
typename std::enable_if<cutlass::is_complex<ElementAccumulator>::value>::type
typename platform::enable_if<cutlass::is_complex<ElementAccumulator>::value>::type
> {
using DefaultSymmkernel = typename kernel::DefaultSymmComplex<
@@ -190,7 +190,7 @@ struct DefaultTrmmUniversal<
Stages,
SplitKSerial,
Operator,
typename std::enable_if< ! cutlass::is_complex<ElementAccumulator>::value>::type
typename platform::enable_if< ! cutlass::is_complex<ElementAccumulator>::value>::type
> {
using DefaultTrmmKernel = typename kernel::DefaultTrmm<
@@ -311,7 +311,7 @@ struct DefaultTrmmUniversal<
Stages,
SplitKSerial,
Operator,
typename std::enable_if<cutlass::is_complex<ElementAccumulator>::value>::type
typename platform::enable_if<cutlass::is_complex<ElementAccumulator>::value>::type
> {
using DefaultTrmmKernel = typename kernel::DefaultTrmmComplex<
+41 -47
View File
@@ -73,32 +73,30 @@ struct EllGemm {
/// Parameters structure
struct Params {
cutlass::gemm::GemmCoord problem_size;
cutlass::gemm::GemmCoord grid_tiled_shape;
int swizzle_log_tile;
typename Mma::IteratorA::Params params_A;
typename Mma::IteratorA::TensorRef ref_A;
typename Mma::IteratorB::Params params_B;
typename Mma::IteratorB::TensorRef ref_B;
typename Epilogue::OutputTileIterator::Params params_C;
typename Epilogue::OutputTileIterator::TensorRef ref_C;
typename Epilogue::OutputTileIterator::Params params_D;
typename Epilogue::OutputTileIterator::TensorRef ref_D;
typename OutputOp::Params output_op;
int *semaphore;
int gemm_k_iterations;
int gemm_k_size;
const int* ell_idx;
int ell_ncol;
int ell_blocksize;
int ell_base_idx;
cutlass::gemm::GemmCoord problem_size{};
cutlass::gemm::GemmCoord grid_tiled_shape{};
int swizzle_log_tile{0};
typename Mma::IteratorA::Params params_A{};
typename Mma::IteratorA::TensorRef ref_A{};
typename Mma::IteratorB::Params params_B{};
typename Mma::IteratorB::TensorRef ref_B{};
typename Epilogue::OutputTileIterator::Params params_C{};
typename Epilogue::OutputTileIterator::TensorRef ref_C{};
typename Epilogue::OutputTileIterator::Params params_D{};
typename Epilogue::OutputTileIterator::TensorRef ref_D{};
typename OutputOp::Params output_op{};
int *semaphore = nullptr;
int gemm_k_iterations{0};
int gemm_k_size{0};
const int* ell_idx = nullptr;
int ell_ncol{0};
int ell_blocksize{0};
int ell_base_idx{0};
//
// Methods
//
CUTLASS_HOST_DEVICE
Params(): swizzle_log_tile(0), semaphore(0), gemm_k_iterations(0), gemm_k_size(0) { }
Params() = default;
CUTLASS_HOST_DEVICE
Params(
@@ -154,9 +152,7 @@ struct EllGemm {
//
// Methods
//
CUTLASS_HOST_DEVICE
EllGemm() { }
EllGemm() = default;
/// Determines whether kernel satisfies alignment
static Status can_implement(
@@ -458,32 +454,30 @@ struct EllGemm<Mma_, Epilogue_, ThreadblockSwizzle_, SplitKSerial, false> {
/// Parameters structure
struct Params {
cutlass::gemm::GemmCoord problem_size;
cutlass::gemm::GemmCoord grid_tiled_shape;
int swizzle_log_tile;
typename Mma::IteratorA::Params params_A;
typename Mma::IteratorA::TensorRef ref_A;
typename Mma::IteratorB::Params params_B;
typename Mma::IteratorB::TensorRef ref_B;
typename Epilogue::OutputTileIterator::Params params_C;
typename Epilogue::OutputTileIterator::TensorRef ref_C;
typename Epilogue::OutputTileIterator::Params params_D;
typename Epilogue::OutputTileIterator::TensorRef ref_D;
typename OutputOp::Params output_op;
int *semaphore;
int gemm_k_iterations;
int gemm_k_size;
const int* ell_idx;
int ell_ncol;
int ell_blocksize;
int ell_base_idx;
cutlass::gemm::GemmCoord problem_size{};
cutlass::gemm::GemmCoord grid_tiled_shape{};
int swizzle_log_tile{0};
typename Mma::IteratorA::Params params_A{};
typename Mma::IteratorA::TensorRef ref_A{};
typename Mma::IteratorB::Params params_B{};
typename Mma::IteratorB::TensorRef ref_B{};
typename Epilogue::OutputTileIterator::Params params_C{};
typename Epilogue::OutputTileIterator::TensorRef ref_C{};
typename Epilogue::OutputTileIterator::Params params_D{};
typename Epilogue::OutputTileIterator::TensorRef ref_D{};
typename OutputOp::Params output_op{};
int *semaphore = nullptr;
int gemm_k_iterations{0};
int gemm_k_size{0};
const int* ell_idx = nullptr;
int ell_ncol{0};
int ell_blocksize{0};
int ell_base_idx{0};
//
// Methods
//
CUTLASS_HOST_DEVICE
Params(): swizzle_log_tile(0), semaphore(0), gemm_k_iterations(0), gemm_k_size(0) { }
Params() = default;
CUTLASS_HOST_DEVICE
Params(
+21 -27
View File
@@ -65,31 +65,29 @@ struct GemmBatched {
/// Parameters structure
struct Params {
cutlass::gemm::GemmCoord problem_size;
cutlass::gemm::GemmCoord grid_tiled_shape;
int swizzle_log_tile;
typename Mma::IteratorA::Params params_A;
typename Mma::IteratorA::TensorRef ref_A;
int64_t stride_A;
typename Mma::IteratorB::Params params_B;
typename Mma::IteratorB::TensorRef ref_B;
int64_t stride_B;
typename Epilogue::OutputTileIterator::Params params_C;
typename Epilogue::OutputTileIterator::TensorRef ref_C;
int64_t stride_C;
typename Epilogue::OutputTileIterator::Params params_D;
typename Epilogue::OutputTileIterator::TensorRef ref_D;
int64_t stride_D;
typename OutputOp::Params epilogue;
int batch_count;
int gemm_k_iterations;
cutlass::gemm::GemmCoord problem_size{};
cutlass::gemm::GemmCoord grid_tiled_shape{};
int swizzle_log_tile{0};
typename Mma::IteratorA::Params params_A{};
typename Mma::IteratorA::TensorRef ref_A{};
int64_t stride_A{0};
typename Mma::IteratorB::Params params_B{};
typename Mma::IteratorB::TensorRef ref_B{};
int64_t stride_B{0};
typename Epilogue::OutputTileIterator::Params params_C{};
typename Epilogue::OutputTileIterator::TensorRef ref_C{};
int64_t stride_C{0};
typename Epilogue::OutputTileIterator::Params params_D{};
typename Epilogue::OutputTileIterator::TensorRef ref_D{};
int64_t stride_D{0};
typename OutputOp::Params epilogue{};
int batch_count{1};
int gemm_k_iterations{0};
//
// Methods
//
CUTLASS_HOST_DEVICE
Params() : swizzle_log_tile(0) { }
Params() = default;
CUTLASS_HOST_DEVICE
Params(
@@ -123,9 +121,7 @@ struct GemmBatched {
stride_D(stride_D_),
epilogue(epilogue_),
batch_count(batch_count_),
gemm_k_iterations((problem_size.k() + Mma::Shape::kK - 1) / Mma::Shape::kK) {
}
gemm_k_iterations((problem_size.k() + Mma::Shape::kK - 1) / Mma::Shape::kK) {}
};
/// Shared memory storage structure
@@ -137,9 +133,7 @@ struct GemmBatched {
//
// Methods
//
CUTLASS_HOST_DEVICE
GemmBatched() { }
GemmBatched() = default;
/// Executes one GEMM
CUTLASS_DEVICE
+27 -51
View File
@@ -133,46 +133,32 @@ public:
// Data members
//
GemmCoord *problem_sizes;
int problem_count;
int threadblock_count;
GemmCoord *problem_sizes{nullptr};
int problem_count{0};
int threadblock_count{0};
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
ElementA ** ptr_A;
ElementB ** ptr_B;
ElementC ** ptr_C;
ElementC ** ptr_D;
ElementA ** ptr_A{nullptr};
ElementB ** ptr_B{nullptr};
ElementC ** ptr_C{nullptr};
ElementC ** ptr_D{nullptr};
typename LayoutA::Stride::LongIndex *lda;
typename LayoutB::Stride::LongIndex *ldb;
typename LayoutC::Stride::LongIndex *ldc;
typename LayoutC::Stride::LongIndex *ldd;
typename LayoutA::Stride::LongIndex *lda{nullptr};
typename LayoutB::Stride::LongIndex *ldb{nullptr};
typename LayoutC::Stride::LongIndex *ldc{nullptr};
typename LayoutC::Stride::LongIndex *ldd{nullptr};
// Only used by device-level operator
GemmCoord *host_problem_sizes;
GemmCoord *host_problem_sizes{nullptr};
//
// Methods
//
/// Default ctor
CUTLASS_HOST_DEVICE
Arguments():
problem_count(0),
threadblock_count(0),
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
lda(nullptr),
ldb(nullptr),
ldc(nullptr),
ldd(nullptr),
host_problem_sizes(nullptr)
{
}
Arguments() = default;
/// Ctor
CUTLASS_HOST_DEVICE
@@ -216,36 +202,26 @@ public:
/// Parameters structure
struct Params {
typename ProblemVisitor::Params problem_visitor;
int threadblock_count;
typename ProblemVisitor::Params problem_visitor{};
int threadblock_count{0};
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
ElementA ** ptr_A;
ElementB ** ptr_B;
ElementC ** ptr_C;
ElementC ** ptr_D;
ElementA ** ptr_A{nullptr};
ElementB ** ptr_B{nullptr};
ElementC ** ptr_C{nullptr};
ElementC ** ptr_D{nullptr};
typename LayoutA::Stride::LongIndex *lda;
typename LayoutB::Stride::LongIndex *ldb;
typename LayoutC::Stride::LongIndex *ldc;
typename LayoutC::Stride::LongIndex *ldd;
typename LayoutA::Stride::LongIndex *lda{nullptr};
typename LayoutB::Stride::LongIndex *ldb{nullptr};
typename LayoutC::Stride::LongIndex *ldc{nullptr};
typename LayoutC::Stride::LongIndex *ldd{nullptr};
//
// Methods
//
CUTLASS_HOST_DEVICE
Params():
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
lda(nullptr),
ldb(nullptr),
ldc(nullptr),
ldd(nullptr)
{ }
Params() = default;
CUTLASS_HOST_DEVICE
Params(Arguments const &args,
@@ -135,50 +135,33 @@ public:
// Data members
//
GemmCoord *problem_sizes;
int problem_count;
int threadblock_count;
GemmCoord *problem_sizes{nullptr};
int problem_count{0};
int threadblock_count{0};
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
ElementA ** ptr_A;
ElementB ** ptr_B;
ElementC ** ptr_C;
ElementC ** ptr_D;
void ** ptr_norm;
void ** ptr_sum;
ElementA ** ptr_A{nullptr};
ElementB ** ptr_B{nullptr};
ElementC ** ptr_C{nullptr};
ElementC ** ptr_D{nullptr};
void ** ptr_norm{nullptr};
void ** ptr_sum{nullptr};
typename LayoutA::Stride::LongIndex *lda;
typename LayoutB::Stride::LongIndex *ldb;
typename LayoutC::Stride::LongIndex *ldc;
typename LayoutC::Stride::LongIndex *ldd;
typename LayoutA::Stride::LongIndex *lda{nullptr};
typename LayoutB::Stride::LongIndex *ldb{nullptr};
typename LayoutC::Stride::LongIndex *ldc{nullptr};
typename LayoutC::Stride::LongIndex *ldd{nullptr};
// Only used by device-level operator
GemmCoord *host_problem_sizes;
GemmCoord *host_problem_sizes{nullptr};
//
// Methods
//
/// Default ctor
CUTLASS_HOST_DEVICE
Arguments():
problem_count(0),
threadblock_count(0),
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
ptr_norm(nullptr),
ptr_sum(nullptr),
lda(nullptr),
ldb(nullptr),
ldc(nullptr),
ldd(nullptr),
host_problem_sizes(nullptr)
{
}
Arguments() = default;
/// Ctor
CUTLASS_HOST_DEVICE
@@ -226,41 +209,29 @@ public:
/// Parameters structure
struct Params {
typename ProblemVisitor::Params problem_visitor;
int threadblock_count;
typename ProblemVisitor::Params problem_visitor{};
int threadblock_count{0};
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
ElementA ** ptr_A;
ElementB ** ptr_B;
ElementC ** ptr_C;
ElementC ** ptr_D;
ElementA ** ptr_A{nullptr};
ElementB ** ptr_B{nullptr};
ElementC ** ptr_C{nullptr};
ElementC ** ptr_D{nullptr};
void ** ptr_norm;
void ** ptr_sum;
void ** ptr_norm{nullptr};
void ** ptr_sum{nullptr};
typename LayoutA::Stride::LongIndex *lda;
typename LayoutB::Stride::LongIndex *ldb;
typename LayoutC::Stride::LongIndex *ldc;
typename LayoutC::Stride::LongIndex *ldd;
typename LayoutA::Stride::LongIndex *lda{nullptr};
typename LayoutB::Stride::LongIndex *ldb{nullptr};
typename LayoutC::Stride::LongIndex *ldc{nullptr};
typename LayoutC::Stride::LongIndex *ldd{nullptr};
//
// Methods
//
CUTLASS_HOST_DEVICE
Params():
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
ptr_norm(nullptr),
ptr_sum(nullptr),
lda(nullptr),
ldb(nullptr),
ldc(nullptr),
ldd(nullptr)
{ }
Params() = default;
CUTLASS_HOST_DEVICE
Params(Arguments const &args,
@@ -111,59 +111,52 @@ public:
// Data members
//
typename EpilogueOutputOp::Params epilogue;
typename EpilogueOutputOp::Params epilogue{};
void const * ptr_A;
void const * ptr_B;
void const * ptr_var;
void const * ptr_mean;
void const * ptr_gamma;
void const * ptr_beta;
void const * ptr_C;
void * ptr_D;
void const * ptr_A{nullptr};
void const * ptr_B{nullptr};
void const * ptr_var{nullptr};
void const * ptr_mean{nullptr};
void const * ptr_gamma{nullptr};
void const * ptr_beta{nullptr};
void const * ptr_C{nullptr};
void * ptr_D{nullptr};
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_var;
int64_t batch_stride_mean;
int64_t batch_stride_gamma;
int64_t batch_stride_beta;
int64_t batch_stride_C;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
int64_t batch_stride_var{0};
int64_t batch_stride_mean{0};
int64_t batch_stride_gamma{0};
int64_t batch_stride_beta{0};
int64_t batch_stride_C{0};
typename LayoutA::Stride stride_a;
typename LayoutB::Stride stride_b;
typename LayoutScaleBias::Stride stride_var;
typename LayoutScaleBias::Stride stride_mean;
typename LayoutScaleBias::Stride stride_gamma;
typename LayoutScaleBias::Stride stride_beta;
typename LayoutC::Stride stride_c;
typename LayoutC::Stride stride_d;
typename LayoutA::Stride stride_a{};
typename LayoutB::Stride stride_b{};
typename LayoutScaleBias::Stride stride_var{};
typename LayoutScaleBias::Stride stride_mean{};
typename LayoutScaleBias::Stride stride_gamma{};
typename LayoutScaleBias::Stride stride_beta{};
typename LayoutC::Stride stride_c{};
typename LayoutC::Stride stride_d{};
typename LayoutA::Stride::LongIndex lda;
typename LayoutB::Stride::LongIndex ldb;
typename LayoutScaleBias::Stride::LongIndex ld_var;
typename LayoutScaleBias::Stride::LongIndex ld_mean;
typename LayoutScaleBias::Stride::LongIndex ld_gamma;
typename LayoutScaleBias::Stride::LongIndex ld_beta;
typename LayoutC::Stride::LongIndex ldc;
typename LayoutC::Stride::LongIndex ldd;
typename LayoutA::Stride::LongIndex lda{};
typename LayoutB::Stride::LongIndex ldb{};
typename LayoutScaleBias::Stride::LongIndex ld_var{};
typename LayoutScaleBias::Stride::LongIndex ld_mean{};
typename LayoutScaleBias::Stride::LongIndex ld_gamma{};
typename LayoutScaleBias::Stride::LongIndex ld_beta{};
typename LayoutC::Stride::LongIndex ldc{};
typename LayoutC::Stride::LongIndex ldd{};
int const * ptr_gather_A_indices;
int const * ptr_gather_B_indices;
int const * ptr_scatter_D_indices;
int const * ptr_gather_A_indices{nullptr};
int const * ptr_gather_B_indices{nullptr};
int const * ptr_scatter_D_indices{nullptr};
//
// Methods
//
Arguments():
ptr_A(nullptr), ptr_B(nullptr), ptr_C(nullptr), ptr_D(nullptr),
ptr_var(nullptr), ptr_mean(nullptr),
ptr_gamma(nullptr), ptr_beta(nullptr),
ptr_gather_A_indices(nullptr),
ptr_gather_B_indices(nullptr),
ptr_scatter_D_indices(nullptr)
{}
Arguments() = default;
/// constructs an arguments structure
Arguments(
+20 -30
View File
@@ -70,46 +70,36 @@ struct GemmParams {
// Data members
//
cutlass::gemm::GemmCoord problem_size;
cutlass::gemm::GemmCoord grid_tiled_shape;
int swizzle_log_tile;
cutlass::gemm::GemmCoord problem_size{};
cutlass::gemm::GemmCoord grid_tiled_shape{};
int swizzle_log_tile{};
// Data members for Mma::Iterator::Params
MmaIteratorParams params_itr_a;
MmaIteratorParams params_itr_b;
GemmUniversalMode mode{GemmUniversalMode::kGemm};
int batch_count{1};
int gemm_k_size{0};
// Data member for Epilogue::OutputTileIterator::Params
EpilogueIteratorParams params_itr_c;
EpilogueIteratorParams params_itr_d;
void * ptr_A{nullptr};
void * ptr_B{nullptr};
void * ptr_C{nullptr};
void * ptr_D{nullptr};
LongIndex lda{0};
LongIndex ldb{0};
LongIndex ldc{0};
LongIndex ldd{0};
GemmUniversalMode mode;
int batch_count;
int gemm_k_size;
LongIndex batch_stride_A{0};
LongIndex batch_stride_B{0};
LongIndex batch_stride_C{0};
LongIndex batch_stride_D{0};
void * ptr_A;
void * ptr_B;
void * ptr_C;
void * ptr_D;
LongIndex lda;
LongIndex ldb;
LongIndex ldc;
LongIndex ldd;
LongIndex batch_stride_A;
LongIndex batch_stride_B;
LongIndex batch_stride_C;
LongIndex batch_stride_D;
int *semaphore;
int *semaphore{nullptr};
//
// Methods
//
CUTLASS_HOST_DEVICE
GemmParams() {}
GemmParams() = default;
CUTLASS_HOST_DEVICE
GemmParams(
@@ -112,51 +112,39 @@ public:
// Data members
//
typename EpilogueOutputOp::Params epilogue;
typename EpilogueOutputOp::Params epilogue{};
void const * ptr_A_real;
void const * ptr_A_imag;
void const * ptr_A_real{nullptr};
void const * ptr_A_imag{nullptr};
void const * ptr_B_real{nullptr};
void const * ptr_B_imag{nullptr};
void const * ptr_C_real{nullptr};
void const * ptr_C_imag{nullptr};
void * ptr_D_real{nullptr};
void * ptr_D_imag{nullptr};
void const * ptr_B_real;
void const * ptr_B_imag;
void const * ptr_C_real;
void const * ptr_C_imag;
void * ptr_D_real;
void * ptr_D_imag;
typename LayoutA::Stride::Index lda_real;
typename LayoutA::Stride::Index lda_imag;
typename LayoutB::Stride::Index ldb_real;
typename LayoutB::Stride::Index ldb_imag;
typename LayoutC::Stride::Index ldc_real;
typename LayoutC::Stride::Index ldc_imag;
typename LayoutC::Stride::Index ldd_real;
typename LayoutC::Stride::Index ldd_imag;
typename LayoutA::Stride::Index lda_real{};
typename LayoutA::Stride::Index lda_imag{};
typename LayoutB::Stride::Index ldb_real{};
typename LayoutB::Stride::Index ldb_imag{};
typename LayoutC::Stride::Index ldc_real{};
typename LayoutC::Stride::Index ldc_imag{};
typename LayoutC::Stride::Index ldd_real{};
typename LayoutC::Stride::Index ldd_imag{};
int64_t batch_stride_A;
int64_t batch_stride_A_imag;
int64_t batch_stride_B;
int64_t batch_stride_B_imag;
int64_t batch_stride_C;
int64_t batch_stride_C_imag;
int64_t batch_stride_D_imag;
int64_t batch_stride_A{0};
int64_t batch_stride_A_imag{0};
int64_t batch_stride_B{0};
int64_t batch_stride_B_imag{0};
int64_t batch_stride_C{0};
int64_t batch_stride_C_imag{0};
int64_t batch_stride_D_imag{0};
//
// Methods
//
Arguments() :
ptr_A_real(nullptr),
ptr_A_imag(nullptr),
ptr_B_real(nullptr),
ptr_B_imag(nullptr),
ptr_C_real(nullptr),
ptr_C_imag(nullptr),
ptr_D_real(nullptr),
ptr_D_imag(nullptr)
{}
Arguments() = default;
/// constructs an arguments structure
Arguments(
@@ -260,34 +248,34 @@ public:
// Data members
//
typename Mma::IteratorA::Params params_A_real;
typename Mma::IteratorA::Params params_A_imag;
typename Mma::IteratorB::Params params_B_real;
typename Mma::IteratorB::Params params_B_imag;
typename Epilogue::OutputTileIterator::Params params_C_real;
typename Epilogue::OutputTileIterator::Params params_C_imag;
typename Epilogue::OutputTileIterator::Params params_D_real;
typename Epilogue::OutputTileIterator::Params params_D_imag;
typename Mma::IteratorA::Params params_A_real{};
typename Mma::IteratorA::Params params_A_imag{};
typename Mma::IteratorB::Params params_B_real{};
typename Mma::IteratorB::Params params_B_imag{};
typename Epilogue::OutputTileIterator::Params params_C_real{};
typename Epilogue::OutputTileIterator::Params params_C_imag{};
typename Epilogue::OutputTileIterator::Params params_D_real{};
typename Epilogue::OutputTileIterator::Params params_D_imag{};
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
void * ptr_A_real;
void * ptr_A_imag;
void * ptr_B_real;
void * ptr_B_imag;
void * ptr_C_real;
void * ptr_C_imag;
void * ptr_D_real;
void * ptr_D_imag;
void * ptr_A_real{nullptr};
void * ptr_A_imag{nullptr};
void * ptr_B_real{nullptr};
void * ptr_B_imag{nullptr};
void * ptr_C_real{nullptr};
void * ptr_C_imag{nullptr};
void * ptr_D_real{nullptr};
void * ptr_D_imag{nullptr};
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_C;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
int64_t batch_stride_C{0};
int64_t batch_stride_A_imag;
int64_t batch_stride_B_imag;
int64_t batch_stride_C_imag;
int64_t batch_stride_D_imag;
int64_t batch_stride_A_imag{0};
int64_t batch_stride_B_imag{0};
int64_t batch_stride_C_imag{0};
int64_t batch_stride_D_imag{0};
//
// Host dispatch API
@@ -112,50 +112,38 @@ public:
// Data members
//
typename EpilogueOutputOp::Params epilogue;
typename EpilogueOutputOp::Params epilogue{};
int const *ptr_M;
int const *ptr_N;
int const *ptr_K;
int const *ptr_M{nullptr};
int const *ptr_N{nullptr};
int const *ptr_K{nullptr};
void const * const * ptr_A_real;
void const * const * ptr_A_imag;
void const * const * ptr_A_real{nullptr};
void const * const * ptr_A_imag{nullptr};
void const * const * ptr_B_real;
void const * const * ptr_B_imag;
void const * const * ptr_B_real{nullptr};
void const * const * ptr_B_imag{nullptr};
void const * const * ptr_C_real;
void const * const * ptr_C_imag;
void const * const * ptr_C_real{nullptr};
void const * const * ptr_C_imag{nullptr};
void * const * ptr_D_real;
void * const * ptr_D_imag;
void * const * ptr_D_real{nullptr};
void * const * ptr_D_imag{nullptr};
typename LayoutA::Stride::Index lda_real;
typename LayoutA::Stride::Index lda_imag;
typename LayoutB::Stride::Index ldb_real;
typename LayoutB::Stride::Index ldb_imag;
typename LayoutC::Stride::Index ldc_real;
typename LayoutC::Stride::Index ldc_imag;
typename LayoutC::Stride::Index ldd_real;
typename LayoutC::Stride::Index ldd_imag;
typename LayoutA::Stride::Index lda_real{};
typename LayoutA::Stride::Index lda_imag{};
typename LayoutB::Stride::Index ldb_real{};
typename LayoutB::Stride::Index ldb_imag{};
typename LayoutC::Stride::Index ldc_real{};
typename LayoutC::Stride::Index ldc_imag{};
typename LayoutC::Stride::Index ldd_real{};
typename LayoutC::Stride::Index ldd_imag{};
//
// Methods
//
Arguments():
ptr_M(nullptr),
ptr_N(nullptr),
ptr_K(nullptr),
ptr_A_real(nullptr),
ptr_A_imag(nullptr),
ptr_B_real(nullptr),
ptr_B_imag(nullptr),
ptr_C_real(nullptr),
ptr_C_imag(nullptr),
ptr_D_real(nullptr),
ptr_D_imag(nullptr)
{}
Arguments() = default;
/// constructs an arguments structure
Arguments(
@@ -248,29 +236,29 @@ public:
// Data members
//
typename Mma::IteratorA::Params params_A_real;
typename Mma::IteratorA::Params params_A_imag;
typename Mma::IteratorB::Params params_B_real;
typename Mma::IteratorB::Params params_B_imag;
typename Epilogue::OutputTileIterator::Params params_C_real;
typename Epilogue::OutputTileIterator::Params params_C_imag;
typename Epilogue::OutputTileIterator::Params params_D_real;
typename Epilogue::OutputTileIterator::Params params_D_imag;
typename Mma::IteratorA::Params params_A_real{};
typename Mma::IteratorA::Params params_A_imag{};
typename Mma::IteratorB::Params params_B_real{};
typename Mma::IteratorB::Params params_B_imag{};
typename Epilogue::OutputTileIterator::Params params_C_real{};
typename Epilogue::OutputTileIterator::Params params_C_imag{};
typename Epilogue::OutputTileIterator::Params params_D_real{};
typename Epilogue::OutputTileIterator::Params params_D_imag{};
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
int const *ptr_M;
int const *ptr_N;
int const *ptr_K;
int const *ptr_M{nullptr};
int const *ptr_N{nullptr};
int const *ptr_K{nullptr};
void const * const * ptr_A_real;
void const * const * ptr_A_imag;
void const * const * ptr_B_real;
void const * const * ptr_B_imag;
void const * const * ptr_C_real;
void const * const * ptr_C_imag;
void * const * ptr_D_real;
void * const * ptr_D_imag;
void const * const * ptr_A_real{nullptr};
void const * const * ptr_A_imag{nullptr};
void const * const * ptr_B_real{nullptr};
void const * const * ptr_B_imag{nullptr};
void const * const * ptr_C_real{nullptr};
void const * const * ptr_C_imag{nullptr};
void * const * ptr_D_real{nullptr};
void * const * ptr_D_imag{nullptr};
//
// Host dispatch API
@@ -29,7 +29,7 @@
*
**************************************************************************************************/
/*! \file
\brief Stream-K Gemm kernel compatible with fused epilogues
\brief Stream-K Gemm kernel compatible with fused epilogues
that broadcast a bias vector over the MMA output.
*/
@@ -65,7 +65,7 @@ struct GemmStreamkWithFusedEpilogue;
// GemmStreamkWithFusedEpilogue with two sources
template <
typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Epilogue_, ///! Epilogue
typename ThreadblockSwizzle_ ///! Threadblock swizzling function
>
@@ -126,55 +126,46 @@ struct GemmStreamkWithFusedEpilogue<Mma_, Epilogue_, ThreadblockSwizzle_, false>
// Data members
//
GemmUniversalMode mode;
GemmCoord problem_size;
int batch_count; // Either (mode == GemmUniversalMode::kBatched) the batch count, or (mode == GemmUniversalMode::kGemm) the tile-splitting factor
GemmUniversalMode mode{GemmUniversalMode::kGemm};
GemmCoord problem_size{};
int batch_count{1}; // Either (mode == GemmUniversalMode::kBatched) the batch count, or (mode == GemmUniversalMode::kGemm) the tile-splitting factor
typename EpilogueOutputOp::Params epilogue;
typename EpilogueOutputOp::Params epilogue{};
void const * ptr_A;
void const * ptr_B;
void const * ptr_C1;
void const * ptr_C2;
void * ptr_D;
void const * ptr_A{nullptr};
void const * ptr_B{nullptr};
void const * ptr_C1{nullptr};
void const * ptr_C2{nullptr};
void * ptr_D{nullptr};
void * ptr_Vector;
void * ptr_Tensor;
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_C1;
int64_t batch_stride_C2;
int64_t batch_stride_D;
int64_t batch_stride_Vector;
int64_t batch_stride_Tensor;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
int64_t batch_stride_C1{0};
int64_t batch_stride_C2{0};
int64_t batch_stride_D{0};
int64_t batch_stride_Vector{0};
int64_t batch_stride_Tensor{0};
typename LayoutA::Stride::Index lda;
typename LayoutB::Stride::Index ldb;
typename LayoutC::Stride::Index ldc1;
typename LayoutC::Stride::Index ldc2;
typename LayoutC::Stride::Index ldd;
typename LayoutC::Stride::Index ldr;
typename LayoutC::Stride::Index ldt;
typename LayoutA::Stride::Index lda{};
typename LayoutB::Stride::Index ldb{};
typename LayoutC::Stride::Index ldc1{};
typename LayoutC::Stride::Index ldc2{};
typename LayoutC::Stride::Index ldd{};
typename LayoutC::Stride::Index ldr{};
typename LayoutC::Stride::Index ldt{};
int avail_sms; /// The number of SMs that StreamK dispatch heuristics will attempt to load-balance across (-1 defaults to device width, 1 implies classic data-parallel scheduling)
int avail_sms{-1}; /// The number of SMs that StreamK dispatch heuristics will attempt to load-balance across (-1 defaults to device width, 1 implies classic data-parallel scheduling)
//
// Methods
//
/// Default Constructor
Arguments():
mode(GemmUniversalMode::kGemm),
batch_count(1),
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C1(nullptr),
ptr_C2(nullptr),
ptr_D(nullptr),
avail_sms(-1)
{}
Arguments() = default;
/// constructs an arguments structure
Arguments(
@@ -208,14 +199,14 @@ struct GemmStreamkWithFusedEpilogue<Mma_, Epilogue_, ThreadblockSwizzle_, false>
mode(mode),
problem_size(problem_size),
batch_count(batch_split),
epilogue(epilogue),
ptr_A(ptr_A), ptr_B(ptr_B), ptr_C1(ptr_C1), ptr_C2(ptr_C2), ptr_D(ptr_D),
ptr_Vector(ptr_Vector),
epilogue(epilogue),
ptr_A(ptr_A), ptr_B(ptr_B), ptr_C1(ptr_C1), ptr_C2(ptr_C2), ptr_D(ptr_D),
ptr_Vector(ptr_Vector),
ptr_Tensor(ptr_Tensor),
batch_stride_A(batch_stride_A),
batch_stride_B(batch_stride_B),
batch_stride_C1(batch_stride_C1),
batch_stride_C2(batch_stride_C2),
batch_stride_A(batch_stride_A),
batch_stride_B(batch_stride_B),
batch_stride_C1(batch_stride_C1),
batch_stride_C2(batch_stride_C2),
batch_stride_Vector(batch_stride_Vector),
batch_stride_Tensor(batch_stride_Tensor),
lda(lda), ldb(ldb), ldc1(ldc1), ldc2(ldc2), ldd(ldd), ldr(ldr), ldt(ldt), avail_sms(avail_sms)
@@ -251,42 +242,42 @@ struct GemmStreamkWithFusedEpilogue<Mma_, Epilogue_, ThreadblockSwizzle_, false>
// Data members
//
void * ptr_A;
void * ptr_B;
void * ptr_A{nullptr};
void * ptr_B{nullptr};
typename Mma::IteratorA::Params params_A;
typename Mma::IteratorB::Params params_B;
typename Mma::IteratorA::Params params_A{};
typename Mma::IteratorB::Params params_B{};
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
GemmUniversalMode mode;
GemmUniversalMode mode{GemmUniversalMode::kGemm};
ThreadblockSwizzle block_mapping;
ThreadblockSwizzle block_mapping{};
void *barrier_workspace;
void *partials_workspace;
void *barrier_workspace{nullptr};
void *partials_workspace{nullptr};
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
void * ptr_C1;
void * ptr_C2;
void * ptr_D;
void * ptr_Tensor;
void * ptr_Vector;
void * ptr_C1{nullptr};
void * ptr_C2{nullptr};
void * ptr_D{nullptr};
void * ptr_Tensor{nullptr};
void * ptr_Vector{nullptr};
typename Epilogue::OutputTileIterator::Params params_C1;
typename Epilogue::OutputTileIterator::Params params_C2;
typename Epilogue::OutputTileIterator::Params params_D;
typename Epilogue::TensorTileIterator::Params params_Tensor;
typename Epilogue::OutputTileIterator::Params params_C1{};
typename Epilogue::OutputTileIterator::Params params_C2{};
typename Epilogue::OutputTileIterator::Params params_D{};
typename Epilogue::TensorTileIterator::Params params_Tensor{};
int64_t batch_stride_C1;
int64_t batch_stride_C2;
int64_t batch_stride_D;
int64_t batch_stride_Vector;
int64_t batch_stride_Tensor;
int64_t batch_stride_C1{0};
int64_t batch_stride_C2{0};
int64_t batch_stride_D{0};
int64_t batch_stride_Vector{0};
int64_t batch_stride_Tensor{0};
typename LayoutC::Stride::Index ldr;
typename LayoutC::Stride::Index ldr{};
protected:
@@ -361,17 +352,17 @@ struct GemmStreamkWithFusedEpilogue<Mma_, Epilogue_, ThreadblockSwizzle_, false>
barrier_workspace(nullptr),
partials_workspace(nullptr)
{
CUTLASS_TRACE_HOST("GemmStreamkWithFusedEpilogue::Params::Params() - problem_size: " << problem_size);
CUTLASS_TRACE_HOST("GemmStreamkWithFusedEpilogue::Params::Params()");
CUTLASS_TRACE_HOST(" ptr_Vector: " << (void *)this->ptr_Vector);
CUTLASS_TRACE_HOST(" ptr_Tensor: " << (void *)this->ptr_Tensor);
CUTLASS_TRACE_HOST(" ldr: " << this->ldr);
CUTLASS_TRACE_HOST(" ldt: " << args.ldt);
CUTLASS_TRACE_HOST(" avail_sms: " << avail_sms);
// Number of SMs to make available for StreamK decomposition
int avail_sms = (args.avail_sms == -1) ?
device_sms :
fast_min(args.avail_sms, device_sms);
CUTLASS_TRACE_HOST(" avail_sms: " << avail_sms);
// Initialize the block mapping structure
block_mapping = ThreadblockSwizzle(
@@ -404,7 +395,6 @@ struct GemmStreamkWithFusedEpilogue<Mma_, Epilogue_, ThreadblockSwizzle_, false>
{
uint8_t *ptr = static_cast<uint8_t*>(workspace);
// Establish partials workspace
partials_workspace = nullptr;
size_t partials_workspace_bytes = get_partials_workspace_size();
@@ -840,7 +830,7 @@ protected:
typename Epilogue::ElementTensor *ptr_Tensor = static_cast<typename Epilogue::ElementTensor *>(params.ptr_Tensor);
// Define the reduction output pointer and move to the appropriate place
typename Epilogue::ElementVector *ptr_Vector =
typename Epilogue::ElementVector *ptr_Vector =
static_cast<typename Epilogue::ElementVector *>(params.ptr_Vector);
// Update pointers for batched/array mode(s)
@@ -969,7 +959,7 @@ protected:
typename Epilogue::ElementTensor *ptr_Tensor = static_cast<typename Epilogue::ElementTensor *>(params.ptr_Tensor);
// Define the reduction output pointer and move to the appropriate place
typename Epilogue::ElementVector *ptr_Vector =
typename Epilogue::ElementVector *ptr_Vector =
static_cast<typename Epilogue::ElementVector *>(params.ptr_Vector);
// Tile iterator loading from residual1.
@@ -1256,7 +1246,7 @@ public:
// GemmStreamkWithFusedEpilogue with one source
template <
typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Epilogue_, ///! Epilogue
typename ThreadblockSwizzle_ ///! Threadblock swizzling function
>
@@ -1318,51 +1308,43 @@ struct GemmStreamkWithFusedEpilogue<Mma_, Epilogue_, ThreadblockSwizzle_, true>
// Data members
//
GemmUniversalMode mode;
GemmCoord problem_size;
int batch_count; // Either (mode == GemmUniversalMode::kBatched) the batch count, or (mode == GemmUniversalMode::kGemm) the tile-splitting factor
GemmUniversalMode mode{GemmUniversalMode::kGemm};
GemmCoord problem_size{};
int batch_count{1}; // Either (mode == GemmUniversalMode::kBatched) the batch count, or (mode == GemmUniversalMode::kGemm) the tile-splitting factor
typename EpilogueOutputOp::Params epilogue;
typename EpilogueOutputOp::Params epilogue{};
void const * ptr_A;
void const * ptr_B;
void const * ptr_C;
void * ptr_D;
void const * ptr_A{nullptr};
void const * ptr_B{nullptr};
void const * ptr_C{nullptr};
void * ptr_D{nullptr};
void * ptr_Vector;
void * ptr_Tensor;
void * ptr_Vector{nullptr};
void * ptr_Tensor{nullptr};
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_C;
int64_t batch_stride_D;
int64_t batch_stride_Vector;
int64_t batch_stride_Tensor;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
int64_t batch_stride_C{0};
int64_t batch_stride_D{0};
int64_t batch_stride_Vector{0};
int64_t batch_stride_Tensor{0};
typename LayoutA::Stride::Index lda;
typename LayoutB::Stride::Index ldb;
typename LayoutC::Stride::Index ldc;
typename LayoutC::Stride::Index ldd;
typename LayoutC::Stride::Index ldr;
typename LayoutC::Stride::Index ldt;
typename LayoutA::Stride::Index lda{};
typename LayoutB::Stride::Index ldb{};
typename LayoutC::Stride::Index ldc{};
typename LayoutC::Stride::Index ldd{};
typename LayoutC::Stride::Index ldr{};
typename LayoutC::Stride::Index ldt{};
int avail_sms; /// The number of SMs that StreamK dispatch heuristics will attempt to load-balance across (-1 defaults to device width, 1 implies classic data-parallel scheduling)
int avail_sms{-1}; /// The number of SMs that StreamK dispatch heuristics will attempt to load-balance across (-1 defaults to device width, 1 implies classic data-parallel scheduling)
//
// Methods
//
/// Default Constructor
Arguments():
mode(GemmUniversalMode::kGemm),
batch_count(1),
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
avail_sms(-1)
{}
Arguments() = default;
/// constructs an arguments structure
Arguments(
@@ -1393,13 +1375,13 @@ struct GemmStreamkWithFusedEpilogue<Mma_, Epilogue_, ThreadblockSwizzle_, true>
mode(mode),
problem_size(problem_size),
batch_count(batch_split),
epilogue(epilogue),
ptr_A(ptr_A), ptr_B(ptr_B), ptr_C(ptr_C), ptr_D(ptr_D),
ptr_Vector(ptr_Vector),
epilogue(epilogue),
ptr_A(ptr_A), ptr_B(ptr_B), ptr_C(ptr_C), ptr_D(ptr_D),
ptr_Vector(ptr_Vector),
ptr_Tensor(ptr_Tensor),
batch_stride_A(batch_stride_A),
batch_stride_B(batch_stride_B),
batch_stride_C(batch_stride_C),
batch_stride_A(batch_stride_A),
batch_stride_B(batch_stride_B),
batch_stride_C(batch_stride_C),
batch_stride_Vector(batch_stride_Vector),
batch_stride_Tensor(batch_stride_Tensor),
lda(lda), ldb(ldb), ldc(ldc), ldd(ldd), ldr(ldr), ldt(ldt), avail_sms(avail_sms)
@@ -1415,7 +1397,7 @@ struct GemmStreamkWithFusedEpilogue<Mma_, Epilogue_, ThreadblockSwizzle_, true>
/// Returns arguments for the transposed problem
Arguments transposed_problem() const {
Arguments args(*this);
std::swap(args.problem_size.m(), args.problem_size.n());
std::swap(args.ptr_A, args.ptr_B);
std::swap(args.lda, args.ldb);
@@ -1436,40 +1418,39 @@ struct GemmStreamkWithFusedEpilogue<Mma_, Epilogue_, ThreadblockSwizzle_, true>
// Data members
//
void * ptr_A;
void * ptr_B;
void * ptr_A{nullptr};
void * ptr_B{nullptr};
typename Mma::IteratorA::Params params_A;
typename Mma::IteratorB::Params params_B;
typename Mma::IteratorA::Params params_A{};
typename Mma::IteratorB::Params params_B{};
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
GemmUniversalMode mode;
GemmUniversalMode mode{GemmUniversalMode::kGemm};
ThreadblockSwizzle block_mapping;
ThreadblockSwizzle block_mapping{};
void *barrier_workspace;
void *partials_workspace;
void *barrier_workspace{nullptr};
void *partials_workspace{nullptr};
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
void * ptr_C;
void * ptr_D;
void * ptr_Tensor;
void * ptr_Vector;
void * ptr_C{nullptr};
void * ptr_D{nullptr};
void * ptr_Tensor{nullptr};
void * ptr_Vector{nullptr};
typename Epilogue::OutputTileIterator::Params params_C;
typename Epilogue::OutputTileIterator::Params params_D;
typename Epilogue::TensorTileIterator::Params params_Tensor;
typename Epilogue::OutputTileIterator::Params params_C{};
typename Epilogue::OutputTileIterator::Params params_D{};
typename Epilogue::TensorTileIterator::Params params_Tensor{};
int64_t batch_stride_C;
int64_t batch_stride_D;
int64_t batch_stride_Vector;
int64_t batch_stride_Tensor;
int64_t batch_stride_C{0};
int64_t batch_stride_D{0};
int64_t batch_stride_Vector{0};
int64_t batch_stride_Tensor{0};
typename LayoutC::Stride::Index ldr;
typename LayoutC::Stride::Index ldr{};
protected:
@@ -1540,17 +1521,17 @@ struct GemmStreamkWithFusedEpilogue<Mma_, Epilogue_, ThreadblockSwizzle_, true>
barrier_workspace(nullptr),
partials_workspace(nullptr)
{
CUTLASS_TRACE_HOST("GemmStreamkWithFusedEpilogue::Params::Params() - problem_size: " << problem_size);
CUTLASS_TRACE_HOST("GemmStreamkWithFusedEpilogue::Params::Params()");
CUTLASS_TRACE_HOST(" ptr_Vector: " << (void *)this->ptr_Vector);
CUTLASS_TRACE_HOST(" ptr_Tensor: " << (void *)this->ptr_Tensor);
CUTLASS_TRACE_HOST(" ldr: " << this->ldr);
CUTLASS_TRACE_HOST(" ldt: " << args.ldt);
CUTLASS_TRACE_HOST(" avail_sms: " << avail_sms);
// Number of SMs to make available for StreamK decomposition
int avail_sms = (args.avail_sms == -1) ?
device_sms :
fast_min(args.avail_sms, device_sms);
CUTLASS_TRACE_HOST(" avail_sms: " << avail_sms);
// Initialize the block mapping structure
block_mapping = ThreadblockSwizzle(
@@ -2018,7 +1999,7 @@ protected:
typename Epilogue::ElementTensor *ptr_Tensor = static_cast<typename Epilogue::ElementTensor *>(params.ptr_Tensor);
// Define the reduction output pointer and move to the appropriate place
typename Epilogue::ElementVector *ptr_Vector =
typename Epilogue::ElementVector *ptr_Vector =
static_cast<typename Epilogue::ElementVector *>(params.ptr_Vector);
// Update pointers for batched/array mode(s)
@@ -2131,7 +2112,7 @@ protected:
typename Epilogue::ElementTensor *ptr_Tensor = static_cast<typename Epilogue::ElementTensor *>(params.ptr_Tensor);
// Define the reduction output pointer and move to the appropriate place
typename Epilogue::ElementVector *ptr_Vector =
typename Epilogue::ElementVector *ptr_Vector =
static_cast<typename Epilogue::ElementVector *>(params.ptr_Vector);
// Tile iterator loading from source tensor.
@@ -122,33 +122,33 @@ public:
// Data members
//
GemmUniversalMode mode;
GemmCoord problem_size;
int batch_count; // Either (mode == GemmUniversalMode::kBatched) the batch count, or (mode == GemmUniversalMode::kGemm) the tile-splitting factor
GemmUniversalMode mode = GemmUniversalMode::kGemm;
GemmCoord problem_size {};
int batch_count {1}; // Either (mode == GemmUniversalMode::kBatched) the batch count, or (mode == GemmUniversalMode::kGemm) the tile-splitting factor
typename EpilogueOutputOp::Params epilogue;
typename EpilogueOutputOp::Params epilogue{};
void const * ptr_A;
void const * ptr_B;
void const * ptr_C;
void * ptr_D;
void const * ptr_A = nullptr;
void const * ptr_B = nullptr;
void const * ptr_C = nullptr;
void * ptr_D = nullptr;
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_C;
int64_t batch_stride_D;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
int64_t batch_stride_C{0};
int64_t batch_stride_D{0};
typename LayoutA::Stride stride_a;
typename LayoutB::Stride stride_b;
typename LayoutC::Stride stride_c;
typename LayoutC::Stride stride_d;
typename LayoutA::Stride stride_a{0};
typename LayoutB::Stride stride_b{0};
typename LayoutC::Stride stride_c{0};
typename LayoutC::Stride stride_d{0};
typename LayoutA::Stride::LongIndex lda;
typename LayoutB::Stride::LongIndex ldb;
typename LayoutC::Stride::LongIndex ldc;
typename LayoutC::Stride::LongIndex ldd;
typename LayoutA::Stride::LongIndex lda{0};
typename LayoutB::Stride::LongIndex ldb{0};
typename LayoutC::Stride::LongIndex ldc{0};
typename LayoutC::Stride::LongIndex ldd{0};
int avail_sms; /// The number of SMs that StreamK dispatch heuristics will attempt to load-balance across (-1 defaults to device width, 1 implies classic data-parallel scheduling)
int avail_sms{-1}; /// The number of SMs that StreamK dispatch heuristics will attempt to load-balance across (-1 defaults to device width, 1 implies classic data-parallel scheduling)
//
@@ -156,15 +156,7 @@ public:
//
/// Default Constructor
Arguments():
mode(GemmUniversalMode::kGemm),
batch_count(1),
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
avail_sms(-1)
{}
Arguments() = default;
/// Constructor
Arguments(
@@ -257,32 +249,32 @@ public:
// Data members
//
void * ptr_A;
void * ptr_B;
void * ptr_A = nullptr;
void * ptr_B = nullptr;
typename Mma::IteratorA::Params params_A;
typename Mma::IteratorB::Params params_B;
typename Mma::IteratorA::Params params_A{};
typename Mma::IteratorB::Params params_B{};
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
GemmUniversalMode mode;
GemmUniversalMode mode = GemmUniversalMode::kGemm;
ThreadblockSwizzle block_mapping;
ThreadblockSwizzle block_mapping{};
void *barrier_workspace;
void *partials_workspace;
void *barrier_workspace = nullptr;
void *partials_workspace = nullptr;
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
void * ptr_D;
void * ptr_C;
void * ptr_D = nullptr;
void * ptr_C = nullptr;
typename Epilogue::OutputTileIterator::Params params_D;
typename Epilogue::OutputTileIterator::Params params_C;
typename Epilogue::OutputTileIterator::Params params_D{};
typename Epilogue::OutputTileIterator::Params params_C{};
int64_t batch_stride_D;
int64_t batch_stride_C;
int64_t batch_stride_D{0};
int64_t batch_stride_C{0};
protected:
@@ -326,7 +318,6 @@ public:
/// Default constructor
Params() = default;
/// Constructor
Params(
Arguments const &args, /// GEMM application arguments
@@ -129,35 +129,35 @@ public:
//
// Data members
//
cute::Shape<int32_t,int32_t,int32_t> problem_shape;
cute::Shape<int32_t,int32_t,int32_t> problem_shape{};
void * ptr_A;
void * ptr_B;
void * ptr_A{nullptr};
void * ptr_B{nullptr};
typename Mma::IteratorA::Params params_A;
typename Mma::IteratorB::Params params_B;
typename Mma::IteratorA::Params params_A{};
typename Mma::IteratorB::Params params_B{};
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
GemmUniversalMode mode;
GemmUniversalMode mode{GemmUniversalMode::kGemm};
ThreadblockSwizzle block_mapping;
ThreadblockSwizzle block_mapping{};
void *barrier_workspace;
void *partials_workspace;
void *barrier_workspace{nullptr};
void *partials_workspace{nullptr};
typename FusionCallbacks::Params output_op;
typename FusionCallbacks::Params output_op{};
void * ptr_D;
void * ptr_C;
void * ptr_D{nullptr};
void * ptr_C{nullptr};
typename Epilogue::OutputTileIterator::Params params_D;
typename Epilogue::OutputTileIterator::Params params_C;
typename Epilogue::OutputTileIterator::Params params_D{};
typename Epilogue::OutputTileIterator::Params params_C{};
int64_t batch_stride_D;
int64_t batch_stride_C;
int64_t batch_stride_D{0};
int64_t batch_stride_C{0};
protected:
@@ -0,0 +1,759 @@
/***************************************************************************************************
* Copyright (c) 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 Gemm kernel with an epilogue that computes the absolute maximum value of the output
and a pre-activation-function auxiliary output. The auxiliary output is also (optionally)
stored to global memory.
*/
#pragma once
#include "cutlass/cutlass.h"
#include "cutlass/fast_math.h"
#include "cutlass/layout/layout.h"
#include "cutlass/gemm/gemm.h"
#include "cutlass/matrix_coord.h"
#include "cutlass/complex.h"
#include "cutlass/semaphore.h"
#include "cutlass/gemm/kernel/params_universal_base.h"
#include "cutlass/trace.h"
/////////////////////////////////////////////////////////////////////////////////////////////////
namespace cutlass {
namespace gemm {
namespace kernel {
/////////////////////////////////////////////////////////////////////////////////////////////////
// Gemm that computes the absolute maximum value of the output and a pre-activation-function
// auxiliary output.
template <
typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Epilogue_, ///! Epilogue
typename ThreadblockSwizzle_ ///! Threadblock swizzling function
>
struct GemmWithAbsMax {
public:
using Mma = Mma_;
using Epilogue = Epilogue_;
using EpilogueOutputOp = typename Epilogue::OutputOp;
using ThreadblockSwizzle = ThreadblockSwizzle_;
using ElementA = typename Mma::IteratorA::Element;
using LayoutA = typename Mma::IteratorA::Layout;
using ElementB = typename Mma::IteratorB::Element;
using LayoutB = typename Mma::IteratorB::Layout;
using ElementC = typename Epilogue::OutputTileIterator::Element;
using LayoutC = typename Epilogue::OutputTileIterator::Layout;
static ComplexTransform const kTransformA = Mma::kTransformA;
static ComplexTransform const kTransformB = Mma::kTransformB;
using Operator = typename Mma::Operator;
using OperatorClass = typename Mma::Operator::OperatorClass;
using ThreadblockShape = typename Mma::Shape;
using WarpShape = typename Mma::Operator::Shape;
using InstructionShape = typename Mma::Policy::Operator::InstructionShape;
using ArchTag = typename Mma::ArchTag;
static int const kStages = Mma::kStages;
static int const kAlignmentA = Mma::IteratorA::AccessType::kElements;
static int const kAlignmentB = Mma::IteratorB::AccessType::kElements;
static int const kAlignmentC = Epilogue::OutputTileIterator::kElementsPerAccess;
/// Warp count (concept: GemmShape)
using WarpCount = typename Mma::WarpCount;
static int const kThreadCount = 32 * WarpCount::kCount;
/// Split-K preserves splits that are 128b aligned
static int const kSplitKAlignment = const_max(
128 / sizeof_bits<ElementA>::value,
128 / sizeof_bits<ElementB>::value
);
//
// Structures
//
/// Argument structure
struct Arguments : UniversalArgumentsBase
{
//
// Data members
//
typename EpilogueOutputOp::Params epilogue;
void const * ptr_A;
void const * ptr_B;
void const * ptr_C;
void * ptr_D;
void * ptr_Aux;
void * ptr_Vector;
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_C;
int64_t batch_stride_Vector;
typename LayoutA::Stride::Index lda;
typename LayoutB::Stride::Index ldb;
typename LayoutC::Stride::Index ldc;
typename LayoutC::Stride::Index ldd;
typename LayoutC::Stride::Index ldaux;
typename LayoutC::Stride::Index ldr;
//
// Methods
//
Arguments():
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
ptr_Aux(nullptr)
{}
/// Constructs an arguments structure with ldaux
Arguments(
GemmUniversalMode mode,
GemmCoord problem_size,
int batch_count,
typename EpilogueOutputOp::Params epilogue,
void const * ptr_A,
void const * ptr_B,
void const * ptr_C,
void * ptr_D,
void * ptr_Aux,
void * ptr_Vector,
int64_t batch_stride_A,
int64_t batch_stride_B,
int64_t batch_stride_C,
int64_t batch_stride_D,
int64_t batch_stride_Vector,
typename LayoutA::Stride::Index lda,
typename LayoutB::Stride::Index ldb,
typename LayoutC::Stride::Index ldc,
typename LayoutC::Stride::Index ldd,
typename LayoutC::Stride::Index ldr,
typename LayoutC::Stride::Index ldaux)
:
UniversalArgumentsBase(mode, problem_size, batch_count, batch_stride_D),
epilogue(epilogue),
ptr_A(ptr_A), ptr_B(ptr_B), ptr_C(ptr_C), ptr_D(ptr_D), ptr_Aux(ptr_Aux),
ptr_Vector(ptr_Vector),
batch_stride_A(batch_stride_A),
batch_stride_B(batch_stride_B),
batch_stride_C(batch_stride_C),
batch_stride_Vector(batch_stride_Vector),
lda(lda), ldb(ldb), ldc(ldc), ldd(ldd), ldaux(ldaux), ldr(ldr)
{
}
/// Constructs an Arguments structure without ldaux.
/// These parameters are overridden with D batch stride and ldd.
Arguments(
GemmUniversalMode mode,
GemmCoord problem_size,
int batch_count,
typename EpilogueOutputOp::Params epilogue,
void const * ptr_A,
void const * ptr_B,
void const * ptr_C,
void * ptr_D,
void * ptr_Aux,
void * ptr_Vector,
int64_t batch_stride_A,
int64_t batch_stride_B,
int64_t batch_stride_C,
int64_t batch_stride_D,
int64_t batch_stride_Vector,
typename LayoutA::Stride::Index lda,
typename LayoutB::Stride::Index ldb,
typename LayoutC::Stride::Index ldc,
typename LayoutC::Stride::Index ldd,
typename LayoutC::Stride::Index ldr)
: Arguments(mode, problem_size, batch_count, epilogue, ptr_A, ptr_B, ptr_C, ptr_D, ptr_Aux, ptr_Vector,
batch_stride_A, batch_stride_B, batch_stride_C, batch_stride_D, batch_stride_Vector,
lda, ldb, ldc, ldd, ldr, ldd)
{
}
/// Returns arguments for the transposed problem
Arguments transposed_problem() const {
Arguments args(*this);
std::swap(args.problem_size.m(), args.problem_size.n());
std::swap(args.ptr_A, args.ptr_B);
std::swap(args.lda, args.ldb);
std::swap(args.batch_stride_A, args.batch_stride_B);
return args;
}
};
//
// Structure for precomputing values in host memory and passing to kernels
//
/// Parameters structure
struct Params : UniversalParamsBase<
ThreadblockSwizzle,
ThreadblockShape,
ElementA,
ElementB,
ElementC,
LayoutA,
LayoutB>
{
using ParamsBase = UniversalParamsBase<
ThreadblockSwizzle,
ThreadblockShape,
ElementA,
ElementB,
ElementC,
LayoutA,
LayoutB>;
//
// Data members
//
typename Mma::IteratorA::Params params_A;
typename Mma::IteratorB::Params params_B;
typename Epilogue::OutputTileIterator::Params params_C;
typename Epilogue::OutputTileIterator::Params params_D;
typename Epilogue::AuxOutputTileIterator::Params params_Aux;
typename EpilogueOutputOp::Params output_op;
void * ptr_A;
void * ptr_B;
void * ptr_C;
void * ptr_D;
void * ptr_Aux;
void * ptr_Vector;
typename LayoutC::Stride::Index ldr;
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_C;
int64_t batch_stride_Vector;
//
// Host dispatch API
//
/// Default constructor
Params() = default;
/// Constructor
Params(
Arguments const &args, /// GEMM application arguments
int device_sms, /// Number of SMs on the device
int sm_occupancy) /// Kernel SM occupancy (in thread blocks)
:
ParamsBase(args, device_sms, sm_occupancy),
params_A(args.lda),
params_B(args.ldb),
params_C(args.ldc),
params_D(args.ldd),
params_Aux(args.ldaux),
output_op(args.epilogue),
ptr_A(const_cast<void *>(args.ptr_A)),
ptr_B(const_cast<void *>(args.ptr_B)),
ptr_C(const_cast<void *>(args.ptr_C)),
ptr_D(args.ptr_D),
ptr_Aux(args.ptr_Aux),
ptr_Vector(args.ptr_Vector),
ldr(args.ldr),
batch_stride_A(args.batch_stride_A),
batch_stride_B(args.batch_stride_B),
batch_stride_C(args.batch_stride_C),
batch_stride_Vector(args.batch_stride_Vector)
{
}
/// Lightweight update given a subset of arguments.
CUTLASS_HOST_DEVICE
void update(Arguments const &args)
{
ptr_A = const_cast<void *>(args.ptr_A);
ptr_B = const_cast<void *>(args.ptr_B);
ptr_C = const_cast<void *>(args.ptr_C);
ptr_D = args.ptr_D;
ptr_Aux = args.ptr_Aux;
ptr_Vector = args.ptr_Vector;
ldr = args.ldr;
batch_stride_A = args.batch_stride_A;
batch_stride_B = args.batch_stride_B;
batch_stride_C = args.batch_stride_C;
this->batch_stride_D = args.batch_stride_D;
batch_stride_Vector = args.batch_stride_Vector;
output_op = args.epilogue;
}
};
/// Shared memory storage structure
union SharedStorage {
typename Mma::SharedStorage main_loop;
typename Epilogue::SharedStorage epilogue;
};
public:
//
// Host dispatch API
//
/// Determines whether kernel satisfies alignment
static Status can_implement(
cutlass::gemm::GemmCoord const & problem_size) {
static int const kAlignmentA = Mma::IteratorA::AccessType::kElements;
static int const kAlignmentB = Mma::IteratorB::AccessType::kElements;
static int const kAlignmentC = Epilogue::OutputTileIterator::kElementsPerAccess;
bool isAMisaligned = false;
bool isBMisaligned = false;
bool isCMisaligned = false;
if (platform::is_same<LayoutA, layout::RowMajor>::value) {
isAMisaligned = problem_size.k() % kAlignmentA;
} else if (platform::is_same<LayoutA, layout::ColumnMajor>::value) {
isAMisaligned = problem_size.m() % kAlignmentA;
} else if (platform::is_same<LayoutA, layout::ColumnMajorInterleaved<32>>::value
|| platform::is_same<LayoutA, layout::ColumnMajorInterleaved<64>>::value) {
isAMisaligned = problem_size.k() % kAlignmentA;
}
if (platform::is_same<LayoutB, layout::RowMajor>::value) {
isBMisaligned = problem_size.n() % kAlignmentB;
} else if (platform::is_same<LayoutB, layout::ColumnMajor>::value) {
isBMisaligned = problem_size.k() % kAlignmentB;
} else if (platform::is_same<LayoutB, layout::RowMajorInterleaved<32>>::value
|| platform::is_same<LayoutB, layout::RowMajorInterleaved<64>>::value) {
isBMisaligned = problem_size.k() % kAlignmentB;
}
if (platform::is_same<LayoutC, layout::RowMajor>::value) {
isCMisaligned = problem_size.n() % kAlignmentC;
} else if (platform::is_same<LayoutC, layout::ColumnMajor>::value) {
isCMisaligned = problem_size.m() % kAlignmentC;
} else if (platform::is_same<LayoutC, layout::ColumnMajorInterleaved<32>>::value
|| platform::is_same<LayoutC, layout::ColumnMajorInterleaved<64>>::value) {
isCMisaligned = problem_size.n() % kAlignmentC;
}
if (isAMisaligned) {
CUTLASS_TRACE_HOST(" returning kErrorMisalignedOperand for A operand");
return Status::kErrorMisalignedOperand;
}
if (isBMisaligned) {
CUTLASS_TRACE_HOST(" returning kErrorMisalignedOperand for B operand");
return Status::kErrorMisalignedOperand;
}
if (isCMisaligned) {
CUTLASS_TRACE_HOST(" returning kErrorMisalignedOperand for C operand");
return Status::kErrorMisalignedOperand;
}
CUTLASS_TRACE_HOST(" returning kSuccess");
return Status::kSuccess;
}
static Status can_implement(Arguments const &args) {
return can_implement(args.problem_size);
}
public:
//
// Device-only API
//
// Factory invocation
CUTLASS_DEVICE
static void invoke(
Params const &params,
SharedStorage &shared_storage)
{
GemmWithAbsMax op;
op(params, shared_storage);
}
/// Executes one GEMM
CUTLASS_DEVICE
void operator()(Params const &params, SharedStorage &shared_storage) {
// Compute threadblock location
ThreadblockSwizzle threadblock_swizzle;
cutlass::gemm::GemmCoord threadblock_tile_offset = threadblock_swizzle.get_tile_offset(params.swizzle_log_tile);
// Early exit if CTA is out of range
if (params.grid_tiled_shape.m() <= threadblock_tile_offset.m() ||
params.grid_tiled_shape.n() <= threadblock_tile_offset.n()) {
return;
}
int offset_k = 0;
int problem_size_k = params.problem_size.k();
ElementA *ptr_A = static_cast<ElementA *>(params.ptr_A);
ElementB *ptr_B = static_cast<ElementB *>(params.ptr_B);
//
// Fetch pointers based on mode.
//
if (params.mode == GemmUniversalMode::kGemm ||
params.mode == GemmUniversalMode::kGemmSplitKParallel) {
if (threadblock_tile_offset.k() + 1 < params.grid_tiled_shape.k()) {
problem_size_k = (threadblock_tile_offset.k() + 1) * params.gemm_k_size;
}
offset_k = threadblock_tile_offset.k() * params.gemm_k_size;
}
else if (params.mode == GemmUniversalMode::kBatched) {
ptr_A += threadblock_tile_offset.k() * params.batch_stride_A;
ptr_B += threadblock_tile_offset.k() * params.batch_stride_B;
}
else if (params.mode == GemmUniversalMode::kArray) {
ptr_A = static_cast<ElementA * const *>(params.ptr_A)[threadblock_tile_offset.k()];
ptr_B = static_cast<ElementB * const *>(params.ptr_B)[threadblock_tile_offset.k()];
}
__syncthreads();
// Compute initial location in logical coordinates
cutlass::MatrixCoord tb_offset_A{
threadblock_tile_offset.m() * Mma::Shape::kM,
offset_k,
};
cutlass::MatrixCoord tb_offset_B{
offset_k,
threadblock_tile_offset.n() * Mma::Shape::kN
};
// Compute position within threadblock
int thread_idx = threadIdx.x;
// Construct iterators to A and B operands
typename Mma::IteratorA iterator_A(
params.params_A,
ptr_A,
{params.problem_size.m(), problem_size_k},
thread_idx,
tb_offset_A);
typename Mma::IteratorB iterator_B(
params.params_B,
ptr_B,
{problem_size_k, params.problem_size.n()},
thread_idx,
tb_offset_B);
// Broadcast the warp_id computed by lane 0 to ensure dependent code
// is compiled as warp-uniform.
int warp_idx = canonical_warp_idx_sync();
int lane_idx = threadIdx.x % 32;
//
// Main loop
//
// Construct thread-scoped matrix multiply
Mma mma(shared_storage.main_loop, thread_idx, warp_idx, lane_idx);
typename Mma::FragmentC accumulators;
accumulators.clear();
// Compute threadblock-scoped matrix multiply-add
int gemm_k_iterations = (problem_size_k - offset_k + Mma::Shape::kK - 1) / Mma::Shape::kK;
// Compute threadblock-scoped matrix multiply-add
mma(
gemm_k_iterations,
accumulators,
iterator_A,
iterator_B,
accumulators);
//
// Epilogue
//
EpilogueOutputOp output_op(params.output_op);
//
// Masked tile iterators constructed from members
//
threadblock_tile_offset = threadblock_swizzle.get_tile_offset(params.swizzle_log_tile);
//assume identity swizzle
MatrixCoord threadblock_offset(
threadblock_tile_offset.m() * Mma::Shape::kM,
threadblock_tile_offset.n() * Mma::Shape::kN
);
int block_idx = threadblock_tile_offset.m() + threadblock_tile_offset.n() * params.grid_tiled_shape.m();
ElementC *ptr_C = static_cast<ElementC *>(params.ptr_C);
ElementC *ptr_D = static_cast<ElementC *>(params.ptr_D);
typename Epilogue::ElementAuxOutput *ptr_Aux = static_cast<typename Epilogue::ElementAuxOutput *>(params.ptr_Aux);
typename Epilogue::ElementVector *ptr_Vector = static_cast<typename Epilogue::ElementVector *>(params.ptr_Vector);
//
// Fetch pointers based on mode.
//
//
// Special path when split-K not enabled.
//
if (params.mode == GemmUniversalMode::kGemm && params.grid_tiled_shape.k() == 1) {
// Tile iterators loading from source tensors.
typename Epilogue::OutputTileIterator iterator_C(
params.params_C,
ptr_C,
params.problem_size.mn(),
thread_idx,
threadblock_offset
);
// Tile iterator writing to destination tensor.
typename Epilogue::OutputTileIterator iterator_D(
params.params_D,
ptr_D,
params.problem_size.mn(),
thread_idx,
threadblock_offset
);
// Tile iterator writing to auxiliary tensor.
typename Epilogue::AuxOutputTileIterator iterator_Aux(
params.params_Aux,
ptr_Aux,
params.problem_size.mn(),
thread_idx,
threadblock_offset
);
// Construct the epilogue
Epilogue epilogue(
shared_storage.epilogue,
thread_idx,
warp_idx,
lane_idx);
// Move to appropriate location for this output tile
if (ptr_Vector) {
ptr_Vector += threadblock_offset.column() + threadblock_tile_offset.m() * params.ldr;
}
// Execute the epilogue operator to update the destination tensor.
epilogue(output_op,
ptr_Vector,
iterator_D,
accumulators,
iterator_C,
iterator_Aux,
params.problem_size.mn(),
threadblock_offset);
return;
}
//
// Slower path when split-K or batching is needed
//
// Construct the semaphore.
Semaphore semaphore(params.semaphore + block_idx, thread_idx);
if (params.mode == GemmUniversalMode::kGemm) {
// If performing a reduction via split-K, fetch the initial synchronization
if (params.grid_tiled_shape.k() > 1) {
// Fetch the synchronization lock initially but do not block.
semaphore.fetch();
// Indicate which position in a serial reduction the output operator is currently updating
output_op.set_k_partition(threadblock_tile_offset.k(), params.grid_tiled_shape.k());
}
}
else if (params.mode == GemmUniversalMode::kGemmSplitKParallel) {
ptr_D += threadblock_tile_offset.k() * params.batch_stride_D;
}
else if (params.mode == GemmUniversalMode::kBatched) {
ptr_C += threadblock_tile_offset.k() * params.batch_stride_C;
ptr_D += threadblock_tile_offset.k() * params.batch_stride_D;
if (ptr_Aux) {
ptr_Aux += threadblock_tile_offset.k() * params.batch_stride_D;
}
if (ptr_Vector) {
ptr_Vector += threadblock_tile_offset.k() * params.batch_stride_Vector;
}
}
else if (params.mode == GemmUniversalMode::kArray) {
ptr_C = static_cast<ElementC * const *>(params.ptr_C)[threadblock_tile_offset.k()];
ptr_D = static_cast<ElementC * const *>(params.ptr_D)[threadblock_tile_offset.k()];
if (ptr_Aux) {
ptr_Aux = static_cast<typename Epilogue::ElementAuxOutput * const *>(params.ptr_Aux)[threadblock_tile_offset.k()];
}
if (ptr_Vector) {
ptr_Vector = static_cast<typename Epilogue::ElementVector * const *>(params.ptr_Vector)[threadblock_tile_offset.k()];
}
}
// Tile iterators loading from source tensors.
typename Epilogue::OutputTileIterator iterator_C(
params.params_C,
ptr_C,
params.problem_size.mn(),
thread_idx,
threadblock_offset
);
// Tile iterator writing to destination tensor.
typename Epilogue::OutputTileIterator iterator_D(
params.params_D,
ptr_D,
params.problem_size.mn(),
thread_idx,
threadblock_offset
);
// Tile iterator writing to auxiliary destination tensor.
typename Epilogue::AuxOutputTileIterator iterator_Aux(
params.params_Aux,
// Only the final block writes the auxiliary tensor
((params.mode == GemmUniversalMode::kGemm && params.grid_tiled_shape.k() > 1) &&
(params.grid_tiled_shape.k() != threadblock_tile_offset.k() + 1))
? nullptr
: ptr_Aux,
params.problem_size.mn(),
thread_idx,
threadblock_offset
);
// Construct the epilogue
Epilogue epilogue(
shared_storage.epilogue,
thread_idx,
warp_idx,
lane_idx);
// Wait on the semaphore - this latency may have been covered by iterator construction
if ((params.mode == GemmUniversalMode::kGemm) && params.grid_tiled_shape.k() > 1) {
// For subsequent threadblocks, the source matrix is held in the 'D' tensor.
if (threadblock_tile_offset.k()) {
iterator_C = iterator_D;
}
semaphore.wait(threadblock_tile_offset.k());
}
// Move to appropriate location for this output tile
if (ptr_Vector) {
ptr_Vector += threadblock_offset.column() + threadblock_tile_offset.m() * params.ldr;
}
// Execute the epilogue operator to update the destination tensor.
epilogue(output_op,
// Only the final block uses Vector
((params.mode == GemmUniversalMode::kGemm && params.grid_tiled_shape.k() > 1) &&
(params.grid_tiled_shape.k() != threadblock_tile_offset.k() + 1))
? nullptr
: ptr_Vector,
iterator_D,
accumulators,
iterator_C,
iterator_Aux,
params.problem_size.mn(),
threadblock_offset);
//
// Release the semaphore
//
if ((params.mode == GemmUniversalMode::kGemm) && params.grid_tiled_shape.k() > 1) {
int lock = 0;
if (params.grid_tiled_shape.k() == threadblock_tile_offset.k() + 1) {
// The final threadblock resets the semaphore for subsequent grids.
lock = 0;
}
else {
// Otherwise, the semaphore is incremented
lock = threadblock_tile_offset.k() + 1;
}
semaphore.release(lock);
}
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace kernel
} // namespace gemm
} // namespace cutlass
/////////////////////////////////////////////////////////////////////////////////////////////////
@@ -54,7 +54,7 @@ namespace kernel {
/////////////////////////////////////////////////////////////////////////////////////////////////
template <
typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Epilogue_, ///! Epilogue
typename ThreadblockSwizzle_, ///! Threadblock swizzling function
bool IsSingleSource = Epilogue_::kIsSingleSource
@@ -63,7 +63,7 @@ struct GemmWithFusedEpilogue;
// GemmWithFusedEpilogue with two sources
template <
typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Epilogue_, ///! Epilogue
typename ThreadblockSwizzle_ ///! Threadblock swizzling function
>
@@ -103,7 +103,7 @@ public:
/// Split-K preserves splits that are 128b aligned
static int const kSplitKAlignment = const_max(
128 / sizeof_bits<ElementA>::value,
128 / sizeof_bits<ElementA>::value,
128 / sizeof_bits<ElementB>::value
);
@@ -147,8 +147,8 @@ public:
//
// Methods
//
Arguments():
Arguments():
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C1(nullptr),
@@ -185,14 +185,14 @@ public:
typename LayoutC::Stride::Index ldt)
:
UniversalArgumentsBase(mode, problem_size, batch_count, batch_stride_D),
epilogue(epilogue),
ptr_A(ptr_A), ptr_B(ptr_B), ptr_C1(ptr_C1), ptr_C2(ptr_C2), ptr_D(ptr_D),
ptr_Vector(ptr_Vector),
epilogue(epilogue),
ptr_A(ptr_A), ptr_B(ptr_B), ptr_C1(ptr_C1), ptr_C2(ptr_C2), ptr_D(ptr_D),
ptr_Vector(ptr_Vector),
ptr_Tensor(ptr_Tensor),
batch_stride_A(batch_stride_A),
batch_stride_B(batch_stride_B),
batch_stride_C1(batch_stride_C1),
batch_stride_C2(batch_stride_C2),
batch_stride_A(batch_stride_A),
batch_stride_B(batch_stride_B),
batch_stride_C1(batch_stride_C1),
batch_stride_C2(batch_stride_C2),
batch_stride_Vector(batch_stride_Vector),
batch_stride_Tensor(batch_stride_Tensor),
lda(lda), ldb(ldb), ldc1(ldc1), ldc2(ldc2), ldd(ldd), ldr(ldr), ldt(ldt)
@@ -207,7 +207,7 @@ public:
/// Returns arguments for the transposed problem
Arguments transposed_problem() const {
Arguments args(*this);
std::swap(args.problem_size.m(), args.problem_size.n());
std::swap(args.ptr_A, args.ptr_B);
std::swap(args.lda, args.ldb);
@@ -307,7 +307,7 @@ public:
batch_stride_Vector(args.batch_stride_Vector),
batch_stride_Tensor(args.batch_stride_Tensor)
{
CUTLASS_TRACE_HOST("GemmWithFusedEpilogue::Params::Params() - problem_size: " << problem_size);
CUTLASS_TRACE_HOST("GemmWithFusedEpilogue::Params::Params()");
CUTLASS_TRACE_HOST(" ptr_Vector: " << (void *)this->ptr_Vector);
CUTLASS_TRACE_HOST(" ptr_Tensor: " << (void *)this->ptr_Tensor);
CUTLASS_TRACE_HOST(" ldr: " << this->ldr);
@@ -460,7 +460,7 @@ public:
int offset_k = 0;
int problem_size_k = params.problem_size.k();
ElementA *ptr_A = static_cast<ElementA *>(params.ptr_A);
ElementA *ptr_A = static_cast<ElementA *>(params.ptr_A);
ElementB *ptr_B = static_cast<ElementB *>(params.ptr_B);
@@ -468,12 +468,12 @@ public:
//
// Fetch pointers based on mode.
//
if (params.mode == GemmUniversalMode::kGemm ||
if (params.mode == GemmUniversalMode::kGemm ||
params.mode == GemmUniversalMode::kGemmSplitKParallel) {
if (threadblock_tile_offset.k() + 1 < params.grid_tiled_shape.k()) {
problem_size_k = (threadblock_tile_offset.k() + 1) * params.gemm_k_size;
problem_size_k = (threadblock_tile_offset.k() + 1) * params.gemm_k_size;
}
offset_k = threadblock_tile_offset.k() * params.gemm_k_size;
@@ -539,10 +539,10 @@ public:
// Compute threadblock-scoped matrix multiply-add
mma(
gemm_k_iterations,
accumulators,
iterator_A,
iterator_B,
gemm_k_iterations,
accumulators,
iterator_A,
iterator_B,
accumulators);
//
@@ -571,16 +571,16 @@ public:
typename Epilogue::ElementTensor *ptr_Tensor = static_cast<typename Epilogue::ElementTensor *>(params.ptr_Tensor);
// Define the reduction output pointer and move to the appropriate place
typename Epilogue::ElementVector *ptr_Vector =
typename Epilogue::ElementVector *ptr_Vector =
static_cast<typename Epilogue::ElementVector *>(params.ptr_Vector);
//
// Fetch pointers based on mode.
//
//
// Special path when split-K not enabled.
//
//
if (params.mode == GemmUniversalMode::kGemm && params.grid_tiled_shape.k() == 1) {
@@ -621,9 +621,9 @@ public:
// Construct the epilogue
Epilogue epilogue(
shared_storage.epilogue,
thread_idx,
warp_idx,
shared_storage.epilogue,
thread_idx,
warp_idx,
lane_idx);
// Move to appropriate location for this output tile
@@ -649,7 +649,7 @@ public:
// Slower path when split-K or batching is needed
//
#if SPLIT_K_ENABLED
// Construct the semaphore.
Semaphore semaphore(params.semaphore + block_idx, thread_idx);
@@ -658,7 +658,7 @@ public:
// If performing a reduction via split-K, fetch the initial synchronization
if (params.grid_tiled_shape.k() > 1) {
// Fetch the synchronization lock initially but do not block.
semaphore.fetch();
@@ -739,15 +739,15 @@ public:
// Construct the epilogue
Epilogue epilogue(
shared_storage.epilogue,
thread_idx,
warp_idx,
shared_storage.epilogue,
thread_idx,
warp_idx,
lane_idx);
#if SPLIT_K_ENABLED
// Wait on the semaphore - this latency may have been covered by iterator construction
if ((params.mode == GemmUniversalMode::kGemm) && params.grid_tiled_shape.k() > 1) {
// For subsequent threadblocks, the source matrix is held in the 'D' tensor.
if (threadblock_tile_offset.k()) {
iterator_C1 = iterator_D;
@@ -783,7 +783,7 @@ public:
//
#if SPLIT_K_ENABLED
if ((params.mode == GemmUniversalMode::kGemm) && params.grid_tiled_shape.k() > 1) {
if ((params.mode == GemmUniversalMode::kGemm) && params.grid_tiled_shape.k() > 1) {
int lock = 0;
if (params.grid_tiled_shape.k() == threadblock_tile_offset.k() + 1) {
@@ -795,7 +795,7 @@ public:
// Otherwise, the semaphore is incremented
lock = threadblock_tile_offset.k() + 1;
}
semaphore.release(lock);
}
#endif
@@ -804,7 +804,7 @@ public:
// GemmWithFusedEpilogue with one source
template <
typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Epilogue_, ///! Epilogue
typename ThreadblockSwizzle_ ///! Threadblock swizzling function
>
@@ -844,7 +844,7 @@ public:
/// Split-K preserves splits that are 128b aligned
static int const kSplitKAlignment = const_max(
128 / sizeof_bits<ElementA>::value,
128 / sizeof_bits<ElementA>::value,
128 / sizeof_bits<ElementB>::value
);
@@ -885,8 +885,8 @@ public:
//
// Methods
//
Arguments():
Arguments():
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
@@ -919,13 +919,13 @@ public:
typename LayoutC::Stride::Index ldt)
:
UniversalArgumentsBase(mode, problem_size, batch_count, batch_stride_D),
epilogue(epilogue),
ptr_A(ptr_A), ptr_B(ptr_B), ptr_C(ptr_C), ptr_D(ptr_D),
ptr_Vector(ptr_Vector),
epilogue(epilogue),
ptr_A(ptr_A), ptr_B(ptr_B), ptr_C(ptr_C), ptr_D(ptr_D),
ptr_Vector(ptr_Vector),
ptr_Tensor(ptr_Tensor),
batch_stride_A(batch_stride_A),
batch_stride_B(batch_stride_B),
batch_stride_C(batch_stride_C),
batch_stride_A(batch_stride_A),
batch_stride_B(batch_stride_B),
batch_stride_C(batch_stride_C),
batch_stride_Vector(batch_stride_Vector),
batch_stride_Tensor(batch_stride_Tensor),
lda(lda), ldb(ldb), ldc(ldc), ldd(ldd), ldr(ldr), ldt(ldt)
@@ -940,7 +940,7 @@ public:
/// Returns arguments for the transposed problem
Arguments transposed_problem() const {
Arguments args(*this);
std::swap(args.problem_size.m(), args.problem_size.n());
std::swap(args.ptr_A, args.ptr_B);
std::swap(args.lda, args.ldb);
@@ -1035,7 +1035,7 @@ public:
batch_stride_Vector(args.batch_stride_Vector),
batch_stride_Tensor(args.batch_stride_Tensor)
{
CUTLASS_TRACE_HOST("GemmWithFusedEpilogue::Params::Params() - problem_size: " << problem_size);
CUTLASS_TRACE_HOST("GemmWithFusedEpilogue::Params::Params()");
CUTLASS_TRACE_HOST(" ptr_Vector: " << (void *)this->ptr_Vector);
CUTLASS_TRACE_HOST(" ptr_Tensor: " << (void *)this->ptr_Tensor);
CUTLASS_TRACE_HOST(" ldr: " << this->ldr);
@@ -1186,7 +1186,7 @@ public:
int offset_k = 0;
int problem_size_k = params.problem_size.k();
ElementA *ptr_A = static_cast<ElementA *>(params.ptr_A);
ElementA *ptr_A = static_cast<ElementA *>(params.ptr_A);
ElementB *ptr_B = static_cast<ElementB *>(params.ptr_B);
@@ -1194,12 +1194,12 @@ public:
//
// Fetch pointers based on mode.
//
if (params.mode == GemmUniversalMode::kGemm ||
if (params.mode == GemmUniversalMode::kGemm ||
params.mode == GemmUniversalMode::kGemmSplitKParallel) {
if (threadblock_tile_offset.k() + 1 < params.grid_tiled_shape.k()) {
problem_size_k = (threadblock_tile_offset.k() + 1) * params.gemm_k_size;
problem_size_k = (threadblock_tile_offset.k() + 1) * params.gemm_k_size;
}
offset_k = threadblock_tile_offset.k() * params.gemm_k_size;
@@ -1265,10 +1265,10 @@ public:
// Compute threadblock-scoped matrix multiply-add
mma(
gemm_k_iterations,
accumulators,
iterator_A,
iterator_B,
gemm_k_iterations,
accumulators,
iterator_A,
iterator_B,
accumulators);
//
@@ -1296,16 +1296,16 @@ public:
typename Epilogue::ElementTensor *ptr_Tensor = static_cast<typename Epilogue::ElementTensor *>(params.ptr_Tensor);
// Define the reduction output pointer and move to the appropriate place
typename Epilogue::ElementVector *ptr_Vector =
typename Epilogue::ElementVector *ptr_Vector =
static_cast<typename Epilogue::ElementVector *>(params.ptr_Vector);
//
// Fetch pointers based on mode.
//
//
// Special path when split-K not enabled.
//
//
if (params.mode == GemmUniversalMode::kGemm && params.grid_tiled_shape.k() == 1) {
@@ -1338,9 +1338,9 @@ public:
// Construct the epilogue
Epilogue epilogue(
shared_storage.epilogue,
thread_idx,
warp_idx,
shared_storage.epilogue,
thread_idx,
warp_idx,
lane_idx);
// Move to appropriate location for this output tile
@@ -1365,7 +1365,7 @@ public:
// Slower path when split-K or batching is needed
//
#if SPLIT_K_ENABLED
// Construct the semaphore.
Semaphore semaphore(params.semaphore + block_idx, thread_idx);
@@ -1374,7 +1374,7 @@ public:
// If performing a reduction via split-K, fetch the initial synchronization
if (params.grid_tiled_shape.k() > 1) {
// Fetch the synchronization lock initially but do not block.
semaphore.fetch();
@@ -1441,15 +1441,15 @@ public:
// Construct the epilogue
Epilogue epilogue(
shared_storage.epilogue,
thread_idx,
warp_idx,
shared_storage.epilogue,
thread_idx,
warp_idx,
lane_idx);
#if SPLIT_K_ENABLED
// Wait on the semaphore - this latency may have been covered by iterator construction
if ((params.mode == GemmUniversalMode::kGemm) && params.grid_tiled_shape.k() > 1) {
// For subsequent threadblocks, the source matrix is held in the 'D' tensor.
if (threadblock_tile_offset.k()) {
iterator_C = iterator_D;
@@ -1484,7 +1484,7 @@ public:
//
#if SPLIT_K_ENABLED
if ((params.mode == GemmUniversalMode::kGemm) && params.grid_tiled_shape.k() > 1) {
if ((params.mode == GemmUniversalMode::kGemm) && params.grid_tiled_shape.k() > 1) {
int lock = 0;
if (params.grid_tiled_shape.k() == threadblock_tile_offset.k() + 1) {
@@ -1496,7 +1496,7 @@ public:
// Otherwise, the semaphore is incremented
lock = threadblock_tile_offset.k() + 1;
}
semaphore.release(lock);
}
#endif
@@ -60,26 +60,24 @@ struct SparseParamsBase
// Data members
//
cutlass::gemm::GemmCoord problem_size;
cutlass::gemm::GemmCoord grid_tiled_shape;
cutlass::gemm::GemmCoord problem_size{};
cutlass::gemm::GemmCoord grid_tiled_shape{};
int swizzle_log_tile;
ParamsA params_A;
TensorRefA ref_A;
ParamsB params_B;
TensorRefB ref_B;
ParamsE params_E;
TensorRefE ref_E;
int gemm_k_iterations;
int gemm_k_size;
ParamsA params_A{};
TensorRefA ref_A{};
ParamsB params_B{};
TensorRefB ref_B{};
ParamsE params_E{};
TensorRefE ref_E{};
int gemm_k_iterations{0};
int gemm_k_size{0};
//
// Host dispatch API
//
/// Default constructor
CUTLASS_HOST_DEVICE
SparseParamsBase() : swizzle_log_tile(0), gemm_k_iterations(0), gemm_k_size(0) { }
SparseParamsBase() = default;
/// Constructor
CUTLASS_HOST_DEVICE
@@ -54,8 +54,8 @@ template <class LayoutA, class LayoutB>
CUTLASS_HOST_DEVICE
static bool
is_continous_k_aligned(GemmCoord problem_size, size_t alignmentA, size_t alignmentB) {
return (std::is_same<LayoutA, layout::RowMajor>::value && (problem_size.k() % alignmentA) == 0) ||
(std::is_same<LayoutB, layout::ColumnMajor>::value && (problem_size.k() % alignmentB) == 0);
return (platform::is_same<LayoutA, layout::RowMajor>::value && (problem_size.k() % alignmentA) == 0) ||
(platform::is_same<LayoutB, layout::ColumnMajor>::value && (problem_size.k() % alignmentB) == 0);
}
} // namespace util
@@ -69,21 +69,16 @@ struct UniversalArgumentsBase
// Data members
//
GemmUniversalMode mode;
GemmCoord problem_size;
int batch_count;
int64_t batch_stride_D;
GemmUniversalMode mode = cutlass::gemm::GemmUniversalMode::kGemm;
GemmCoord problem_size{};
int batch_count{1};
int64_t batch_stride_D{0};
//
// Methods
//
UniversalArgumentsBase() :
mode(GemmUniversalMode::kGemm),
batch_count(1),
batch_stride_D(0)
{}
UniversalArgumentsBase() = default;
/// constructs an arguments structure
UniversalArgumentsBase(
@@ -117,17 +112,14 @@ struct UniversalParamsBase
// Data members
//
GemmCoord problem_size;
GemmCoord grid_tiled_shape;
int swizzle_log_tile;
GemmUniversalMode mode;
int batch_count;
int gemm_k_size;
int64_t batch_stride_D;
int *semaphore;
GemmCoord problem_size{};
GemmCoord grid_tiled_shape{};
int swizzle_log_tile{0};
GemmUniversalMode mode = cutlass::gemm::GemmUniversalMode::kGemm;
int batch_count {0};
int gemm_k_size {0};
int64_t batch_stride_D {0};
int *semaphore = nullptr;
//
@@ -137,7 +129,6 @@ struct UniversalParamsBase
/// Default constructor
UniversalParamsBase() = default;
/// Constructor
UniversalParamsBase(
UniversalArgumentsBase const &args, /// GEMM application arguments
+31 -61
View File
@@ -197,51 +197,34 @@ public:
// Data members
//
GemmUniversalMode mode;
GemmCoord *problem_sizes;
int problem_count;
int threadblock_count;
GemmUniversalMode mode = GemmUniversalMode::kGemm;
GemmCoord *problem_sizes = nullptr;
int problem_count{0};
int threadblock_count{0};
typename EpilogueOutputOp::Params epilogue;
ElementA ** ptr_A;
ElementB ** ptr_B;
ElementC ** ptr_C;
ElementC ** ptr_D;
ElementA ** ptr_A = nullptr;
ElementB ** ptr_B = nullptr;
ElementC ** ptr_C = nullptr;
ElementC ** ptr_D = nullptr;
typename LayoutA::Stride::LongIndex *lda;
typename LayoutB::Stride::LongIndex *ldb;
typename LayoutC::Stride::LongIndex *ldc;
typename LayoutC::Stride::LongIndex *ldd;
typename LayoutA::Stride::LongIndex *lda = nullptr;
typename LayoutB::Stride::LongIndex *ldb = nullptr;
typename LayoutC::Stride::LongIndex *ldc = nullptr;
typename LayoutC::Stride::LongIndex *ldd = nullptr;
// Only used by device-level operator
GemmCoord *host_problem_sizes;
GemmCoord *host_problem_sizes = nullptr;
bool allow_early_exit;
bool allow_early_exit = false;
//
// Methods
//
/// Default ctor
CUTLASS_HOST_DEVICE
Arguments():
mode(GemmUniversalMode::kGemm),
problem_count(0),
threadblock_count(0),
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
lda(nullptr),
ldb(nullptr),
ldc(nullptr),
ldd(nullptr),
host_problem_sizes(nullptr),
allow_early_exit(false)
{
}
Arguments() = default;
/// Ctor
CUTLASS_HOST_DEVICE
@@ -290,43 +273,31 @@ public:
/// Parameters structure
struct Params {
typename ProblemVisitor::Params problem_visitor;
int threadblock_count;
typename ProblemVisitor::Params problem_visitor{};
int threadblock_count = 0;
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
GemmUniversalMode mode;
int batch_count;
GemmUniversalMode mode = cutlass::gemm::GemmUniversalMode::kGemm;
int batch_count = 0;
ElementA ** ptr_A;
ElementB ** ptr_B;
ElementC ** ptr_C;
ElementC ** ptr_D;
ElementA** ptr_A = nullptr;
ElementB** ptr_B = nullptr;
ElementC** ptr_C = nullptr;
ElementC** ptr_D = nullptr;
typename LayoutA::Stride::LongIndex *lda;
typename LayoutB::Stride::LongIndex *ldb;
typename LayoutC::Stride::LongIndex *ldc;
typename LayoutC::Stride::LongIndex *ldd;
typename LayoutA::Stride::LongIndex* lda = nullptr;
typename LayoutB::Stride::LongIndex* ldb = nullptr;
typename LayoutC::Stride::LongIndex* ldc = nullptr;
typename LayoutC::Stride::LongIndex* ldd = nullptr;
bool allow_early_exit;
bool allow_early_exit = false;
//
// Methods
//
CUTLASS_HOST_DEVICE
Params():
mode(cutlass::gemm::GemmUniversalMode::kGemm),
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
lda(nullptr),
ldb(nullptr),
ldc(nullptr),
ldd(nullptr),
allow_early_exit(false)
{ }
Params() = default;
CUTLASS_HOST_DEVICE
Params(Arguments const &args, void *workspace = nullptr, int tile_count = 0):
@@ -380,8 +351,7 @@ public:
// Methods
//
CUTLASS_DEVICE
Rank2KGrouped() { }
Rank2KGrouped() = default;
/// Determines whether kernel satisfies alignment
static Status can_implement(cutlass::gemm::GemmCoord const & problem_size) {
+44 -68
View File
@@ -119,38 +119,34 @@ public:
// Data members
//
GemmUniversalMode mode;
GemmCoord problem_size;
int batch_count;
GemmUniversalMode mode = cutlass::gemm::GemmUniversalMode::kGemm;
GemmCoord problem_size {};
int batch_count{1};
typename EpilogueOutputOp::Params epilogue;
typename EpilogueOutputOp::Params epilogue{};
void const * ptr_A;
void const * ptr_B;
void const * ptr_C;
void * ptr_D;
void const * ptr_A = nullptr;
void const * ptr_B = nullptr;
void const * ptr_C = nullptr;
void * ptr_D = nullptr;
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_C;
int64_t batch_stride_D;
int64_t batch_stride_A {0};
int64_t batch_stride_B {0};
int64_t batch_stride_C {0};
int64_t batch_stride_D {0};
typename LayoutA::Stride::Index lda;
typename LayoutB::Stride::Index ldb;
typename LayoutC::Stride::Index ldc;
typename LayoutC::Stride::Index ldd;
typename LayoutA::Stride::Index lda{0};
typename LayoutB::Stride::Index ldb{0};
typename LayoutC::Stride::Index ldc{0};
typename LayoutC::Stride::Index ldd{0};
bool allow_early_exit;
bool allow_early_exit{false};
//
// Methods
//
Arguments():
mode(GemmUniversalMode::kGemm),
batch_count(1),
ptr_A(nullptr), ptr_B(nullptr), ptr_C(nullptr), ptr_D(nullptr),
allow_early_exit(false) { }
Arguments() = default;
/// constructs an arguments structure
Arguments(
@@ -177,7 +173,8 @@ public:
batch_count(batch_count),
epilogue(epilogue),
ptr_A(ptr_A), ptr_B(ptr_B), ptr_C(ptr_C), ptr_D(ptr_D),
batch_stride_A(batch_stride_A), batch_stride_C(batch_stride_C), batch_stride_D(batch_stride_D),
batch_stride_A(batch_stride_A), batch_stride_B(0),
batch_stride_C(batch_stride_C), batch_stride_D(batch_stride_D),
lda(lda), ldb(ldb), ldc(ldc), ldd(ldd),
allow_early_exit(allow_early_exit) {
@@ -203,67 +200,46 @@ public:
/// Parameters structure
struct Params {
cutlass::gemm::GemmCoord problem_size;
cutlass::gemm::GemmCoord grid_tiled_shape;
int swizzle_log_tile;
cutlass::gemm::GemmCoord problem_size{};
cutlass::gemm::GemmCoord grid_tiled_shape{};
int swizzle_log_tile{0};
// Mma1 Iterator A and B params
typename Mma1::IteratorA::Params params_A;
typename Mma1::IteratorB::Params params_BT;
typename Mma1::IteratorA::Params params_A{};
typename Mma1::IteratorB::Params params_BT{};
// Mma2 Iterator A and B params
typename Mma2::IteratorA::Params params_B;
typename Mma2::IteratorB::Params params_AT;
typename Mma2::IteratorA::Params params_B{};
typename Mma2::IteratorB::Params params_AT{};
typename Epilogue::OutputTileIterator::Params params_C;
typename Epilogue::OutputTileIterator::Params params_D;
typename Epilogue::OutputTileIterator::Params params_C{};
typename Epilogue::OutputTileIterator::Params params_D{};
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
GemmUniversalMode mode;
int batch_count;
int gemm_k_size;
GemmUniversalMode mode = cutlass::gemm::GemmUniversalMode::kGemm;
int batch_count{0};
int gemm_k_size{0};
void * ptr_A;
void * ptr_B;
void * ptr_C;
void * ptr_D;
void * ptr_A = nullptr;
void * ptr_B = nullptr;
void * ptr_C = nullptr;
void * ptr_D = nullptr;
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_C;
int64_t batch_stride_D;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
int64_t batch_stride_C{0};
int64_t batch_stride_D{0};
int *semaphore;
int *semaphore = nullptr;
bool allow_early_exit;
bool allow_early_exit {false};
//
// Methods
//
CUTLASS_HOST_DEVICE
Params():
swizzle_log_tile(0),
params_A(0),
params_BT(0),
params_B(0),
params_AT(0),
params_C(0),
params_D(0),
batch_count(0),
gemm_k_size(0),
mode(cutlass::gemm::GemmUniversalMode::kGemm),
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
batch_stride_A(0),
batch_stride_B(0),
batch_stride_C(0),
batch_stride_D(0),
semaphore(nullptr),
allow_early_exit(false) { }
Params() = default;
CUTLASS_HOST_DEVICE
Params(
+40 -64
View File
@@ -106,36 +106,32 @@ public:
// Data members
//
GemmUniversalMode mode;
GemmCoord problem_size;
int batch_count;
GemmUniversalMode mode{GemmUniversalMode::kGemm};
GemmCoord problem_size{};
int batch_count{1};
typename EpilogueOutputOp::Params epilogue;
typename EpilogueOutputOp::Params epilogue{};
void const * ptr_A;
void const * ptr_C;
void * ptr_D;
void const * ptr_A{nullptr};
void const * ptr_C{nullptr};
void * ptr_D{nullptr};
int64_t batch_stride_A;
int64_t batch_stride_C;
int64_t batch_stride_D;
int64_t batch_stride_A{0};
int64_t batch_stride_C{0};
int64_t batch_stride_D{0};
typename LayoutA::Stride::Index lda;
typename LayoutB::Stride::Index ldb;
typename LayoutC::Stride::Index ldc;
typename LayoutC::Stride::Index ldd;
typename LayoutA::Stride::Index lda{};
typename LayoutB::Stride::Index ldb{};
typename LayoutC::Stride::Index ldc{};
typename LayoutC::Stride::Index ldd{};
bool allow_early_exit;
bool allow_early_exit{false};
//
// Methods
//
Arguments():
mode(GemmUniversalMode::kGemm),
batch_count(1),
ptr_A(nullptr), ptr_C(nullptr), ptr_D(nullptr),
allow_early_exit(false) { }
Arguments() = default;
/// constructs an arguments structure
Arguments(
@@ -160,7 +156,8 @@ public:
epilogue(epilogue),
ptr_A(ptr_A), ptr_C(ptr_C), ptr_D(ptr_D),
batch_stride_A(batch_stride_A), batch_stride_C(batch_stride_C), batch_stride_D(batch_stride_D),
lda(lda), ldb(ldb), ldc(ldc), ldd(ldd),
lda(lda), ldb(0),
ldc(ldc), ldd(ldd),
allow_early_exit(allow_early_exit) {
}
@@ -174,59 +171,38 @@ public:
/// Parameters structure
struct Params {
cutlass::gemm::GemmCoord problem_size;
cutlass::gemm::GemmCoord grid_tiled_shape;
int swizzle_log_tile;
cutlass::gemm::GemmCoord problem_size{};
cutlass::gemm::GemmCoord grid_tiled_shape{};
int swizzle_log_tile{0};
typename Mma::IteratorA::Params params_A;
typename Mma::IteratorB::Params params_B;
typename Epilogue::OutputTileIterator::Params params_C;
typename Epilogue::OutputTileIterator::Params params_D;
typename EpilogueOutputOp::Params output_op;
typename Mma::IteratorA::Params params_A{};
typename Mma::IteratorB::Params params_B{};
typename Epilogue::OutputTileIterator::Params params_C{};
typename Epilogue::OutputTileIterator::Params params_D{};
typename EpilogueOutputOp::Params output_op{};
GemmUniversalMode mode;
int batch_count;
int gemm_k_size;
GemmUniversalMode mode = cutlass::gemm::GemmUniversalMode::kGemm;
int batch_count{0};
int gemm_k_size{0};
void * ptr_A;
void * ptr_B;
void * ptr_C;
void * ptr_D;
void * ptr_A{nullptr};
void * ptr_B{nullptr};
void * ptr_C{nullptr};
void * ptr_D{nullptr};
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_C;
int64_t batch_stride_D;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
int64_t batch_stride_C{0};
int64_t batch_stride_D{0};
int *semaphore;
int *semaphore{nullptr};
bool allow_early_exit;
bool allow_early_exit{false};
//
// Methods
//
CUTLASS_HOST_DEVICE
Params():
swizzle_log_tile(0),
params_A(0),
params_B(0),
params_C(0),
params_D(0),
batch_count(0),
gemm_k_size(0),
mode(cutlass::gemm::GemmUniversalMode::kGemm),
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
batch_stride_A(0),
batch_stride_B(0),
batch_stride_C(0),
batch_stride_D(0),
semaphore(nullptr),
allow_early_exit(false) { }
Params() = default;
CUTLASS_HOST_DEVICE
Params(
+8 -8
View File
@@ -116,10 +116,10 @@ static_assert(is_valid_tile_scheduler, "SM70 kernel does not support specializin
// Kernel entry point API
struct Params {
GemmUniversalMode mode;
ProblemShape problem_shape;
MainloopParams mainloop;
EpilogueParams epilogue;
GemmUniversalMode mode{};
ProblemShape problem_shape{};
MainloopParams mainloop{};
EpilogueParams epilogue{};
};
//
@@ -150,15 +150,16 @@ static_assert(is_valid_tile_scheduler, "SM70 kernel does not support specializin
return mode_implementable && TileScheduler::can_implement(args.scheduler);
}
static int
static size_t
get_workspace_size(Arguments const& args) {
int workspace_size = 0;
size_t workspace_size = 0;
return workspace_size;
}
static
cutlass::Status
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr) {
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr,
CudaHostAdapter* cuda_adapter = nullptr) {
cutlass::Status status = Status::kSuccess;
return status;
@@ -250,7 +251,6 @@ static_assert(is_valid_tile_scheduler, "SM70 kernel does not support specializin
thread_idx,
smem_buf
);
// Epilogue and write to gD
CollectiveEpilogue epilogue{params.epilogue};
epilogue(
@@ -168,13 +168,13 @@ public:
// Kernel entry point API
struct Params {
GemmUniversalMode mode;
ProblemShape problem_shape;
MainloopParams mainloop;
EpilogueParams epilogue;
KernelHardwareInfo hw_info;
TileSchedulerParams scheduler;
void* workspace;
GemmUniversalMode mode{};
ProblemShape problem_shape{};
MainloopParams mainloop{};
EpilogueParams epilogue{};
KernelHardwareInfo hw_info{};
TileSchedulerParams scheduler{};
void* workspace{nullptr};
};
//
@@ -290,7 +290,8 @@ public:
}
static cutlass::Status
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr) {
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr,
CudaHostAdapter* cuda_adapter = nullptr) {
Status status = Status::kSuccess;
uint8_t* workspace_ptr = reinterpret_cast<uint8_t*>(workspace);
size_t workspace_offset = 0;
@@ -305,7 +306,7 @@ public:
return status;
}
status = CollectiveEpilogue::initialize_workspace(args.problem_shape, args.epilogue, workspace_ptr + workspace_offset, stream);
status = CollectiveEpilogue::initialize_workspace(args.problem_shape, args.epilogue, workspace_ptr + workspace_offset, stream, cuda_adapter);
workspace_offset += CollectiveEpilogue::get_workspace_size(args.problem_shape, args.epilogue);
workspace_offset = round_nearest(workspace_offset, MinWorkspaceAlignment);
@@ -135,10 +135,10 @@ public:
// Kernel entry point API
struct Params {
GemmUniversalMode mode;
ProblemShape problem_shape;
MainloopParams mainloop;
EpilogueParams epilogue;
GemmUniversalMode mode{};
ProblemShape problem_shape{};
MainloopParams mainloop{};
EpilogueParams epilogue{};
};
//
@@ -180,13 +180,14 @@ public:
return implementable;
}
static int
static size_t
get_workspace_size(Arguments const& args) {
return 0;
}
static cutlass::Status
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr) {
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr,
CudaHostAdapter* cuda_adapter = nullptr) {
return Status::kSuccess;
}
@@ -141,10 +141,10 @@ public:
// Kernel entry point API
struct Params {
GemmUniversalMode mode;
ProblemShape problem_shape;
MainloopParams mainloop;
EpilogueParams epilogue;
GemmUniversalMode mode{};
ProblemShape problem_shape{};
MainloopParams mainloop{};
EpilogueParams epilogue{};
};
//
@@ -187,14 +187,15 @@ public:
}
static
int
size_t
get_workspace_size(Arguments const& args) {
return 0;
}
static
cutlass::Status
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr) {
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr,
CudaHostAdapter* cuda_adapter = nullptr) {
return Status::kSuccess;
}
@@ -148,13 +148,13 @@ public:
// Kernel entry point API
struct Params {
GemmUniversalMode mode;
ProblemShape problem_shape;
MainloopParams mainloop;
EpilogueParams epilogue;
KernelHardwareInfo hw_info;
TileSchedulerParams scheduler;
void* workspace;
GemmUniversalMode mode{};
ProblemShape problem_shape{};
MainloopParams mainloop{};
EpilogueParams epilogue{};
KernelHardwareInfo hw_info{};
TileSchedulerParams scheduler{};
void* workspace{nullptr};
};
//
@@ -250,7 +250,8 @@ public:
}
static cutlass::Status
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr) {
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr,
CudaHostAdapter* cuda_adapter = nullptr) {
Status status = Status::kSuccess;
uint8_t* workspace_ptr = reinterpret_cast<uint8_t*>(workspace);
size_t workspace_offset = 0;
@@ -265,7 +266,7 @@ public:
return status;
}
status = CollectiveEpilogue::initialize_workspace(args.problem_shape, args.epilogue, workspace_ptr + workspace_offset, stream);
status = CollectiveEpilogue::initialize_workspace(args.problem_shape, args.epilogue, workspace_ptr + workspace_offset, stream, cuda_adapter);
workspace_offset += CollectiveEpilogue::get_workspace_size(args.problem_shape, args.epilogue);
workspace_offset = round_nearest(workspace_offset, MinWorkspaceAlignment);
if (status != Status::kSuccess) {
@@ -156,12 +156,12 @@ public:
// Kernel entry point API
struct Params {
GemmUniversalMode mode;
ProblemShape problem_shape;
MainloopParams mainloop;
EpilogueParams epilogue;
KernelHardwareInfo hw_info;
TileSchedulerParams scheduler;
GemmUniversalMode mode{};
ProblemShape problem_shape{};
MainloopParams mainloop{};
EpilogueParams epilogue{};
KernelHardwareInfo hw_info{};
TileSchedulerParams scheduler{};
};
//
@@ -249,7 +249,8 @@ public:
}
static cutlass::Status
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr) {
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr,
CudaHostAdapter* cuda_adapter = nullptr) {
Status status = Status::kSuccess;
uint8_t* workspace_ptr = reinterpret_cast<uint8_t*>(workspace);
size_t workspace_offset = 0;
@@ -263,7 +264,7 @@ public:
return status;
}
status = CollectiveEpilogue::initialize_workspace(args.problem_shape, args.epilogue, workspace_ptr + workspace_offset, stream);
status = CollectiveEpilogue::initialize_workspace(args.problem_shape, args.epilogue, workspace_ptr + workspace_offset, stream, cuda_adapter);
workspace_offset += CollectiveEpilogue::get_workspace_size(args.problem_shape, args.epilogue);
workspace_offset = round_nearest(workspace_offset, MinWorkspaceAlignment);
if (status != Status::kSuccess) {
@@ -145,10 +145,10 @@ public:
// Kernel entry point API
struct Params {
GemmUniversalMode mode;
ProblemShape problem_shape;
MainloopParams mainloop;
EpilogueParams epilogue;
GemmUniversalMode mode{};
ProblemShape problem_shape{};
MainloopParams mainloop{};
EpilogueParams epilogue{};
};
//
@@ -191,14 +191,15 @@ public:
}
static
int
size_t
get_workspace_size(Arguments const& args) {
return 0;
}
static
cutlass::Status
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr) {
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr,
CudaHostAdapter* cuda_adapter = nullptr) {
return Status::kSuccess;
}
@@ -146,12 +146,12 @@ public:
// Kernel entry point API
struct Params {
GemmUniversalMode mode;
ProblemShape problem_shape;
MainloopParams mainloop;
EpilogueParams epilogue;
KernelHardwareInfo hw_info;
TileSchedulerParams scheduler;
GemmUniversalMode mode{};
ProblemShape problem_shape{};
MainloopParams mainloop{};
EpilogueParams epilogue{};
KernelHardwareInfo hw_info{};
TileSchedulerParams scheduler{};
};
//
@@ -213,7 +213,7 @@ public:
}
static
int
size_t
get_workspace_size(Arguments const& args) {
TileScheduler t;
return t.template get_workspace_size<ProblemShape, ElementAccumulator>(
@@ -222,7 +222,8 @@ public:
static
cutlass::Status
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr) {
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr,
CudaHostAdapter* cuda_adapter = nullptr) {
TileScheduler t;
return t.template initialize_workspace<ProblemShape, ElementAccumulator>(
args.scheduler, workspace, stream, args.problem_shape, args.hw_info, NumMmaWarpGroups);
@@ -156,12 +156,12 @@ public:
// Kernel entry point API
struct Params {
GemmUniversalMode mode;
ProblemShape problem_shape;
MainloopParams mainloop;
EpilogueParams epilogue;
KernelHardwareInfo hw_info;
TileSchedulerParams scheduler;
GemmUniversalMode mode{};
ProblemShape problem_shape{};
MainloopParams mainloop{};
EpilogueParams epilogue{};
KernelHardwareInfo hw_info{};
TileSchedulerParams scheduler{};
};
//
@@ -224,14 +224,15 @@ public:
}
static
int
size_t
get_workspace_size(Arguments const& args) {
return 0;
}
static
cutlass::Status
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr) {
initialize_workspace(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr,
CudaHostAdapter* cuda_adapter = nullptr) {
return Status::kSuccess;
}
@@ -58,11 +58,34 @@ public:
FastDivmodU64 const& divmod_cluster_blk_major,
int32_t log_swizzle_size,
RasterOrder raster_order) {
auto [cta_m_in_cluster, cta_n_in_cluster, _] = cute::block_id_in_cluster();
return get_work_idx_m_and_n(
blk_per_grid_dim,
divmod_cluster_shape_major,
divmod_cluster_shape_minor,
divmod_cluster_blk_major,
log_swizzle_size,
raster_order,
cta_m_in_cluster,
cta_n_in_cluster
);
}
static CUTLASS_DEVICE
cute::tuple<int32_t, int32_t>
get_work_idx_m_and_n(
uint64_t blk_per_grid_dim,
FastDivmodU64Pow2 const& divmod_cluster_shape_major,
FastDivmodU64Pow2 const& divmod_cluster_shape_minor,
FastDivmodU64 const& divmod_cluster_blk_major,
int32_t log_swizzle_size,
RasterOrder raster_order,
uint64_t cta_m_in_cluster,
uint64_t cta_n_in_cluster) {
uint64_t cluster_id, cluster_major_offset = 0, cluster_minor_offset = 0;
divmod_cluster_shape_major(cluster_id, cluster_major_offset, blk_per_grid_dim);
auto [cta_m_in_cluster, cta_n_in_cluster, _] = cute::block_id_in_cluster();
if (raster_order == RasterOrder::AlongN) {
cluster_minor_offset = cta_m_in_cluster;
}
@@ -97,7 +120,7 @@ public:
// The basic tile scheduler does not require any additional workspace
template <class ProblemShape, class ElementAccumulator>
static int
static size_t
get_workspace_size(Arguments const&, ProblemShape, KernelHardwareInfo const&, uint32_t, const uint32_t = 1) {
return 0;
}
@@ -400,7 +400,7 @@ public:
// The basic tile scheduler does not require any additional workspace
template <class ProblemShape, class ElementAccumulator>
static int
static size_t
get_workspace_size(Arguments const&, ProblemShape, KernelHardwareInfo const&, uint32_t, const uint32_t = 1) {
return 0;
}
@@ -386,7 +386,8 @@ public:
WorkTileInfo const& work_tile_info,
FrgTensorC& accumulators,
uint32_t num_barriers,
uint32_t barrier_idx) {
uint32_t barrier_idx,
uint32_t num_accumulator_mtxs = 1) {
using ElementAccumulator = typename FrgTensorC::value_type;
@@ -412,7 +413,7 @@ public:
// Reductions use BlockStripedReduce with a width of BarrierManager::ThreadCount under the hood.
// Thus, the start of the reduction space is the same across all threads in a warp group.
int reduction_offset =
(cute::size<0>(TileShape{}) * cute::size<1>(TileShape{}) * reduction_tile_idx) +
(cute::size<0>(TileShape{}) * cute::size<1>(TileShape{}) * reduction_tile_idx * num_accumulator_mtxs) +
reduction_peer_offset +
(size(accumulators) * barrier_idx * BarrierManager::ThreadCount);
@@ -444,7 +445,7 @@ public:
}
auto reduction_workspace_size = Params::get_reduction_workspace_size(
reduction_tiles, to_gemm_coord(TileShape{}), sizeof_bits<ElementAccumulator>::value);
reduction_tiles, to_gemm_coord(TileShape{}), sizeof_bits<ElementAccumulator>::value, num_accumulator_mtxs);
BarrierType* lock_workspace = reinterpret_cast<BarrierType*>(
reinterpret_cast<uint8_t*>(params.reduction_workspace_) + reduction_workspace_size);
@@ -540,7 +541,7 @@ public:
}
template <class ProblemShape, class ElementAccumulator>
static int
static size_t
get_workspace_size(
Arguments const& args,
ProblemShape problem_shape,
@@ -836,7 +837,8 @@ private:
params.divmod_cluster_shape_minor_,
params.divmod_cluster_blk_major_,
params.log_swizzle_size_,
params.raster_order_);
params.raster_order_
);
// Set the M, N, and L block offsets
work_tile_info.M_idx = work_idx_m;
@@ -0,0 +1,509 @@
/***************************************************************************************************
* Copyright (c) 2024 - 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 Sparse GEMM kernel with an epilogue that computes the absolute maximum value of the output
and a pre-activation-function auxiliary output. The auxiliary output is also (optionally)
stored to global memory.
*/
#pragma once
#include "cutlass/cutlass.h"
#include "cutlass/gemm/gemm.h"
#include "cutlass/gemm/kernel/params_sparse_base.h"
#include "cutlass/matrix_coord.h"
#include "cutlass/semaphore.h"
/////////////////////////////////////////////////////////////////////////////////////////////////
namespace cutlass {
namespace gemm {
namespace kernel {
/////////////////////////////////////////////////////////////////////////////////////////////////
template <
typename Mma_, ///! Threadblock-scoped matrix multiply-accumulate
typename Epilogue_, ///! Epilogue
typename ThreadblockSwizzle_, ///! Threadblock swizzling function
bool SplitKSerial ///! If true, code supporting split-K via serial reduction is enabled.
>
struct SparseGemmWithAbsmax {
using Mma = Mma_;
using Epilogue = Epilogue_;
using OutputOp = typename Epilogue::OutputOp;
using ThreadblockSwizzle = ThreadblockSwizzle_;
static bool const kSplitKSerial = SplitKSerial;
static int const kSparse = Mma::kSparse;
static int const kMetaSizeInBits = Mma::kMetaSizeInBits;
static int const kMaxID2 = Mma::kMaxID2;
static int const kElementsPerElementE = Mma::kElementsPerElementE;
using ElementE = typename Mma::ElementE;
using LayoutE = typename Mma::LayoutE;
using LayoutC = typename Epilogue::OutputTileIterator::Layout;
/// Warp count (concept: GemmShape)
using WarpCount = typename Mma::WarpCount;
static int const kThreadCount = 32 * WarpCount::kCount;
using ParamsA = typename Mma::IteratorA::Params;
using TensorRefA = typename Mma::IteratorA::TensorRef;
using ParamsB = typename Mma::IteratorB::Params;
using TensorRefB = typename Mma::IteratorB::TensorRef;
using ParamsE = typename Mma::IteratorE::Params;
using TensorRefE = typename Mma::IteratorE::TensorRef;
using ParamsC = typename Epilogue::OutputTileIterator::Params;
using TensorRefC = typename Epilogue::OutputTileIterator::TensorRef;
using ParamsD = typename Epilogue::OutputTileIterator::Params;
using TensorRefD = typename Epilogue::OutputTileIterator::TensorRef;
using ParamsAux = typename Epilogue::AuxOutputTileIterator::Params;
using TensorRefAux = typename Epilogue::AuxOutputTileIterator::TensorRef;
/// Argument structure
struct Arguments {
//
// Data members
//
GemmCoord problem_size;
TensorRefA ref_A;
TensorRefB ref_B;
TensorRefC ref_C;
TensorRefD ref_D;
TensorRefE ref_E;
TensorRefAux ref_Aux;
void* ptr_Vector;
typename LayoutC::Stride::Index ldr;
typename Epilogue::OutputOp::Params epilogue;
int split_k_slices;
//
// Methods
//
/// Default ctor
CUTLASS_HOST_DEVICE
Arguments(): problem_size(0, 0, 0), split_k_slices(1) {
}
/// Constructs an Arguments structure
CUTLASS_HOST_DEVICE
Arguments(
GemmCoord problem_size_,
TensorRefA ref_A_,
TensorRefB ref_B_,
TensorRefC ref_C_,
TensorRefD ref_D_,
TensorRefE ref_E_,
TensorRefAux ref_Aux_,
void* ptr_Vector_,
typename LayoutC::Stride::Index ldr_,
typename OutputOp::Params epilogue_ =
typename OutputOp::Params(),
int split_k_slices = 1
):
problem_size(problem_size_),
ref_A(ref_A_),
ref_B(ref_B_),
ref_C(ref_C_),
ref_D(ref_D_),
ref_E(ref_E_),
ref_Aux(ref_Aux_),
ptr_Vector(ptr_Vector_),
ldr(ldr_),
epilogue(epilogue_),
split_k_slices(split_k_slices) {
}
};
/// Parameters structure
struct Params : public SparseParamsBase<
ThreadblockSwizzle, ParamsA, TensorRefA, ParamsB, TensorRefB,
ParamsE, TensorRefE> {
using Base = SparseParamsBase<
ThreadblockSwizzle, ParamsA, TensorRefA, ParamsB, TensorRefB,
ParamsE, TensorRefE>;
//
// Data members
//
ParamsC params_C;
TensorRefC ref_C;
ParamsD params_D;
TensorRefD ref_D;
ParamsAux params_Aux;
TensorRefAux ref_Aux;
void* ptr_Vector;
typename LayoutC::Stride::Index ldr;
typename OutputOp::Params output_op;
int *semaphore;
//
// Methods
//
CUTLASS_HOST_DEVICE
Params() { }
CUTLASS_HOST_DEVICE
Params(
cutlass::gemm::GemmCoord const & problem_size,
cutlass::gemm::GemmCoord const & grid_tiled_shape,
TensorRefA ref_A,
TensorRefB ref_B,
TensorRefC ref_C,
TensorRefD ref_D,
TensorRefE ref_E,
TensorRefAux ref_Aux,
void* ptr_Vector,
typename LayoutC::Stride::Index ldr,
typename OutputOp::Params output_op = typename OutputOp::Params(),
int *workspace = nullptr
):
Base(problem_size, grid_tiled_shape, ref_A, ref_B, ref_E, Mma::Shape::kK),
params_C(ref_C.layout()),
ref_C(ref_C),
params_D(ref_D.layout()),
ref_D(ref_D),
output_op(output_op),
ref_Aux(ref_Aux),
params_Aux(ref_Aux.layout()),
ptr_Vector(ptr_Vector),
ldr(ldr) {
semaphore = workspace;
}
};
/// Shared memory storage structure
union SharedStorage {
typename Mma::SharedStorage main_loop;
typename Epilogue::SharedStorage epilogue;
};
//
// Methods
//
CUTLASS_HOST_DEVICE
SparseGemmWithAbsmax() { }
/// Determines whether kernel satisfies alignment
static Status can_implement(
cutlass::gemm::GemmCoord const & problem_size,
typename Mma::IteratorA::TensorRef ref_A,
typename Mma::IteratorB::TensorRef ref_B,
typename Epilogue::OutputTileIterator::TensorRef ref_C,
typename Epilogue::OutputTileIterator::TensorRef ref_D,
typename Mma::IteratorE::TensorRef ref_E) {
static int const kAlignmentA = Mma::IteratorA::AccessType::kElements;
static int const kAlignmentB = Mma::IteratorB::AccessType::kElements;
static int const kAlignmentC = Epilogue::OutputTileIterator::kElementsPerAccess;
static int const kAlignmentE = Mma::IteratorE::AccessType::kElements;
if (!TensorRef_aligned(ref_A, kAlignmentA)) {
return Status::kErrorMisalignedOperand;
}
if (!TensorRef_aligned(ref_B, kAlignmentB)) {
return Status::kErrorMisalignedOperand;
}
if (!TensorRef_aligned(ref_C, kAlignmentC)) {
return Status::kErrorMisalignedOperand;
}
if (!TensorRef_aligned(ref_D, kAlignmentC)) {
return Status::kErrorMisalignedOperand;
}
if (!TensorRef_aligned(ref_E, kAlignmentE)) {
return Status::kErrorMisalignedOperand;
}
if ((problem_size.m() % kAlignmentA) || ((problem_size.k() / kSparse) % kAlignmentA) ||
(problem_size.n() % kAlignmentB) || (problem_size.k() % kAlignmentB) ||
(problem_size.m() % kAlignmentC) || (problem_size.n() % kAlignmentC) ||
(problem_size.m() % kAlignmentE) || ((problem_size.k() / kSparse) % kAlignmentE)) {
return Status::kErrorMisalignedOperand;
}
// The k dimension has to be the multiple of the Threadblock k because out
// of bound meta data would be initialized to 0 by acync.zfill but 0 is not
// a valid meta data.
if (problem_size.k() % Mma::Shape::kK) {
return Status::kErrorMisalignedOperand;
}
// M dimension has to be multiple of 32 (sparse float) or 16 (sparse int)
// because of the row reordering of operand E
static int const kAlignmentM = (sizeof(ElementE) == 2) ? 32 : 16;
if (problem_size.m() % kAlignmentM) {
return Status::kErrorMisalignedOperand;
}
return Status::kSuccess;
}
/// Executes one GEMM
CUTLASS_DEVICE
void operator()(Params const &params, SharedStorage &shared_storage) {
// Compute threadblock location
ThreadblockSwizzle threadblock_swizzle;
cutlass::gemm::GemmCoord threadblock_tile_offset =
threadblock_swizzle.get_tile_offset(params.swizzle_log_tile);
// Early exit if CTA is out of range
if (params.grid_tiled_shape.m() <= threadblock_tile_offset.m() ||
params.grid_tiled_shape.n() <= threadblock_tile_offset.n()) {
return;
}
// Compute initial location in logical coordinates
cutlass::MatrixCoord tb_offset_A{
threadblock_tile_offset.m() * Mma::Shape::kM,
threadblock_tile_offset.k() * params.gemm_k_size / kSparse,
};
cutlass::MatrixCoord tb_offset_B{
threadblock_tile_offset.k() * params.gemm_k_size,
threadblock_tile_offset.n() * Mma::Shape::kN
};
cutlass::MatrixCoord tb_offset_E{
threadblock_tile_offset.m() * Mma::Shape::kM,
threadblock_tile_offset.k() * params.gemm_k_size / kSparse,
};
// Problem size is a function of threadblock index in the K dimension
int problem_size_k = min(
params.problem_size.k(),
(threadblock_tile_offset.k() + 1) * params.gemm_k_size);
// Compute threadblock-scoped matrix multiply-add
int gemm_k_iterations = (problem_size_k - tb_offset_B.row() + Mma::Shape::kK - 1) / Mma::Shape::kK;
// Compute position within threadblock
int thread_idx = threadIdx.x;
// Construct iterators to A, B, and E operands
typename Mma::IteratorA iterator_A(
params.params_A,
params.ref_A.data(),
{params.problem_size.m(), problem_size_k / kSparse},
thread_idx,
tb_offset_A);
typename Mma::IteratorB iterator_B(
params.params_B,
params.ref_B.data(),
{problem_size_k, params.problem_size.n()},
thread_idx,
tb_offset_B);
typename Mma::IteratorE iterator_E(
params.params_E, params.ref_E.data(),
{params.problem_size.m(),
problem_size_k / kSparse / kElementsPerElementE},
thread_idx, tb_offset_E);
// Broadcast the warp_id computed by lane 0 to ensure dependent code
// is compiled as warp-uniform.
int warp_idx = canonical_warp_idx_sync();
int lane_idx = threadIdx.x % 32;
//
// Main loop
//
// Construct thread-scoped matrix multiply
Mma mma(shared_storage.main_loop, thread_idx, warp_idx, lane_idx);
typename Mma::FragmentC accumulators;
accumulators.clear();
if (!kSplitKSerial || gemm_k_iterations > 0) {
// Compute threadblock-scoped matrix multiply-add
mma(gemm_k_iterations, accumulators, iterator_A, iterator_B, iterator_E, accumulators);
}
//
// Epilogue
//
OutputOp output_op(params.output_op);
//
// Masked tile iterators constructed from members
//
threadblock_tile_offset =
threadblock_swizzle.get_tile_offset(params.swizzle_log_tile);
//assume identity swizzle
MatrixCoord threadblock_offset(
threadblock_tile_offset.m() * Mma::Shape::kM,
threadblock_tile_offset.n() * Mma::Shape::kN
);
int block_idx = threadblock_tile_offset.m() + threadblock_tile_offset.n() * params.grid_tiled_shape.m();
// Construct the semaphore.
Semaphore semaphore(params.semaphore + block_idx, thread_idx);
// If performing a reduction via split-K, fetch the initial synchronization
if (kSplitKSerial && params.grid_tiled_shape.k() > 1) {
// Fetch the synchronization lock initially but do not block.
semaphore.fetch();
// Indicate which position in a serial reduction the output operator is currently updating
output_op.set_k_partition(threadblock_tile_offset.k(), params.grid_tiled_shape.k());
}
typename Epilogue::ElementVector *ptr_Vector = static_cast<typename Epilogue::ElementVector *>(params.ptr_Vector);
// Move to appropriate location for this output tile
if (ptr_Vector) {
ptr_Vector += threadblock_offset.column() + threadblock_tile_offset.m() * params.ldr;
}
// Tile iterator loading from source tensor.
typename Epilogue::OutputTileIterator iterator_C(
params.params_C,
params.ref_C.data(),
params.problem_size.mn(),
thread_idx,
threadblock_offset
);
// Tile iterator writing to destination tensor.
typename Epilogue::OutputTileIterator iterator_D(
params.params_D,
params.ref_D.data(),
params.problem_size.mn(),
thread_idx,
threadblock_offset
);
// Tile iterator writing to auxiliary destination tensor.
typename Epilogue::AuxOutputTileIterator iterator_Aux(
params.params_Aux,
// Only the final block writes the auxiliary tensor
((kSplitKSerial && params.grid_tiled_shape.k() > 1) &&
(params.grid_tiled_shape.k() != threadblock_tile_offset.k() + 1))
? nullptr
: params.ref_Aux.data(),
params.problem_size.mn(),
thread_idx,
threadblock_offset
);
Epilogue epilogue(
shared_storage.epilogue,
thread_idx,
warp_idx,
lane_idx);
// Wait on the semaphore - this latency may have been covered by iterator construction
if (kSplitKSerial && params.grid_tiled_shape.k() > 1) {
// For subsequent threadblocks, the source matrix is held in the 'D' tensor.
if (threadblock_tile_offset.k()) {
iterator_C = iterator_D;
}
semaphore.wait(threadblock_tile_offset.k());
__threadfence();
}
// Execute the epilogue operator to update the destination tensor.
epilogue(output_op,
// Only the final block uses Vector
((kSplitKSerial && params.grid_tiled_shape.k() > 1) &&
(params.grid_tiled_shape.k() != threadblock_tile_offset.k() + 1))
? nullptr
: ptr_Vector,
iterator_D,
accumulators,
iterator_C,
iterator_Aux,
params.problem_size.mn(),
threadblock_offset);
//
// Release the semaphore
//
if (kSplitKSerial && params.grid_tiled_shape.k() > 1) {
int lock = 0;
if (params.grid_tiled_shape.k() == threadblock_tile_offset.k() + 1) {
// The final threadblock resets the semaphore for subsequent grids.
lock = 0;
}
else {
// Otherwise, the semaphore is incremented
lock = threadblock_tile_offset.k() + 1;
}
__threadfence();
semaphore.release(lock);
}
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace kernel
} // namespace gemm
} // namespace cutlass
@@ -334,8 +334,8 @@ public:
// Convert CTA-level work tile info to cluster-level tile coord
CUTLASS_DEVICE
cute::Coord<int,int,int,int>
tile_info_to_coord_mnkl(WorkTileInfo work_tile_info) const {
auto
work_tile_to_cluster_coord_mnkl(WorkTileInfo work_tile_info) const {
// TileScheduler works at CTA-level, kernel works at cluster-level
int m_coord = idx2crd(work_tile_info.M_idx / scheduler_params.cluster_shape_m_,
scheduler_params.problem_tiles_m_);
+42 -65
View File
@@ -119,35 +119,32 @@ public:
// Data members
//
GemmUniversalMode mode;
GemmCoord problem_size;
int batch_count;
GemmUniversalMode mode = GemmUniversalMode::kGemm;
GemmCoord problem_size{};
int batch_count{1};
typename EpilogueOutputOp::Params epilogue;
typename EpilogueOutputOp::Params epilogue{};
void const * ptr_A;
void const * ptr_B;
void const * ptr_C;
void * ptr_D;
void const * ptr_A{nullptr};
void const * ptr_B{nullptr};
void const * ptr_C{nullptr};
void * ptr_D{nullptr};
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_C;
int64_t batch_stride_D;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
int64_t batch_stride_C{0};
int64_t batch_stride_D{0};
typename LayoutA::Stride::Index lda;
typename LayoutB::Stride::Index ldb;
typename LayoutC::Stride::Index ldc;
typename LayoutC::Stride::Index ldd;
typename LayoutA::Stride::Index lda{0};
typename LayoutB::Stride::Index ldb{0};
typename LayoutC::Stride::Index ldc{0};
typename LayoutC::Stride::Index ldd{0};
//
// Methods
//
Arguments():
mode(GemmUniversalMode::kGemm),
batch_count(1),
ptr_A(nullptr), ptr_B(nullptr), ptr_C(nullptr), ptr_D(nullptr) { }
Arguments() = default;
/// constructs an arguments structure
Arguments(
@@ -173,7 +170,8 @@ public:
batch_count(batch_count),
epilogue(epilogue),
ptr_A(ptr_A), ptr_B(ptr_B), ptr_C(ptr_C), ptr_D(ptr_D),
batch_stride_A(batch_stride_A), batch_stride_C(batch_stride_C), batch_stride_D(batch_stride_D),
batch_stride_A(batch_stride_A), batch_stride_B(0),
batch_stride_C(batch_stride_C), batch_stride_D(batch_stride_D),
lda(lda), ldb(ldb), ldc(ldc), ldd(ldd) {
}
@@ -206,64 +204,43 @@ public:
/// Parameters structure
struct Params {
cutlass::gemm::GemmCoord problem_size;
cutlass::gemm::GemmCoord grid_tiled_shape;
int swizzle_log_tile;
cutlass::gemm::GemmCoord problem_size{};
cutlass::gemm::GemmCoord grid_tiled_shape{};
int swizzle_log_tile{0};
// Mma1 Iterator A and B params
typename Mma1::IteratorA::Params params_A_mma1;
typename Mma1::IteratorB::Params params_B_mma1;
typename Mma1::IteratorA::Params params_A_mma1{};
typename Mma1::IteratorB::Params params_B_mma1{};
// Mma2 Iterator A and B params
typename Mma2::IteratorA::Params params_A_mma2;
typename Mma2::IteratorB::Params params_B_mma2;
typename Mma2::IteratorA::Params params_A_mma2{};
typename Mma2::IteratorB::Params params_B_mma2{};
typename Epilogue::OutputTileIterator::Params params_C;
typename Epilogue::OutputTileIterator::Params params_D;
typename Epilogue::OutputTileIterator::Params params_C{};
typename Epilogue::OutputTileIterator::Params params_D{};
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
GemmUniversalMode mode;
int batch_count;
int gemm_k_size;
GemmUniversalMode mode = cutlass::gemm::GemmUniversalMode::kGemm;
int batch_count {0};
int gemm_k_size {0};
void * ptr_A;
void * ptr_B;
void * ptr_C;
void * ptr_D;
void * ptr_A{nullptr};
void * ptr_B{nullptr};
void * ptr_C{nullptr};
void * ptr_D{nullptr};
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_C;
int64_t batch_stride_D;
int64_t batch_stride_A {0};
int64_t batch_stride_B {0};
int64_t batch_stride_C {0};
int64_t batch_stride_D {0};
int *semaphore;
int *semaphore{nullptr};
//
// Methods
//
CUTLASS_HOST_DEVICE
Params():
swizzle_log_tile(0),
params_A_mma1(0),
params_B_mma1(0),
params_A_mma2(0),
params_B_mma2(0),
params_C(0),
params_D(0),
batch_count(0),
gemm_k_size(0),
mode(cutlass::gemm::GemmUniversalMode::kGemm),
ptr_A(nullptr),
ptr_B(nullptr),
ptr_C(nullptr),
ptr_D(nullptr),
batch_stride_A(0),
batch_stride_B(0),
batch_stride_C(0),
batch_stride_D(0),
semaphore(nullptr) { }
Params() = default;
CUTLASS_HOST_DEVICE
Params(
@@ -125,9 +125,9 @@ struct PersistentTileSchedulerSm90Params {
int max_swizzle_size,
RasterOrderOptions raster_order_option
) {
CUTLASS_UNUSED(hw_info);
// Round up to nearest multiple of swizzle_size along each mode
auto log_swizzle_size = get_log_swizzle_size(problem_blocks.x, problem_blocks.y, max_swizzle_size);
auto problem_blocks_m = round_up(problem_blocks.x, (1 << log_swizzle_size) * cluster_shape.m());
@@ -619,9 +619,15 @@ struct PersistentTileSchedulerSm90StreamKParams {
);
uint64_t ctas_per_wave = grid.x * grid.y;
auto cluster_size = cluster_shape.m() * cluster_shape.n();
// The number of output tiles to be computed in stream-K and data-parallel fashion, respectively.
uint32_t sk_tiles = get_num_sk_tiles(output_tiles, ctas_per_wave, k_tiles_per_output_tile, decomposition_mode);
uint32_t sk_tiles = get_num_sk_tiles(
output_tiles,
ctas_per_wave,
cluster_size,
k_tiles_per_output_tile,
decomposition_mode
);
uint64_t dp_tiles = output_tiles - sk_tiles;
// Calculate the number of work units covering the data-parallel and stream-K tiles.
@@ -634,24 +640,8 @@ struct PersistentTileSchedulerSm90StreamKParams {
// is needed per data-parallel tile.
uint64_t dp_units = dp_tiles;
// Number of k iterations computed by the stream-K units as a whole
uint64_t k_tiles_sk_total = k_tiles_per_output_tile * sk_tiles;
// If there are stream-K tiles to compute and a sufficiently large number of k iterations
// across them, they will be covered by a single wave of persistent threadblocks. Thus, there
// will be as many work units as there are threadblocks in a single wave.
//
// When the total k iterations across stream-K tiles is too small to justify distributing
// across an entire wave of blocks, we instead distribute the iterations over a smaller
// set of blocks.
// Calculate the number of stream-K units that would be needed if each stream-K unit
// computed the minimum allowable k iterations. Truncate this to be in units of clusters.
auto cluster_size = cluster_shape.m() * cluster_shape.n();
uint64_t min_sized_sk_units = (k_tiles_sk_total / min_iters_per_sk_unit_);
min_sized_sk_units = (min_sized_sk_units / cluster_size) * cluster_size;
uint64_t sk_units = platform::min(ctas_per_wave, min_sized_sk_units);
uint64_t ctas_per_sk_wave = ctas_per_wave;
uint64_t sk_units = get_num_sk_units(cluster_shape, ctas_per_sk_wave, sk_tiles, k_tiles_per_output_tile);
if (decomposition_mode == DecompositionMode::DataParallel ||
(decomposition_mode == DecompositionMode::Heuristic && sk_tiles == 0) ||
@@ -869,7 +859,13 @@ struct PersistentTileSchedulerSm90StreamKParams {
// Returns the number of stream-K tiles that will be computed amongst `output_tiles` total
// output tiles on a device with `ctas_per_wave` CTAs in each wave.
static uint32_t
get_num_sk_tiles(uint64_t output_tiles, uint64_t ctas_per_wave, uint32_t k_tiles_per_output_tile, DecompositionMode decomposition_mode) {
get_num_sk_tiles(
uint64_t output_tiles,
uint64_t ctas_per_wave,
uint64_t cluster_size,
uint32_t k_tiles_per_output_tile,
DecompositionMode decomposition_mode
) {
uint32_t full_waves = static_cast<uint32_t>(output_tiles / ctas_per_wave);
uint32_t total_waves = static_cast<uint32_t>((output_tiles + ctas_per_wave - 1) / ctas_per_wave);
@@ -878,6 +874,14 @@ struct PersistentTileSchedulerSm90StreamKParams {
return 0;
}
// If there is wave quantization, assign the first two waves worth of tiles to be
// covered by stream-K work and the remainder to be data-parallel. Since we know
// that full_waves == total_waves - 1 in this case, the number of data-parallel
// waves is simply full_waves-1 (unless full_waves == 0).
uint32_t dp_waves = full_waves > 1 ? full_waves - 1 : 0;
uint64_t dp_tiles = dp_waves * ctas_per_wave;
uint64_t sk_tiles = output_tiles - dp_tiles;
if (decomposition_mode == DecompositionMode::Heuristic) {
if (full_waves == total_waves || k_tiles_per_output_tile <= min_iters_per_sk_unit_) {
// All tiles will be data-parallel tiles if there is either no quantization
@@ -892,24 +896,28 @@ struct PersistentTileSchedulerSm90StreamKParams {
// Rudimentary heuristic: prefer data-parallel decomposition if we have more than
// one wave and the tail wave is more than half full. This is subject to change.
uint64_t tail_tiles = output_tiles - (full_waves * ctas_per_wave);
if (tail_tiles >= (ctas_per_wave / 2)) {
if (2 * tail_tiles >= ctas_per_wave) {
return 0;
}
}
// If there is wave quantization, assign the first two waves worth of tiles to be
// covered by stream-K work and the remainder to be data-parallel. Since we know
// that full_waves == total_waves - 1 in this case, the number of data-parallel
// waves is simply full_waves-1 (unless full_waves == 0).
uint32_t dp_waves = full_waves > 0 ? full_waves - 1 : 0;
uint64_t dp_tiles = dp_waves * ctas_per_wave;
return static_cast<uint32_t>(output_tiles - dp_tiles);
return static_cast<uint32_t>(sk_tiles);
}
CUTLASS_HOST_DEVICE
static uint64_t
get_num_sk_units(GemmCoord cluster_shape, uint64_t ctas_per_wave, uint32_t sk_tiles, uint32_t k_tiles_per_output_tile) {
get_num_sk_units(GemmCoord cluster_shape, uint64_t ctas_per_sk_wave, uint32_t sk_tiles, uint32_t k_tiles_per_output_tile) {
// If there are stream-K tiles to compute and a sufficiently large number of k iterations
// across them, they will be covered by a single wave of persistent threadblocks. Thus, there
// will be as many work units as there are threadblocks in a single wave.
//
// When the total k iterations across stream-K tiles is too small to justify distributing
// across an entire wave of blocks, we instead distribute the iterations over a smaller
// set of blocks.
// Calculate the number of stream-K units that would be needed if each stream-K unit
// computed the minimum allowable k iterations. Truncate this to be in units of clusters.
// Number of k iterations computed by the stream-K units as a whole
uint64_t k_tiles_sk_total = k_tiles_per_output_tile * sk_tiles;
@@ -919,7 +927,7 @@ struct PersistentTileSchedulerSm90StreamKParams {
uint64_t min_sized_sk_units = (k_tiles_sk_total / min_iters_per_sk_unit_);
min_sized_sk_units = (min_sized_sk_units / cluster_size) * cluster_size;
uint64_t sk_units = platform::min(ctas_per_wave, min_sized_sk_units);
uint64_t sk_units = platform::min(ctas_per_sk_wave, min_sized_sk_units);
return sk_units;
}
@@ -934,9 +942,9 @@ struct PersistentTileSchedulerSm90StreamKParams {
// Calculates the size of the workspace needed for holding partial outputs from splits
CUTLASS_HOST_DEVICE
static int
get_reduction_workspace_size(uint64_t num_tiles, GemmCoord tile_shape, uint32_t accumulator_bits) {
get_reduction_workspace_size(uint64_t num_tiles, GemmCoord tile_shape, uint32_t accumulator_bits, uint32_t num_accumulator_mtxs = 1) {
auto output_tile_size = tile_shape.m() * tile_shape.n();
auto workspace_bits = accumulator_bits * output_tile_size * num_tiles;
auto workspace_bits = accumulator_bits * output_tile_size * num_tiles * num_accumulator_mtxs;
return round_up_to_l2_alignment(bits_to_bytes(static_cast<int>(workspace_bits)));
}
@@ -957,7 +965,8 @@ struct PersistentTileSchedulerSm90StreamKParams {
uint32_t mma_warp_groups,
uint32_t barrier_bits,
uint32_t accumulator_bits,
uint32_t epilogue_subtile = 1) {
uint32_t epilogue_subtile = 1,
uint32_t num_accumulator_mtxs = 1) {
auto log_swizzle_size = UnderlyingParams::get_log_swizzle_size(problem_blocks.x, problem_blocks.y, max_swizzle);
problem_blocks.x = round_up(problem_blocks.x, (1 << log_swizzle_size) * cluster_shape.m());
@@ -975,7 +984,7 @@ struct PersistentTileSchedulerSm90StreamKParams {
(decomposition_mode == DecompositionMode::Heuristic && splits > 1)) {
// Basic split-K variant requires workspace for all output tiles
barrier_workspace_size = get_barrier_workspace_size(output_tiles, mma_warp_groups, barrier_bits);
reduction_workspace_size = get_reduction_workspace_size(output_tiles, tile_shape, accumulator_bits);
reduction_workspace_size = get_reduction_workspace_size(output_tiles, tile_shape, accumulator_bits, num_accumulator_mtxs);
}
else {
KernelHardwareInfo new_hw_info;
@@ -995,8 +1004,16 @@ struct PersistentTileSchedulerSm90StreamKParams {
raster_order_option
);
uint64_t ctas_per_wave = grid.x * grid.y;
uint32_t sk_tiles = get_num_sk_tiles(output_tiles, ctas_per_wave, static_cast<uint32_t>(k_tiles_per_output_tile), decomposition_mode);
uint64_t sk_units = get_num_sk_units(cluster_shape, ctas_per_wave, sk_tiles, k_tiles_per_output_tile);
uint64_t cluster_size = cluster_shape.m() * cluster_shape.n();
uint32_t sk_tiles = get_num_sk_tiles(
output_tiles,
ctas_per_wave,
cluster_size,
static_cast<uint32_t>(k_tiles_per_output_tile),
decomposition_mode
);
uint64_t ctas_per_sk_wave = ctas_per_wave;
uint64_t sk_units = get_num_sk_units(cluster_shape, ctas_per_sk_wave, sk_tiles, k_tiles_per_output_tile);
uint64_t dp_tiles = output_tiles - sk_tiles;
uint64_t reduction_tiles = sk_tiles;
@@ -1012,7 +1029,7 @@ struct PersistentTileSchedulerSm90StreamKParams {
// written its accumulator to scratch space. The separate reduction unit will only begin
// performing the reduction when the barrier has reached the number of peers for the output tile.
barrier_workspace_size = get_barrier_workspace_size(sk_tiles, mma_warp_groups, barrier_bits);
reduction_workspace_size = get_reduction_workspace_size(reduction_tiles, tile_shape, accumulator_bits);
reduction_workspace_size = get_reduction_workspace_size(reduction_tiles, tile_shape, accumulator_bits, num_accumulator_mtxs);
}
}
#endif // !defined(__CUDACC_RTC__)
@@ -1030,7 +1047,7 @@ struct PersistentTileSchedulerSm90StreamKParams {
// Get the amount of scratch workspace needed for the kernel. This variant of the method should only be used when
// problem_shape and tile_shape contain modes of only rank 1.
static int
static size_t
get_workspace_size(
BatchedGemmCoord problem_shape,
GemmCoord tile_shape,
@@ -1043,7 +1060,8 @@ struct PersistentTileSchedulerSm90StreamKParams {
uint32_t mma_warp_groups,
uint32_t barrier_bits,
uint32_t element_accumulator_bits,
uint32_t epilogue_subtile) {
uint32_t epilogue_subtile,
uint32_t num_accumulator_mtxs) {
dim3 problem_blocks = UnderlyingParams::get_tiled_cta_shape_mnl(problem_shape, tile_shape, cluster_shape);
uint32_t k_tiles_per_output_tile = (problem_shape.k() + tile_shape.k() - 1) / tile_shape.k();
@@ -1061,14 +1079,15 @@ struct PersistentTileSchedulerSm90StreamKParams {
mma_warp_groups,
barrier_bits,
element_accumulator_bits,
epilogue_subtile
epilogue_subtile,
num_accumulator_mtxs
);
}
// Version of get_workspace_size that takes in as input the number of CTAs in the M and N dimensions.
// This is useful for calculating the tiled shape when a mode of problem and/or CTA shape has rank > 1,
// for which using CuTe algebra for calculating tile shapes is easiest.
static int
static size_t
get_workspace_size(
dim3 problem_blocks,
uint32_t k_tiles_per_output_tile,
@@ -1082,7 +1101,8 @@ struct PersistentTileSchedulerSm90StreamKParams {
uint32_t mma_warp_groups,
uint32_t barrier_bits,
uint32_t element_accumulator_bits,
uint32_t epilogue_subtile = 1) {
uint32_t epilogue_subtile = 1,
uint32_t num_accumulator_mtxs = 1) {
int barrier_workspace_size = 0;
int reduction_workspace_size = 0;
@@ -1103,7 +1123,8 @@ struct PersistentTileSchedulerSm90StreamKParams {
mma_warp_groups,
barrier_bits,
element_accumulator_bits,
epilogue_subtile
epilogue_subtile,
num_accumulator_mtxs
);
#endif
@@ -1170,7 +1191,8 @@ struct PersistentTileSchedulerSm90StreamKParams {
uint32_t mma_warp_groups,
uint32_t barrier_bits,
uint32_t element_accumulator_bits,
uint32_t epilogue_subtile = 1) {
uint32_t epilogue_subtile = 1,
uint32_t num_accumulator_mtxs = 1) {
#if !defined(__CUDACC_RTC__)
int barrier_workspace_size = 0;
@@ -1191,7 +1213,8 @@ struct PersistentTileSchedulerSm90StreamKParams {
mma_warp_groups,
barrier_bits,
element_accumulator_bits,
epilogue_subtile
epilogue_subtile,
num_accumulator_mtxs
);
if (barrier_workspace_size > 0) {
@@ -1301,9 +1324,9 @@ struct PersistentTileSchedulerSm90GroupParams {
int max_swizzle_size,
RasterOrderOptions raster_order_option
) {
CUTLASS_UNUSED(hw_info);
// Round up to nearest multiple of swizzle_size along each mode
auto log_swizzle_size = get_log_swizzle_size(problem_blocks.x, problem_blocks.y, max_swizzle_size);
auto problem_blocks_m = round_up(problem_blocks.x, (1 << log_swizzle_size) * cluster_shape.m());
+34 -53
View File
@@ -110,32 +110,29 @@ public:
// Data members
//
GemmUniversalMode mode;
GemmCoord problem_size;
int batch_count;
GemmUniversalMode mode{GemmUniversalMode::kGemm};
GemmCoord problem_size{};
int batch_count{1};
typename EpilogueOutputOp::Params epilogue;
typename EpilogueOutputOp::Params epilogue{};
void const * ptr_A;
void const * ptr_B;
void * ptr_D;
void const * ptr_A{nullptr};
void const * ptr_B{nullptr};
void * ptr_D{nullptr};
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_D;
int64_t batch_stride_A{0};
int64_t batch_stride_B{0};
int64_t batch_stride_D{0};
typename LayoutA::Stride::Index lda;
typename LayoutB::Stride::Index ldb;
typename LayoutC::Stride::Index ldd;
typename LayoutA::Stride::Index lda{0};
typename LayoutB::Stride::Index ldb{0};
typename LayoutC::Stride::Index ldd{0};
//
// Methods
//
Arguments():
mode(GemmUniversalMode::kGemm),
batch_count(1),
ptr_A(nullptr), ptr_B(nullptr), ptr_D(nullptr) { }
Arguments() = default;
/// constructs an arguments structure
Arguments(
@@ -161,7 +158,7 @@ public:
batch_stride_A(batch_stride_A), batch_stride_B(batch_stride_B), batch_stride_D(batch_stride_D),
lda(lda), ldb(ldb), ldd(ldd) {
}
/// Returns arguments for the transposed problem sizes
Arguments transposed_problem_size() const {
Arguments args(*this);
@@ -190,50 +187,34 @@ public:
/// Parameters structure
struct Params {
cutlass::gemm::GemmCoord problem_size;
cutlass::gemm::GemmCoord grid_tiled_shape;
int swizzle_log_tile;
cutlass::gemm::GemmCoord problem_size{};
cutlass::gemm::GemmCoord grid_tiled_shape{};
int swizzle_log_tile{0};
typename Mma::IteratorA::Params params_A;
typename Mma::IteratorB::Params params_B;
typename Epilogue::OutputTileIterator::Params params_D;
typename Mma::IteratorA::Params params_A{};
typename Mma::IteratorB::Params params_B{};
typename Epilogue::OutputTileIterator::Params params_D{};
typename EpilogueOutputOp::Params output_op;
typename EpilogueOutputOp::Params output_op{};
GemmUniversalMode mode;
int batch_count;
int gemm_k_size;
GemmUniversalMode mode = cutlass::gemm::GemmUniversalMode::kGemm;
int batch_count {0};
int gemm_k_size {0};
void * ptr_A;
void * ptr_B;
void * ptr_D;
void * ptr_A{nullptr};
void * ptr_B{nullptr};
void * ptr_D{nullptr};
int64_t batch_stride_A;
int64_t batch_stride_B;
int64_t batch_stride_D;
int64_t batch_stride_A {0};
int64_t batch_stride_B {0};
int64_t batch_stride_D {0};
int *semaphore;
int *semaphore{nullptr};
//
// Methods
//
CUTLASS_HOST_DEVICE
Params():
swizzle_log_tile(0),
params_A(0),
params_B(0),
params_D(0),
batch_count(0),
gemm_k_size(0),
mode(cutlass::gemm::GemmUniversalMode::kGemm),
ptr_A(nullptr),
ptr_B(nullptr),
ptr_D(nullptr),
batch_stride_A(0),
batch_stride_B(0),
batch_stride_D(0),
semaphore(nullptr) { }
Params() = default;
CUTLASS_HOST_DEVICE
Params(