Files
2026-07-13 12:40:42 +08:00

339 lines
11 KiB
C++

/* Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#pragma once
#include <sstream>
#include <string>
#include <unordered_map>
#include "paddle/phi/backends/dynload/cublasLt.h"
#include "paddle/phi/core/dense_tensor.h"
namespace phi {
struct CublasLtAlgoParam {
int algoId;
int swizzle;
int customOption;
int tile;
int splitK_val;
int reductionScheme;
int stages;
size_t workspace_size;
};
const std::map<std::tuple<int, int, int>, CublasLtAlgoParam> AlgoParamCache{};
class CublasLtHelper {
public:
CublasLtHelper(int m, int k, int n, cublasLtHandle_t handle)
: handle_(handle), alpha_(1), beta_(0), m_(m), k_(k), n_(n) {
cublasStatus_t status;
#if CUBLAS_VER_MAJOR < 11
cudaDataType_t cudaComputeType = CUDA_R_32I;
#else
cublasComputeType_t cudaComputeType = CUBLAS_COMPUTE_32I;
#endif
// matmul desc
#if CUBLAS_VER_MAJOR < 11
status = dynload::cublasLtMatmulDescCreate(&matmul_desc_, cudaComputeType);
#else
status = dynload::cublasLtMatmulDescCreate(
&matmul_desc_, cudaComputeType, CUDA_R_32I);
#endif
PADDLE_ENFORCE_EQ(
status,
CUBLAS_STATUS_SUCCESS,
common::errors::External(
"cublasLtMatmulDescCreate execution error, "
"refer https://docs.nvidia.com/cuda/cublas/index.html to get more "
"information"));
cublasOperation_t op_transpose = CUBLAS_OP_T;
status =
dynload::cublasLtMatmulDescSetAttribute(matmul_desc_,
CUBLASLT_MATMUL_DESC_TRANSA,
&op_transpose,
sizeof(op_transpose));
PADDLE_ENFORCE_EQ(
status,
CUBLAS_STATUS_SUCCESS,
common::errors::External(
"cublasLtMatmulDescSetAttribute execution error, "
"refer https://docs.nvidia.com/cuda/cublas/index.html to get more "
"information"));
// matrix desc
status = dynload::cublasLtMatrixLayoutCreate(&B_desc_, CUDA_R_8I, k, n, k);
PADDLE_ENFORCE_EQ(
status,
CUBLAS_STATUS_SUCCESS,
common::errors::External(
"cublasLtMatrixLayoutCreate execution error, "
"refer https://docs.nvidia.com/cuda/cublas/index.html to get more "
"information"));
status = dynload::cublasLtMatrixLayoutCreate(&A_desc_, CUDA_R_8I, k, m, k);
PADDLE_ENFORCE_EQ(
status,
CUBLAS_STATUS_SUCCESS,
common::errors::External(
"cublasLtMatrixLayoutCreate execution error, "
"refer https://docs.nvidia.com/cuda/cublas/index.html to get more "
"information"));
status = dynload::cublasLtMatrixLayoutCreate(&C_desc_, CUDA_R_32I, n, m, n);
PADDLE_ENFORCE_EQ(
status,
CUBLAS_STATUS_SUCCESS,
common::errors::External(
"cublasLtMatrixLayoutCreate execution error, "
"refer https://docs.nvidia.com/cuda/cublas/index.html to get more "
"information"));
#if defined(PADDLE_WITH_CUDA)
int algoId = 21;
int swizzle = 0;
int customOption = 0;
int tile = 15;
int splitK_val = 0;
int reductionScheme = 0;
int stages = 23;
workspace_size_ = 0;
if (m >= 128) {
tile = 20;
stages = 17;
}
std::tuple<int, int, int> key(m_, k_, n_);
if (AlgoParamCache.count(key) != 0) {
auto value = AlgoParamCache.at(key);
algoId = value.algoId;
swizzle = value.swizzle;
customOption = value.customOption;
tile = value.tile;
splitK_val = value.splitK_val;
reductionScheme = value.reductionScheme;
stages = value.stages;
workspace_size_ = value.workspace_size;
}
dynload::cublasLtMatmulAlgoInit(handle_,
cudaComputeType,
CUDA_R_32I,
CUDA_R_8I,
CUDA_R_8I,
CUDA_R_32I,
CUDA_R_32I,
algoId,
&algo_);
dynload::cublasLtMatmulAlgoConfigSetAttribute(
&algo_,
CUBLASLT_ALGO_CONFIG_CUSTOM_OPTION,
&(customOption),
sizeof(customOption));
dynload::cublasLtMatmulAlgoConfigSetAttribute(
&algo_, CUBLASLT_ALGO_CONFIG_TILE_ID, &(tile), sizeof(tile));
dynload::cublasLtMatmulAlgoConfigSetAttribute(
&algo_,
CUBLASLT_ALGO_CONFIG_SPLITK_NUM,
&(splitK_val),
sizeof(splitK_val));
dynload::cublasLtMatmulAlgoConfigSetAttribute(
&algo_,
CUBLASLT_ALGO_CONFIG_CTA_SWIZZLING,
&(swizzle),
sizeof(swizzle));
dynload::cublasLtMatmulAlgoConfigSetAttribute(
&algo_,
CUBLASLT_ALGO_CONFIG_REDUCTION_SCHEME,
&(reductionScheme),
sizeof(int));
#if CUDA_VERSION >= 11000
dynload::cublasLtMatmulAlgoConfigSetAttribute(
&algo_, CUBLASLT_ALGO_CONFIG_STAGES_ID, &(stages), sizeof(stages));
#endif
#endif
}
~CublasLtHelper() {}
void GEMM(const int8_t* A_dev,
const int8_t* B_dev,
int32_t* C_dev,
cudaStream_t stream,
void* workspace = nullptr) {
cublasStatus_t status;
status = dynload::cublasLtMatmul(handle_,
matmul_desc_,
&alpha_,
B_dev,
B_desc_,
A_dev,
A_desc_,
&beta_,
C_dev,
C_desc_,
C_dev,
C_desc_,
#if defined(PADDLE_WITH_CUDA)
&algo_,
workspace,
workspace_size_,
#else
nullptr,
nullptr,
0,
#endif
stream);
PADDLE_ENFORCE_EQ(
status,
CUBLAS_STATUS_SUCCESS,
common::errors::External(
"cublasLtMatmul execution error, "
"refer https://docs.nvidia.com/cuda/cublas/index.html to get more "
"information"));
}
private:
cublasLtHandle_t handle_;
cublasLtMatmulDesc_t matmul_desc_;
cublasLtMatrixLayout_t A_desc_;
cublasLtMatrixLayout_t B_desc_;
cublasLtMatrixLayout_t C_desc_;
cublasLtMatmulAlgo_t algo_;
int32_t alpha_ = 1;
int32_t beta_ = 0;
int m_ = 0;
int k_ = 0;
int n_ = 0;
size_t workspace_size_ = 0;
};
template <typename T>
inline cudaDataType_t GetCublasLtDataType() {
return CUDA_R_32F;
}
template <>
inline cudaDataType_t GetCublasLtDataType<phi::float16>() {
return CUDA_R_16F;
}
template <>
inline cudaDataType_t GetCublasLtDataType<phi::bfloat16>() {
return CUDA_R_16BF;
}
#if CUDA_VERSION >= 12010
template <typename T>
void CublasLtMatmulFP8(const GPUContext& dev_ctx,
const DenseTensor& mat_a,
const DenseTensor& mat_b,
DenseTensor* workspace,
DenseTensor* out) {
// TODO(large-tensor): downstream functors may still use int
int64_t m = mat_a.dims()[0];
// TODO(large-tensor): downstream functors may still use int
int64_t k = mat_a.dims()[1];
// TODO(large-tensor): downstream functors may still use int
int64_t n = mat_b.dims()[1];
// init data structure
cublasStatus_t status;
auto A_type = CUDA_R_8F_E4M3;
auto B_type = CUDA_R_8F_E4M3;
auto C_type = GetCublasLtDataType<T>();
cublasLtMatmulDesc_t matmul_desc_;
cublasLtMatrixLayout_t A_desc_;
cublasLtMatrixLayout_t B_desc_;
cublasLtMatrixLayout_t C_desc_;
float alpha_ = 1.0f;
float beta_ = 0.0f;
cublasComputeType_t cudaComputeType = CUBLAS_COMPUTE_32F;
status = dynload::cublasLtMatmulDescCreate(
&matmul_desc_, cudaComputeType, CUDA_R_32F);
cublasOperation_t op_transpose = CUBLAS_OP_T;
status = dynload::cublasLtMatmulDescSetAttribute(matmul_desc_,
CUBLASLT_MATMUL_DESC_TRANSA,
&op_transpose,
sizeof(op_transpose));
status = dynload::cublasLtMatrixLayoutCreate(&B_desc_, B_type, k, n, k);
status = dynload::cublasLtMatrixLayoutCreate(&A_desc_, A_type, k, m, k);
status = dynload::cublasLtMatrixLayoutCreate(&C_desc_, C_type, n, m, n);
// Need to use heuristic
int returnedResults = 0;
cublasLtMatmulHeuristicResult_t heuristicResult = {};
cublasLtMatmulPreference_t preference = NULL;
size_t workspace_size = workspace->numel();
status = dynload::cublasLtMatmulPreferenceCreate(&preference);
status = dynload::cublasLtMatmulPreferenceSetAttribute(
preference,
CUBLASLT_MATMUL_PREF_MAX_WORKSPACE_BYTES,
&workspace_size,
sizeof(workspace_size));
status = dynload::cublasLtMatmulAlgoGetHeuristic(dev_ctx.cublaslt_handle(),
matmul_desc_,
B_desc_,
A_desc_,
C_desc_,
C_desc_,
preference,
1,
&heuristicResult,
&returnedResults);
PADDLE_ENFORCE_NE(returnedResults,
0,
common::errors::NotFound(
"Unable to find suitable cuBLAS GEMM algorithm"));
status = dynload::cublasLtMatmul(
dev_ctx.cublaslt_handle(),
matmul_desc_,
&alpha_,
mat_b.data<phi::float8_e4m3fn>(),
B_desc_,
mat_a.data<phi::float8_e4m3fn>(),
A_desc_,
&beta_,
out->data<T>(),
C_desc_,
out->data<T>(),
C_desc_,
// nullptr,
&heuristicResult.algo,
// nullptr,
reinterpret_cast<void*>(workspace->data<int8_t>()),
// 0,
workspace_size,
dev_ctx.stream());
}
#endif
} // namespace phi