parent
f3c9789c7f
commit
3ba7a738f3
@ -0,0 +1,87 @@
|
||||
#include <cublas_v2.h>
|
||||
#include "paddle/platform/dynamic_loader.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace dyload {
|
||||
namespace dynload {
|
||||
|
||||
std::once_flag cublas_dso_flag;
|
||||
void *cublas_dso_handle = nullptr;
|
||||
|
||||
/**
|
||||
* The following macro definition can generate structs
|
||||
* (for each function) to dynamic load cublas routine
|
||||
* via operator overloading.
|
||||
*
|
||||
* note: default dynamic linked libs
|
||||
*/
|
||||
#ifdef PADDLE_USE_DSO
|
||||
#define DYNAMIC_LOAD_CUBLAS_WRAP(__name) \
|
||||
struct DynLoad__##__name { \
|
||||
template <typename... Args> \
|
||||
cublasStatus_t operator()(Args... args) { \
|
||||
typedef cublasStatus_t (*cublasFunc)(Args...); \
|
||||
std::call_once(cublas_dso_flag, GetCublasDsoHandle, &cublas_dso_handle); \
|
||||
void *p_##__name = dlsym(cublas_dso_handle, #__name); \
|
||||
return reinterpret_cast<cublasFunc>(p_##__name)(args...); \
|
||||
} \
|
||||
} __name; // struct DynLoad__##__name
|
||||
#else
|
||||
#define DYNAMIC_LOAD_CUBLAS_WRAP(__name) \
|
||||
struct DynLoad__##__name { \
|
||||
template <typename... Args> \
|
||||
cublasStatus_t operator()(Args... args) { \
|
||||
return __name(args...); \
|
||||
} \
|
||||
} __name; // struct DynLoad__##__name
|
||||
#endif
|
||||
|
||||
#define DYNAMIC_LOAD_CUBLAS_V2_WRAP(__name) DYNAMIC_LOAD_CUBLAS_WRAP(__name)
|
||||
|
||||
// include all needed cublas functions in HPPL
|
||||
// clang-format off
|
||||
#define CUBLAS_BLAS_ROUTINE_EACH(__macro) \
|
||||
__macro(cublasSgemv) \
|
||||
__macro(cublasDgemv) \
|
||||
__macro(cublasSgemm) \
|
||||
__macro(cublasDgemm) \
|
||||
__macro(cublasSgeam) \
|
||||
__macro(cublasDgeam) \
|
||||
|
||||
DYNAMIC_LOAD_CUBLAS_V2_WRAP(cublasCreate)
|
||||
DYNAMIC_LOAD_CUBLAS_V2_WRAP(cublasDestroy)
|
||||
DYNAMIC_LOAD_CUBLAS_V2_WRAP(cublasSetStream)
|
||||
DYNAMIC_LOAD_CUBLAS_V2_WRAP(cublasSetPointerMode)
|
||||
DYNAMIC_LOAD_CUBLAS_V2_WRAP(cublasGetPointerMode)
|
||||
DYNAMIC_LOAD_CUBLAS_WRAP(cublasSgemmBatched)
|
||||
DYNAMIC_LOAD_CUBLAS_WRAP(cublasDgemmBatched)
|
||||
DYNAMIC_LOAD_CUBLAS_WRAP(cublasCgemmBatched)
|
||||
DYNAMIC_LOAD_CUBLAS_WRAP(cublasZgemmBatched)
|
||||
DYNAMIC_LOAD_CUBLAS_WRAP(cublasSgetrfBatched)
|
||||
DYNAMIC_LOAD_CUBLAS_WRAP(cublasSgetriBatched)
|
||||
DYNAMIC_LOAD_CUBLAS_WRAP(cublasDgetrfBatched)
|
||||
DYNAMIC_LOAD_CUBLAS_WRAP(cublasDgetriBatched)
|
||||
CUBLAS_BLAS_ROUTINE_EACH(DYNAMIC_LOAD_CUBLAS_V2_WRAP)
|
||||
|
||||
#undef DYNAMIC_LOAD_CUBLAS_WRAP
|
||||
#undef DYNAMIC_LOAD_CUBLAS_V2_WRAP
|
||||
#undef CUBLAS_BLAS_ROUTINE_EACH
|
||||
|
||||
} /* namespace dynload */
|
||||
|
||||
// clang-format on
|
||||
#ifndef PADDLE_TYPE_DOUBLE
|
||||
#define CUBLAS_GEAM dynload::cublasSgeam
|
||||
#define CUBLAS_GEMV dynload::cublasSgemv
|
||||
#define CUBLAS_GEMM dynload::cublasSgemm
|
||||
#define CUBLAS_GETRF dynload::cublasSgetrfBatched
|
||||
#define CUBLAS_GETRI dynload::cublasSgetriBatched
|
||||
#else
|
||||
#define CUBLAS_GEAM dynload::cublasDgeam
|
||||
#define CUBLAS_GEMV dynload::cublasDgemv
|
||||
#define CUBLAS_GEMM dynload::cublasDgemm
|
||||
#define CUBLAS_GETRF dynload::cublasDgetrfBatched
|
||||
#define CUBLAS_GETRI dynload::cublasDgetriBatched
|
||||
#endif
|
||||
} // namespace dyload
|
||||
} // namespace paddle
|
@ -0,0 +1,114 @@
|
||||
#include <cudnn.h>
|
||||
#include "paddle/platform/dynamic_loader.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace dyload {
|
||||
|
||||
std::once_flag cudnn_dso_flag;
|
||||
void* cudnn_dso_handle = nullptr;
|
||||
|
||||
#ifdef PADDLE_USE_DSO
|
||||
|
||||
#define DYNAMIC_LOAD_CUDNN_WRAP(__name) \
|
||||
struct DynLoad__##__name { \
|
||||
template <typename... Args> \
|
||||
auto operator()(Args... args) -> decltype(__name(args...)) { \
|
||||
using cudnn_func = decltype(__name(args...)) (*)(Args...); \
|
||||
std::call_once(cudnn_dso_flag, GetCudnnDsoHandle, &cudnn_dso_handle); \
|
||||
void* p_##__name = dlsym(cudnn_dso_handle, #__name); \
|
||||
return reinterpret_cast<cudnn_func>(p_##__name)(args...); \
|
||||
} \
|
||||
} __name; /* struct DynLoad__##__name */
|
||||
|
||||
#else
|
||||
|
||||
#define DYNAMIC_LOAD_CUDNN_WRAP(__name) \
|
||||
struct DynLoad__##__name { \
|
||||
template <typename... Args> \
|
||||
auto operator()(Args... args) -> decltype(__name(args...)) { \
|
||||
return __name(args...); \
|
||||
} \
|
||||
} __name; /* struct DynLoad__##__name */
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* include all needed cudnn functions in HPPL
|
||||
* different cudnn version has different interfaces
|
||||
**/
|
||||
// clang-format off
|
||||
#define CUDNN_DNN_ROUTINE_EACH(__macro) \
|
||||
__macro(cudnnSetTensor4dDescriptor) \
|
||||
__macro(cudnnSetTensor4dDescriptorEx) \
|
||||
__macro(cudnnGetConvolutionNdForwardOutputDim) \
|
||||
__macro(cudnnGetConvolutionForwardAlgorithm) \
|
||||
__macro(cudnnCreateTensorDescriptor) \
|
||||
__macro(cudnnDestroyTensorDescriptor) \
|
||||
__macro(cudnnCreateFilterDescriptor) \
|
||||
__macro(cudnnSetFilter4dDescriptor) \
|
||||
__macro(cudnnSetPooling2dDescriptor) \
|
||||
__macro(cudnnDestroyFilterDescriptor) \
|
||||
__macro(cudnnCreateConvolutionDescriptor) \
|
||||
__macro(cudnnCreatePoolingDescriptor) \
|
||||
__macro(cudnnDestroyPoolingDescriptor) \
|
||||
__macro(cudnnSetConvolution2dDescriptor) \
|
||||
__macro(cudnnDestroyConvolutionDescriptor) \
|
||||
__macro(cudnnCreate) \
|
||||
__macro(cudnnDestroy) \
|
||||
__macro(cudnnSetStream) \
|
||||
__macro(cudnnActivationForward) \
|
||||
__macro(cudnnConvolutionForward) \
|
||||
__macro(cudnnConvolutionBackwardBias) \
|
||||
__macro(cudnnGetConvolutionForwardWorkspaceSize) \
|
||||
__macro(cudnnTransformTensor) \
|
||||
__macro(cudnnPoolingForward) \
|
||||
__macro(cudnnPoolingBackward) \
|
||||
__macro(cudnnSoftmaxBackward) \
|
||||
__macro(cudnnSoftmaxForward) \
|
||||
__macro(cudnnGetVersion) \
|
||||
__macro(cudnnGetErrorString)
|
||||
CUDNN_DNN_ROUTINE_EACH(DYNAMIC_LOAD_CUDNN_WRAP)
|
||||
|
||||
#define CUDNN_DNN_ROUTINE_EACH_R2(__macro) \
|
||||
__macro(cudnnAddTensor) \
|
||||
__macro(cudnnConvolutionBackwardData) \
|
||||
__macro(cudnnConvolutionBackwardFilter)
|
||||
CUDNN_DNN_ROUTINE_EACH_R2(DYNAMIC_LOAD_CUDNN_WRAP)
|
||||
|
||||
// APIs available after R3:
|
||||
#if CUDNN_VERSION >= 3000
|
||||
#define CUDNN_DNN_ROUTINE_EACH_AFTER_R3(__macro) \
|
||||
__macro(cudnnGetConvolutionBackwardFilterWorkspaceSize) \
|
||||
__macro(cudnnGetConvolutionBackwardDataAlgorithm) \
|
||||
__macro(cudnnGetConvolutionBackwardFilterAlgorithm) \
|
||||
__macro(cudnnGetConvolutionBackwardDataWorkspaceSize)
|
||||
CUDNN_DNN_ROUTINE_EACH_AFTER_R3(DYNAMIC_LOAD_CUDNN_WRAP)
|
||||
#undef CUDNN_DNN_ROUTINE_EACH_AFTER_R3
|
||||
#endif
|
||||
|
||||
|
||||
// APIs available after R4:
|
||||
#if CUDNN_VERSION >= 4007
|
||||
#define CUDNN_DNN_ROUTINE_EACH_AFTER_R4(__macro) \
|
||||
__macro(cudnnBatchNormalizationForwardTraining) \
|
||||
__macro(cudnnBatchNormalizationForwardInference) \
|
||||
__macro(cudnnBatchNormalizationBackward)
|
||||
CUDNN_DNN_ROUTINE_EACH_AFTER_R4(DYNAMIC_LOAD_CUDNN_WRAP)
|
||||
#undef CUDNN_DNN_ROUTINE_EACH_AFTER_R4
|
||||
#endif
|
||||
|
||||
// APIs in R5
|
||||
#if CUDNN_VERSION >= 5000
|
||||
#define CUDNN_DNN_ROUTINE_EACH_R5(__macro) \
|
||||
__macro(cudnnCreateActivationDescriptor) \
|
||||
__macro(cudnnSetActivationDescriptor) \
|
||||
__macro(cudnnGetActivationDescriptor) \
|
||||
__macro(cudnnDestroyActivationDescriptor)
|
||||
CUDNN_DNN_ROUTINE_EACH_R5(DYNAMIC_LOAD_CUDNN_WRAP)
|
||||
#undef CUDNN_DNN_ROUTINE_EACH_R5
|
||||
#endif
|
||||
|
||||
#undef CUDNN_DNN_ROUTINE_EACH
|
||||
// clang-format on
|
||||
} // namespace dyload
|
||||
} // namespace paddle
|
@ -0,0 +1,42 @@
|
||||
#include <curand.h>
|
||||
#include "paddle/platform/dynamic_loader.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace dyload {
|
||||
#ifdef PADDLE_USE_DSO
|
||||
#define DYNAMIC_LOAD_CURAND_WRAP(__name) \
|
||||
struct DynLoad__##__name { \
|
||||
template <typename... Args> \
|
||||
curandStatus_t operator()(Args... args) { \
|
||||
typedef curandStatus_t (*curandFunc)(Args...); \
|
||||
std::call_once(curand_dso_flag, GetCurandDsoHandle, &curand_dso_handle); \
|
||||
void *p_##__name = dlsym(curand_dso_handle, #__name); \
|
||||
return reinterpret_cast<curandFunc>(p_##__name)(args...); \
|
||||
} \
|
||||
} __name; /* struct DynLoad__##__name */
|
||||
#else
|
||||
#define DYNAMIC_LOAD_CURAND_WRAP(__name) \
|
||||
struct DynLoad__##__name { \
|
||||
template <typename... Args> \
|
||||
curandStatus_t operator()(Args... args) { \
|
||||
return __name(args...); \
|
||||
} \
|
||||
} __name; /* struct DynLoad__##__name */
|
||||
#endif
|
||||
|
||||
/* include all needed curand functions in HPPL */
|
||||
// clang-format off
|
||||
#define CURAND_RAND_ROUTINE_EACH(__macro) \
|
||||
__macro(curandCreateGenerator) \
|
||||
__macro(curandSetStream) \
|
||||
__macro(curandSetPseudoRandomGeneratorSeed)\
|
||||
__macro(curandGenerateUniform) \
|
||||
__macro(curandGenerateUniformDouble)
|
||||
// clang-format on
|
||||
|
||||
CURAND_RAND_ROUTINE_EACH(DYNAMIC_LOAD_CURAND_WRAP)
|
||||
|
||||
#undef CURAND_RAND_ROUTINE_EACH
|
||||
#undef DYNAMIC_LOAD_CURAND_WRAP
|
||||
}
|
||||
} // namespace paddle
|
@ -0,0 +1,157 @@
|
||||
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
|
||||
|
||||
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. */
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include "DynamicLoader.h"
|
||||
#include "Logging.h"
|
||||
|
||||
DEFINE_string(cudnn_dir, "",
|
||||
"Specify path for loading libcudnn.so. For instance, "
|
||||
"/usr/local/cudnn/lib. If empty [default], dlopen "
|
||||
"will search cudnn from LD_LIBRARY_PATH");
|
||||
|
||||
DEFINE_string(cuda_dir, "",
|
||||
"Specify path for loading cuda library, such as libcublas, "
|
||||
"libcurand. For instance, /usr/local/cuda/lib64. If default, "
|
||||
"dlopen will search cuda from LD_LIBRARY_PATH");
|
||||
|
||||
DEFINE_string(warpctc_dir, "", "Specify path for loading libwarpctc.so.");
|
||||
|
||||
DEFINE_string(lapack_dir, "", "Specify path for loading liblapack.so.");
|
||||
|
||||
static inline std::string join(const std::string& part1,
|
||||
const std::string& part2) {
|
||||
// directory separator
|
||||
const char sep = '/';
|
||||
if (!part2.empty() && part2.front() == sep) {
|
||||
return part2;
|
||||
}
|
||||
std::string ret;
|
||||
ret.reserve(part1.size() + part2.size() + 1);
|
||||
ret = part1;
|
||||
if (!ret.empty() && ret.back() != sep) {
|
||||
ret += sep;
|
||||
}
|
||||
ret += part2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void GetDsoHandleFromDefaultPath(std::string& dso_path,
|
||||
void** dso_handle,
|
||||
int dynload_flags) {
|
||||
VLOG(3) << "Try to find library: " << dso_path
|
||||
<< " from default system path.";
|
||||
// default search from LD_LIBRARY_PATH/DYLD_LIBRARY_PATH
|
||||
*dso_handle = dlopen(dso_path.c_str(), dynload_flags);
|
||||
|
||||
// DYLD_LIBRARY_PATH is disabled after Mac OS 10.11 to
|
||||
// bring System Integrity Projection (SIP), if dso_handle
|
||||
// is null, search from default package path in Mac OS.
|
||||
#if defined(__APPLE__) || defined(__OSX__)
|
||||
if (nullptr == *dso_handle) {
|
||||
dso_path = join("/usr/local/cuda/lib/", dso_path);
|
||||
*dso_handle = dlopen(dso_path.c_str(), dynload_flags);
|
||||
if (nullptr == *dso_handle) {
|
||||
if (dso_path == "libcudnn.dylib") {
|
||||
LOG(FATAL)
|
||||
<< "Note: [Recommend] copy cudnn into /usr/local/cuda/ \n" // NOLINT
|
||||
<< "For instance, sudo tar -xzf "
|
||||
"cudnn-7.5-osx-x64-v5.0-ga.tgz -C " // NOLINT
|
||||
<< "/usr/local \n sudo chmod a+r "
|
||||
"/usr/local/cuda/include/cudnn.h " // NOLINT
|
||||
<< "/usr/local/cuda/lib/libcudnn*";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void GetDsoHandleFromSearchPath(const std::string& search_root,
|
||||
const std::string& dso_name,
|
||||
void** dso_handle) {
|
||||
int dynload_flags = RTLD_LAZY | RTLD_LOCAL;
|
||||
*dso_handle = nullptr;
|
||||
|
||||
std::string dlPath = dso_name;
|
||||
if (search_root.empty()) {
|
||||
GetDsoHandleFromDefaultPath(dlPath, dso_handle, dynload_flags);
|
||||
} else {
|
||||
// search xxx.so from custom path
|
||||
dlPath = join(search_root, dso_name);
|
||||
*dso_handle = dlopen(dlPath.c_str(), dynload_flags);
|
||||
// if not found, search from default path
|
||||
if (nullptr == *dso_handle) {
|
||||
LOG(WARNING) << "Failed to find dynamic library: " << dlPath << " ("
|
||||
<< dlerror() << ")";
|
||||
dlPath = dso_name;
|
||||
GetDsoHandleFromDefaultPath(dlPath, dso_handle, dynload_flags);
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(nullptr != *dso_handle) << "Failed to find dynamic library: " << dlPath
|
||||
<< " (" << dlerror() << ") \n"
|
||||
<< "Please specify its path correctly using "
|
||||
"following ways: \n"
|
||||
|
||||
<< "Method. set environment variable "
|
||||
"LD_LIBRARY_PATH on Linux or "
|
||||
<< "DYLD_LIBRARY_PATH on Mac OS. \n"
|
||||
<< "For instance, issue command: export "
|
||||
"LD_LIBRARY_PATH=... \n"
|
||||
|
||||
<< "Note: After Mac OS 10.11, using the "
|
||||
"DYLD_LIBRARY_PATH is impossible "
|
||||
<< "unless System Integrity Protection (SIP) "
|
||||
"is disabled.";
|
||||
}
|
||||
|
||||
void GetCublasDsoHandle(void** dso_handle) {
|
||||
#if defined(__APPLE__) || defined(__OSX__)
|
||||
GetDsoHandleFromSearchPath(FLAGS_cuda_dir, "libcublas.dylib", dso_handle);
|
||||
#else
|
||||
GetDsoHandleFromSearchPath(FLAGS_cuda_dir, "libcublas.so", dso_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetCudnnDsoHandle(void** dso_handle) {
|
||||
#if defined(__APPLE__) || defined(__OSX__)
|
||||
GetDsoHandleFromSearchPath(FLAGS_cudnn_dir, "libcudnn.dylib", dso_handle);
|
||||
#else
|
||||
GetDsoHandleFromSearchPath(FLAGS_cudnn_dir, "libcudnn.so", dso_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetCurandDsoHandle(void** dso_handle) {
|
||||
#if defined(__APPLE__) || defined(__OSX__)
|
||||
GetDsoHandleFromSearchPath(FLAGS_cuda_dir, "libcurand.dylib", dso_handle);
|
||||
#else
|
||||
GetDsoHandleFromSearchPath(FLAGS_cuda_dir, "libcurand.so", dso_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetWarpCTCDsoHandle(void** dso_handle) {
|
||||
#if defined(__APPLE__) || defined(__OSX__)
|
||||
GetDsoHandleFromSearchPath(FLAGS_warpctc_dir, "libwarpctc.dylib", dso_handle);
|
||||
#else
|
||||
GetDsoHandleFromSearchPath(FLAGS_warpctc_dir, "libwarpctc.so", dso_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetLapackDsoHandle(void** dso_handle) {
|
||||
#if defined(__APPLE__) || defined(__OSX__)
|
||||
GetDsoHandleFromSearchPath(FLAGS_lapack_dir, "liblapacke.dylib", dso_handle);
|
||||
#else
|
||||
GetDsoHandleFromSearchPath(FLAGS_lapack_dir, "liblapacke.so", dso_handle);
|
||||
#endif
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.
|
||||
|
||||
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. */
|
||||
|
||||
#ifndef DYNAMIC_LOAD_H_
|
||||
#define DYNAMIC_LOAD_H_
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief load the DSO of CUBLAS
|
||||
*
|
||||
* @param **dso_handle dso handler
|
||||
*
|
||||
*/
|
||||
void GetCublasDsoHandle(void** dso_handle);
|
||||
|
||||
/**
|
||||
* @brief load the DSO of CUDNN
|
||||
*
|
||||
* @param **dso_handle dso handler
|
||||
*
|
||||
*/
|
||||
void GetCudnnDsoHandle(void** dso_handle);
|
||||
|
||||
/**
|
||||
* @brief load the DSO of CURAND
|
||||
*
|
||||
* @param **dso_handle dso handler
|
||||
*
|
||||
*/
|
||||
void GetCurandDsoHandle(void** dso_handle);
|
||||
|
||||
/**
|
||||
* @brief load the DSO of warp-ctc
|
||||
*
|
||||
* @param **dso_handle dso handler
|
||||
*
|
||||
*/
|
||||
void GetWarpCTCDsoHandle(void** dso_handle);
|
||||
|
||||
/**
|
||||
* @brief load the DSO of lapack
|
||||
*
|
||||
* @param **dso_handle dso handler
|
||||
*
|
||||
*/
|
||||
void GetLapackDsoHandle(void** dso_handle);
|
||||
|
||||
#endif // DYNAMIC_LOAD_H_
|
Loading…
Reference in new issue