#ifndef GPU_NVIDIA_CUDNN_MATMUL_LT_IMPL_HPP
#define GPU_NVIDIA_CUDNN_MATMUL_LT_IMPL_HPP
#include <cublasLt.h>
#include "cudnn.h"
#include <cublas_v2.h>
#include "common/float16.hpp"
#include "gpu/nvidia/cudnn_matmul_base_impl.hpp"
#include "gpu/nvidia/cudnn_matmul_executor.hpp"
#include "gpu/nvidia/engine.hpp"
#include "gpu/nvidia/stream.hpp"
#include "gpu/nvidia/sycl_cuda_scoped_context.hpp"
#include "gpu/nvidia/sycl_cuda_utils.hpp"
namespace dnnl {
namespace impl {
namespace gpu {
namespace nvidia {
struct cublas_lt_params : cublas_base_params {
status_t init(impl::engine_t *engine, const memory_desc_t *src_md,
const memory_desc_t *weights_md, const memory_desc_t *dst_md,
const memory_desc_t *bias_md, const primitive_attr_t *attr,
bool batched, bool with_bias) {
CHECK(get_cublas_data_type(src_md->data_type, src_type_));
CHECK(get_cublas_data_type(weights_md->data_type, weights_type_));
CHECK(get_cublas_data_type(dst_md->data_type, dst_type_));
auto src_d = memory_desc_wrapper(*src_md);
auto weights_d = memory_desc_wrapper(*weights_md);
auto dst_d = memory_desc_wrapper(*dst_md);
isbatched_ = batched && dst_d.dims()[0];
has_runtime_params_ = src_d.has_runtime_dims_or_strides()
|| dst_d.has_runtime_dims_or_strides()
|| weights_d.has_runtime_dims_or_strides();
with_dst_scale_ = !attr->scales_.get(DNNL_ARG_DST).has_default_values();
if (with_dst_scale_) {
if (attr->scales_.get_mask(DNNL_ARG_DST) > 0) {
multi_dst_scale_ = true;
}
}
check_imma_case(src_d, weights_d, dst_d);
with_bias_ = with_bias;
bool dst_row_major = !is_md_col_major(dst_d);
if (with_bias_) {
if (has_runtime_params_) {
return status::unimplemented;
} else {
bias_dt_mismatch_ = (bias_md->data_type != dst_md->data_type);
if (imma_case_) {
with_separate_bias_ = true;
if (dst_d.data_type() == dnnl_s8) {
reorder_required_ = true;
} else {
reorder_required_ = false;
}
} else {
if (bias_dt_mismatch_ || dst_row_major) {
with_separate_bias_ = true;
reorder_required_ = false;
}
if (!with_separate_bias_ && !dst_row_major) {
memory_desc_wrapper bias_d
= memory_desc_wrapper(*bias_md);
if ((bias_d.dims()[1 + isbatched_]
!= static_cast<dim_t>(M_)
|| bias_d.dims()[0 + isbatched_] != 1)
|| M_ == 1 || N_ == 1 || has_runtime_params_) {
with_separate_bias_ = true;
reorder_required_ = false;
}
}
}
}
}
with_bias_epilogue_ = with_bias_ && !with_separate_bias_;
if (with_eltwise(0, attr) || with_eltwise(1, attr)) {
if (dst_d.has_runtime_dims_or_strides()) {
return status::unimplemented;
} else {
with_relu_ = eltwise_algo(attr) == alg_kind::eltwise_relu;
if (!with_relu_ || dst_row_major || with_separate_bias_) {
with_separate_eltwise_ = true;
}
}
}
with_relu_epilogue_ = with_relu_ && !with_separate_eltwise_;
if ((with_separate_bias_ && !imma_case_) || with_separate_eltwise_) {
return status::unimplemented;
}
if (!imma_case_ && !with_relu_epilogue_ && !with_bias_epilogue_) {
return status::unimplemented;
}
if (imma_case_ && with_relu_epilogue_) { return status::unimplemented; }
if (imma_case_ && with_bias_epilogue_) {
with_separate_bias_ = true;
with_bias_epilogue_ = false;
}
if (with_dst_scale_
&& (with_bias_epilogue_ || with_separate_bias_
|| with_relu_epilogue_)) {
multi_dst_scale_ = true;
}
const bool supports_ampere_layout = has_imma_ampere_layout_support(
utils::downcast<nvidia::engine_t *>(engine)->device());
imma_ampere_case_ = imma_case_ && supports_ampere_layout;
imma_plain_case_ = imma_case_ && !imma_ampere_case_;
if (with_sum(attr)) { post_op_sum_ = sum_scale(attr); }
alpha_beta_size_bytes_ = dst_d.data_type_size();
if (dst_d.data_type() == dnnl_s8) {
alpha_beta_size_bytes_ = sizeof(float);
}
alpha_ = std::malloc(alpha_beta_size_bytes_);
beta_ = std::malloc(alpha_beta_size_bytes_);
if (!has_runtime_params_) {
CHECK(set_params(src_d, weights_d, dst_d, engine));
}
return status::success;
}
status_t init_from_params(const std::shared_ptr<cublas_lt_params> &other) {
if (!other) { return status::invalid_arguments; }
src_type_ = other->src_type_;
weights_type_ = other->weights_type_;
dst_type_ = other->dst_type_;
isbatched_ = other->isbatched_;
has_runtime_params_ = other->has_runtime_params_;
with_dst_scale_ = other->with_dst_scale_;
multi_dst_scale_ = other->multi_dst_scale_;
with_bias_ = other->with_bias_;
bias_dt_mismatch_ = other->bias_dt_mismatch_;
with_separate_bias_ = other->with_separate_bias_;
reorder_required_ = other->reorder_required_;
with_bias_epilogue_ = other->with_bias_epilogue_;
with_relu_epilogue_ = other->with_relu_epilogue_;
imma_ampere_case_ = other->imma_ampere_case_;
imma_plain_case_ = other->imma_plain_case_;
alpha_beta_size_bytes_ = other->alpha_beta_size_bytes_;
alpha_ = std::malloc(alpha_beta_size_bytes_);
beta_ = std::malloc(alpha_beta_size_bytes_);
return status::success;
}
status_t set_params(const memory_desc_wrapper &src_d,
const memory_desc_wrapper &weights_d,
const memory_desc_wrapper &dst_d, impl::engine_t *engine) {
batch_count_ = isbatched_ ? dst_d.dims()[0] : 1;
M_ = static_cast<uint64_t>(dst_d.dims()[isbatched_ + 1]);
N_ = static_cast<uint64_t>(dst_d.dims()[isbatched_ + 0]);
K_ = static_cast<uint64_t>(src_d.dims()[isbatched_ + 1]);
if (imma_case_) {
w_blocked_ = is_md_col32(weights_d);
dst_blocked_ = is_md_col32(dst_d);
src_blocked_ = src_d.is_cublaslt_blocked_desc();
CUBLAS_EXECUTE_FUNC(cublasLtMatrixTransformDescCreate, &trans_desc_,
CUDA_R_32I);
if (!imma_ampere_case_) {
const bool all_plain_layout = src_d.is_plain()
&& weights_d.is_plain() && dst_d.is_plain();
const bool is_tnn = is_md_col_major(src_d)
&& !is_md_col_major(weights_d)
&& is_md_col_major(dst_d);
const bool are_dims_ok
= M_ % 4 == 0 && K_ % 4 == 0 && N_ % 4 == 0;
if (!(is_tnn && all_plain_layout && are_dims_ok)) {
return status::unimplemented;
}
} else {
CHECK(init_imma_ampere_sizes(src_d, weights_d, dst_d));
}
}
CHECK(set_gemm_params(src_d, weights_d, dst_d));
auto &sycl_engine = *utils::downcast<nvidia::engine_t *>(engine);
impl::stream_t *service_stream;
CHECK(sycl_engine.get_service_stream(service_stream));
auto cuda_stream = utils::downcast<nvidia::stream_t *>(service_stream);
auto cublas_handle = cuda_stream->get_cublas_handle();
auto lt_handle = (cublasLtHandle_t)cublas_handle;
CHECK(init_scratchpad_size(lt_handle, src_d, weights_d, dst_d));
return status::success;
}
void check_imma_case(const memory_desc_wrapper &src_d,
const memory_desc_wrapper &weights_d,
const memory_desc_wrapper &dst_d) {
if (src_d.data_type() == dnnl_s8 && weights_d.data_type() == dnnl_s8
&& (dst_d.data_type() == dnnl_s32
|| dst_d.data_type() == dnnl_s8)) {
w_blocked_ = is_md_col32(weights_d);
bool weights_supported = weights_d.has_runtime_dims_or_strides()
|| w_blocked_ || weights_d.is_plain();
src_blocked_ = src_d.is_cublaslt_blocked_desc();
bool src_supported = src_d.has_runtime_dims_or_strides()
|| src_blocked_ || src_d.is_plain();
dst_blocked_ = is_md_col32(dst_d);
bool dst_supported = dst_d.has_runtime_dims_or_strides()
|| dst_blocked_ || dst_d.is_plain();
imma_case_ = weights_supported && src_supported && dst_supported;
}
}
status_t set_gemm_params(const memory_desc_wrapper &src_d,
const memory_desc_wrapper &weights_d,
const memory_desc_wrapper &dst_d) {
trans_c_ = !is_md_col_major(dst_d);
trans_a_ = !is_md_col_major(weights_d);
trans_b_ = !is_md_col_major(src_d);
if (imma_ampere_case_) {
if (w_blocked_) { trans_a_ = false; }
if (dst_blocked_) { trans_c_ = false; }
}
auto dst_dt = dst_d.data_type();
if (imma_case_ && reorder_required_) { dst_dt = dnnl_s32; }
if (dst_dt == dnnl_s8 || dst_dt == dnnl_bf16) {
CHECK(get_cublas_data_type(dnnl_f32, acc_type_));
} else {
CHECK(get_cublas_data_type(dst_dt, acc_type_));
}
CHECK(get_cublas_data_type(src_d.data_type(), src_type_));
CHECK(get_cublas_data_type(weights_d.data_type(), weights_type_));
CHECK(get_cublas_data_type(dst_dt, dst_type_));
if (dst_dt == dnnl_f16 && src_d.data_type() == dnnl_f16
&& weights_d.data_type() == dnnl_f16) {
compute_type_ = CUBLAS_COMPUTE_16F;
} else if (src_d.data_type() == dnnl_s8
&& weights_d.data_type() == dnnl_s8
&& (dst_dt == dnnl_s32 || dst_dt == dnnl_s8)) {
compute_type_ = CUBLAS_COMPUTE_32I;
}
CUBLAS_EXECUTE_FUNC(cublasLtMatmulDescCreate, &operation_desc_,
compute_type_, acc_type_);
if (batch_count_ != 1) {
stride_a_ = get_batch_stride(weights_d);
stride_b_ = src_d.is_cublaslt_blocked_desc()
? (K_ * N_)
: get_batch_stride(src_d);
stride_c_ = get_batch_stride(dst_d);
if (src_d.dims()[0] > weights_d.dims()[0]) {
stride_a_ = 0;
stride_a_blocked_ = 0;
} else if (src_d.dims()[0] < weights_d.dims()[0]) {
stride_b_ = 0;
stride_b_blocked_ = 0;
}
}
if (!imma_ampere_case_) {
create_non_blocked_layouts();
} else {
create_blocked_layouts();
}
return status::success;
}
status_t init_imma_ampere_sizes(const memory_desc_wrapper &src_d,
const memory_desc_wrapper &weights_d,
const memory_desc_wrapper &dst_d) {
a_blocked_ld_ = c_blocked_ld_ = M_ * 32;
b_blocked_ld_ = ceildiv(N_, static_cast<uint64_t>(32)) * 32 * 32;
stride_b_blocked_
= ceildiv(K_, static_cast<uint64_t>(32)) * b_blocked_ld_;
source_size_ = batch_count_ * stride_b_blocked_ * src_d.data_type_size()
* 32;
stride_a_blocked_
= ceildiv(K_, static_cast<uint64_t>(32)) * a_blocked_ld_;
if (!w_blocked_) {
weight_size_ = batch_count_ * stride_a_blocked_
* weights_d.data_type_size() * 32;
}
stride_c_blocked_
= ceildiv(N_, static_cast<uint64_t>(32)) * c_blocked_ld_;
if (!dst_blocked_) {
dest_size_ = batch_count_ * stride_c_blocked_
* dst_d.data_type_size() * 32;
}
return status::success;
}
status_t init_scratchpad_size(cublasLtHandle_t lt_handle,
const memory_desc_wrapper &src_d,
const memory_desc_wrapper &weights_d,
const memory_desc_wrapper &dst_d) {
reorder_scratch_size_ = 0;
CUBLAS_EXECUTE_FUNC(cublasLtMatmulPreferenceCreate, &preference_);
uint64_t workspace_size = getenv_int_user(
"CUBLASLT_MAX_MATMUL_WORKSPACE_SIZE", 1073741824);
CUBLAS_EXECUTE_FUNC(cublasLtMatmulPreferenceSetAttribute, preference_,
CUBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES, &workspace_size,
sizeof(workspace_size));
cublasLtReductionScheme_t reduction_scheme
= CUBLASLT_REDUCTION_SCHEME_MASK;
CUBLAS_EXECUTE_FUNC(cublasLtMatmulPreferenceSetAttribute, preference_,
CUBLASLT_MATMUL_PREF_REDUCTION_SCHEME_MASK, &reduction_scheme,
sizeof(reduction_scheme));
int num_results = 0;
if (imma_ampere_case_) {
CUBLAS_EXECUTE_FUNC(cublasLtMatmulAlgoGetHeuristic, lt_handle,
operation_desc_, blocked_a_layout_, blocked_b_layout_,
blocked_c_layout_, blocked_c_layout_, preference_,
1 , &heuristic_results_,
&num_results);
} else {
CUBLAS_EXECUTE_FUNC(cublasLtMatmulAlgoGetHeuristic, lt_handle,
operation_desc_, a_layout_, b_layout_, c_layout_, c_layout_,
preference_, 1 ,
&heuristic_results_, &num_results);
}
if (num_results == 0) { return status_t::dnnl_runtime_error; }
gemm_algo_ = heuristic_results_.algo;
algo_scratch_size_ = heuristic_results_.workspaceSize;
const auto dst_nelems = dst_d.nelems(true);
reorder_scratch_size_ = dst_nelems * sizeof(float);
return status_t::dnnl_success;
}
void init_scratchpad(memory_tracking::registrar_t scratchpad) {
if (reorder_scratch_size_ > 0) {
scratchpad.book(memory_tracking::names::key_matmul_dst_in_acc_dt,
reorder_scratch_size_, 1, 256);
}
if (algo_scratch_size_ > 0) {
scratchpad.book(memory_tracking::names::key_matmul_lt_algo_scratch,
algo_scratch_size_, 1, 256);
}
if (weight_size_ > 0) {
scratchpad.book(memory_tracking::names::key_gemm_blocked_a,
weight_size_, 1, 256);
}
if (source_size_ > 0) {
scratchpad.book(memory_tracking::names::key_gemm_blocked_b,
source_size_, 1, 256);
}
if (dest_size_ > 0) {
scratchpad.book(memory_tracking::names::key_matmul_lt_block_c,
dest_size_, 1, 256);
}
}
bool is_md_col_major(const memory_desc_wrapper &md) {
if (md.is_blocking_desc()) {
const auto &md_strides = &md.blocking_desc().strides[isbatched_];
return (md_strides[1] == 1 && md.dims()[isbatched_ + 0] > 1);
}
return false;
}
void maybe_swap(uint64_t &row, uint64_t &col, cublasOperation_t &op,
cublasLtOrder_t order, bool transpose) {
if (transpose) {
std::swap(row, col);
op = cublasOperation_t::CUBLAS_OP_T;
order = CUBLASLT_ORDER_ROW;
}
}
status_t create_matrix_layout(cublasLtMatrixLayout_t &layout,
cublasLtOrder_t order, cublasOperation_t trans, uint64_t row,
uint64_t col, uint64_t ld, const cudaDataType_t data_type,
cublasLtMatmulDescAttributes_t trans_attr, uint64_t stride) {
CUBLAS_EXECUTE_FUNC(cublasLtMatmulDescSetAttribute, operation_desc_,
trans_attr, &trans, sizeof(trans));
CUBLAS_EXECUTE_FUNC(
cublasLtMatrixLayoutCreate, &layout, data_type, row, col, ld);
CUBLAS_EXECUTE_FUNC(cublasLtMatrixLayoutSetAttribute, layout,
CUBLASLT_MATRIX_LAYOUT_ORDER, &order, sizeof(order));
if (batch_count_ != 1) {
CUBLAS_EXECUTE_FUNC(cublasLtMatrixLayoutSetAttribute, layout,
CUBLASLT_MATRIX_LAYOUT_BATCH_COUNT, &batch_count_,
sizeof(batch_count_));
CUBLAS_EXECUTE_FUNC(cublasLtMatrixLayoutSetAttribute, layout,
CUBLASLT_MATRIX_LAYOUT_STRIDED_BATCH_OFFSET, &stride,
sizeof(stride));
}
return status_t::dnnl_success;
}
size_t bias_scratch_size() { return reorder_scratch_size_; }
bool has_runtime_params() { return has_runtime_params_; }
void create_non_blocked_layouts() {
auto trans_op = cublasOperation_t::CUBLAS_OP_N;
auto order = CUBLASLT_ORDER_COL;
auto row = M_;
auto col = K_;
maybe_swap(row, col, trans_op, order, trans_a_);
create_matrix_layout(a_layout_, CUBLASLT_ORDER_COL, trans_op, row, col,
row, weights_type_, CUBLASLT_MATMUL_DESC_TRANSA, stride_a_);
row = K_;
col = N_;
trans_op = cublasOperation_t::CUBLAS_OP_N;
maybe_swap(row, col, trans_op, order, trans_b_);
create_matrix_layout(b_layout_, CUBLASLT_ORDER_COL, trans_op, row, col,
row, src_type_, CUBLASLT_MATMUL_DESC_TRANSB, stride_b_);
row = M_;
col = N_;
order = CUBLASLT_ORDER_COL;
maybe_swap(row, col, trans_op, order, trans_c_);
create_matrix_layout(c_layout_, order, cublasOperation_t::CUBLAS_OP_N,
row, col, row, dst_type_, CUBLASLT_MATMUL_DESC_TRANSC,
stride_c_);
}
void create_blocked_layouts() {
create_matrix_layout(blocked_a_layout_, CUBLASLT_ORDER_COL32,
cublasOperation_t::CUBLAS_OP_N, M_, K_, a_blocked_ld_,
weights_type_, CUBLASLT_MATMUL_DESC_TRANSA, stride_a_blocked_);
create_matrix_layout(blocked_b_layout_, CUBLASLT_ORDER_COL32_2R_4R4,
cublasOperation_t::CUBLAS_OP_N, N_, K_, b_blocked_ld_,
src_type_, CUBLASLT_MATMUL_DESC_TRANSB, stride_b_blocked_);
create_matrix_layout(blocked_c_layout_, CUBLASLT_ORDER_COL32,
cublasOperation_t::CUBLAS_OP_N, M_, N_, c_blocked_ld_,
dst_type_, CUBLASLT_MATMUL_DESC_TRANSC, stride_c_blocked_);
uint64_t row, col;
if (!w_blocked_) {
row = M_;
col = K_;
if (trans_a_) { std::swap(row, col); }
create_matrix_layout(a_layout_, CUBLASLT_ORDER_COL,
cublasOperation_t::CUBLAS_OP_N, row, col, row,
weights_type_, CUBLASLT_MATMUL_DESC_TRANSA, stride_a_);
}
if (!src_blocked_) {
row = K_;
col = N_;
if (trans_b_) { std::swap(row, col); }
create_matrix_layout(b_layout_, CUBLASLT_ORDER_COL,
cublasOperation_t::CUBLAS_OP_N, row, col, row, src_type_,
CUBLASLT_MATMUL_DESC_TRANSB, stride_b_);
}
if (!dst_blocked_) {
row = M_;
col = N_;
if (trans_c_) { std::swap(row, col); }
create_matrix_layout(c_layout_, CUBLASLT_ORDER_COL,
cublasOperation_t::CUBLAS_OP_N, row, col, row, dst_type_,
CUBLASLT_MATMUL_DESC_TRANSC, stride_c_);
}
cublasOperation_t b_trans_t = cublasOperation_t::CUBLAS_OP_T;
CUBLAS_EXECUTE_FUNC(cublasLtMatmulDescSetAttribute, operation_desc_,
CUBLASLT_MATMUL_DESC_TRANSB, &b_trans_t, sizeof(b_trans_t));
}
void rt_cleanup() const {
if (a_layout_) {
CUBLAS_EXECUTE_FUNC(cublasLtMatrixLayoutDestroy, a_layout_);
}
if (b_layout_) {
CUBLAS_EXECUTE_FUNC(cublasLtMatrixLayoutDestroy, b_layout_);
}
if (c_layout_) {
CUBLAS_EXECUTE_FUNC(cublasLtMatrixLayoutDestroy, c_layout_);
}
if (operation_desc_) {
CUBLAS_EXECUTE_FUNC(cublasLtMatmulDescDestroy, operation_desc_);
}
if (imma_ampere_case_) {
if (trans_desc_) {
CUBLAS_EXECUTE_FUNC(
cublasLtMatrixTransformDescDestroy, trans_desc_);
}
if (blocked_a_layout_) {
CUBLAS_EXECUTE_FUNC(
cublasLtMatrixLayoutDestroy, blocked_a_layout_);
}
if (blocked_b_layout_) {
CUBLAS_EXECUTE_FUNC(
cublasLtMatrixLayoutDestroy, blocked_b_layout_);
}
if (blocked_c_layout_) {
CUBLAS_EXECUTE_FUNC(
cublasLtMatrixLayoutDestroy, blocked_c_layout_);
}
}
}
void cleanup() const {
std::free(alpha_);
std::free(beta_);
if (preference_) {
CUBLAS_EXECUTE_FUNC(cublasLtMatmulPreferenceDestroy, preference_);
}
rt_cleanup();
}
cublasLtMatmulDesc_t operation_desc_;
cublasLtMatrixLayout_t a_layout_;
cublasLtMatrixLayout_t b_layout_;
cublasLtMatrixLayout_t c_layout_;
cublasLtMatrixLayout_t blocked_a_layout_;
cublasLtMatrixLayout_t blocked_b_layout_;
cublasLtMatrixLayout_t blocked_c_layout_;
bool multi_dst_scale_ = false;
bool with_bias_ = false;
bool with_bias_epilogue_ = false;
bool with_relu_;
bool with_relu_epilogue_ = false;
bool imma_case_ = false;
bool imma_ampere_case_ = false;
bool imma_plain_case_ = false;
bool w_blocked_ = false;
bool src_blocked_ = false;
bool dst_blocked_ = false;
cublasLtMatrixTransformDesc_t trans_desc_;
uint64_t source_size_ = 0;
uint64_t weight_size_ = 0;
uint64_t dest_size_ = 0;
int64_t stride_a_, stride_b_, stride_c_, stride_a_blocked_,
stride_b_blocked_, stride_c_blocked_, a_blocked_ld_, b_blocked_ld_,
c_blocked_ld_;
bool trans_a_ = false, trans_b_ = false, trans_c_ = false;
cublasComputeType_t compute_type_ = CUBLAS_COMPUTE_32F;
size_t alpha_beta_size_bytes_ = 0;
void *alpha_ = nullptr;
void *beta_ = nullptr;
size_t algo_scratch_size_ = 0;
cublasLtMatmulAlgo_t gemm_algo_;
cublasLtMatmulPreference_t preference_;
cublasLtMatmulHeuristicResult_t heuristic_results_;
};
struct cudnn_matmul_lt_impl_t {
void set_non_runtime_params(
const std::shared_ptr<cublas_lt_params> &matmul_params) {
matmul_params_ = matmul_params;
}
void execute(cublasHandle_t cublas_handle,
const std::shared_ptr<cublas_lt_params> matmul_params, void *a,
void *b, void *c, void *bias, void *algo_scratch,
void *reorder_scratch, void *block_a_scratch, void *block_b_scratch,
void *block_c_scratch, void * ,
void * , void *dst_scale) {
cudaStream_t cuda_stream;
CUBLAS_EXECUTE_FUNC(cublasGetStream, cublas_handle, &cuda_stream);
std::shared_ptr<cublas_lt_params> params
= matmul_params->has_runtime_params_ ? matmul_params
: matmul_params_;
auto acc_type = params->acc_type_;
cudaStream_t streamId;
auto lt_handle = (cublasLtHandle_t)(cublas_handle);
CUBLAS_EXECUTE_FUNC(cublasGetStream, cublas_handle, &streamId);
auto b_layout = params->b_layout_;
auto blocked_b_layout = params->blocked_b_layout_;
auto a_layout = params->a_layout_;
auto blocked_a_layout = params->blocked_a_layout_;
auto imma_ampere_case = params->imma_ampere_case_;
if (imma_ampere_case) {
if (!params->src_blocked_) {
transform_matrix(lt_handle, params, b_layout, b,
blocked_b_layout, block_b_scratch, !params->trans_b_,
streamId);
b = block_b_scratch;
}
if (!params->w_blocked_) {
transform_matrix(lt_handle, params, a_layout, a,
blocked_a_layout, block_a_scratch, params->trans_a_,
streamId);
a = block_a_scratch;
}
}
cublasLtEpilogue_t epilogue = CUBLASLT_EPILOGUE_DEFAULT;
auto with_bias_epilogue = params->with_bias_epilogue_;
auto with_relu_epilogue = params->with_relu_epilogue_;
auto operation_desc = params->operation_desc_;
if (with_bias_epilogue) {
if (with_relu_epilogue) {
epilogue = CUBLASLT_EPILOGUE_RELU_BIAS;
} else {
epilogue = CUBLASLT_EPILOGUE_BIAS;
}
CUBLAS_EXECUTE_FUNC(cublasLtMatmulDescSetAttribute, operation_desc,
CUBLASLT_MATMUL_DESC_BIAS_POINTER, &bias, sizeof(bias));
} else if (with_relu_epilogue && !with_bias_epilogue) {
epilogue = CUBLASLT_EPILOGUE_RELU;
}
CUBLAS_EXECUTE_FUNC(cublasLtMatmulDescSetAttribute, operation_desc,
CUBLASLT_MATMUL_DESC_EPILOGUE, &epilogue, sizeof(epilogue));
float scale = 1.0f;
float host_dst_scale = 1.0f;
if (dst_scale && !params->multi_dst_scale_ && acc_type != CUDA_R_32I) {
CUDA_EXECUTE_FUNC(cuMemcpyAsync, (CUdeviceptr)&host_dst_scale,
(CUdeviceptr)dst_scale, sizeof(float), cuda_stream);
scale /= host_dst_scale;
}
auto alpha = params->alpha_;
auto beta = params->beta_;
auto post_op_sum = params->post_op_sum_;
if (acc_type == CUDA_R_16F) {
dnnl::impl::float16_t half_scale = scale;
dnnl::impl::float16_t half_gemm_beta = post_op_sum;
*static_cast<float16_t *>(alpha) = half_scale;
*static_cast<float16_t *>(beta) = half_gemm_beta;
} else {
*static_cast<float *>(alpha) = scale;
*static_cast<float *>(beta) = post_op_sum;
}
auto dst_blocked = params->dst_blocked_;
auto c_layout = params->c_layout_;
auto gemm_algo = params->gemm_algo_;
auto heuristic_results = params->heuristic_results_;
if (imma_ampere_case) {
if (!dst_blocked) {
std::memset(beta, 0, params->alpha_beta_size_bytes_);
}
auto blocked_c_layout = params->blocked_c_layout_;
c = params->reorder_required_ ? reorder_scratch : c;
void *tmp_c = dst_blocked ? c : block_c_scratch;
CUBLAS_EXECUTE_FUNC(cublasLtMatmul, lt_handle, operation_desc,
alpha, a, blocked_a_layout, b, blocked_b_layout, beta,
tmp_c, blocked_c_layout, tmp_c, blocked_c_layout,
&gemm_algo, algo_scratch, heuristic_results.workspaceSize,
streamId);
if (!dst_blocked) {
transform_matrix(lt_handle, params, blocked_c_layout,
block_c_scratch, c_layout, c, params->trans_c_,
streamId, post_op_sum);
}
} else {
CUBLAS_EXECUTE_FUNC(cublasLtMatmul, lt_handle, operation_desc,
alpha, a, a_layout, b, b_layout, beta, c, c_layout, c,
c_layout, &gemm_algo, algo_scratch,
heuristic_results.workspaceSize, streamId);
}
}
~cudnn_matmul_lt_impl_t() {
if (matmul_params_) { matmul_params_->cleanup(); }
}
private:
void transform_matrix(cublasLtHandle_t handle,
const std::shared_ptr<cublas_lt_params> ¶ms,
cublasLtMatrixLayout_t in_layout, void *in,
cublasLtMatrixLayout_t out_layout, void *out, bool transpose,
cudaStream_t stream, int beta = 0) {
int alpha = 1;
cublasLtMatrixTransformDesc_t trans_desc = params->trans_desc_;
cublasOperation_t transform_trans
= transpose ? CUBLAS_OP_T : CUBLAS_OP_N;
CUBLAS_EXECUTE_FUNC(cublasLtMatrixTransformDescSetAttribute, trans_desc,
CUBLASLT_MATRIX_TRANSFORM_DESC_TRANSA, &transform_trans,
sizeof(transform_trans));
CUBLAS_EXECUTE_FUNC(cublasLtMatrixTransform, handle, trans_desc, &alpha,
in, in_layout, &beta, out, out_layout, out, out_layout, stream);
}
std::shared_ptr<cublas_lt_params> matmul_params_;
};
} } } }
#endif