-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: unify PADDLE_ENFORCE for cublas, cudnn, curand #2883
Conversation
@@ -74,8 +75,7 @@ class CUDADeviceContext : public DeviceContext { | |||
public: | |||
explicit CUDADeviceContext(const GPUPlace gpu_place) : gpu_place_(gpu_place) { | |||
GPUPlaceGuard guard(gpu_place_); | |||
paddle::platform::throw_on_error(cudaStreamCreate(&stream_), | |||
"cudaStreamCreate failed"); | |||
PADDLE_ENFORCE(cudaStreamCreate(&stream_), "cudaStreamCreate failed"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PADDLE_ENFORCE
means the condition must be true
. But CUXXXX_STATUS_SUCCESS
is zero, and false. So it seems that these lines should be
PADDLE_ENFORCE(cudaStreamCreate(&stream_) == CUDA_SUCCESS);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion, PADDLE_ENFORCE(condition, ...)
means condition
must execute correctly. No matter the return of condition is 0 or 1, the internal of PADDLE_ENFORCE
can figure out how to deal with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with @reyoung. I check on how glog does. What CHECK
does is to check the condition is true.
And we can implement CUDNN_ENFORCE/CUBLAS_ENFORCE
based on PADDLE_ENFORCE
for writing related codes more conveniently
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that
PADDLE_ENFORCE(cudaStreamCreate(&stream_))
is shorter than
PADDLE_ENFORCE(cudaStreamCreate(&stream_) == CUDA_SUCCESS);
and it is compatible with the use of the word "enforce" in English, I support that we adopt @gangliao 's proposal -- to make PADDLE_ENFORCE
handle the condition.
I agree the English word CHECK should be followed by a boolean value and expects to be true. My point is that ENFORCE should be followed by an action, which is hopefully successful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, @wangkuiyi
PADDLE_ENFORCE(cudaStreamCreate(&stream_) == CUDA_SUCCESS);
will also impede us to print apposite error info for cuda, cudnn, cublas, curand.
paddle/platform/enforce.h
Outdated
|
||
template <typename... Args> | ||
inline void throw_on_error(cudaError_t e, const Args&... args) { | ||
if (e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that this snippet
if (e) {
std::stringstream ss;
ss << ::paddle::string::Sprintf(args...);
ss << ::paddle::string::Sprintf(" at [%s:%s];", __FILE__, __LINE__);
throw thrust::system_error(e, thrust::cuda_category(), ss.str());
}
can be rewritten as
if (e) {
throw thrust::system_error(e, thrust::cuda_category(),
string::Sprintf(args...) + string::Sprintf(" at "...));
}
I assume that we can write string::Sprintf
other than ::paddle::string::Sprintf
.
paddle/platform/enforce.h
Outdated
std::string all_msg_; | ||
}; | ||
|
||
// From https://stackoverflow.com/questions/30130930/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about rephrase this comment:
// Because most enforce conditions would evaluate to true, we can use
// __builtin_expect to instruct the C++ compiler to generate code that always forces
// branch prediction of true. This generates faster binary code. For more details,
// please check https://stackoverflow.com/a/43870188/724872. __builtin_expect
// is since C++11.
paddle/platform/enforce.h
Outdated
template <typename... Args> | ||
inline void throw_on_error(int stat, const Args&... args) { | ||
if (UNLIKELY(!(stat))) { | ||
PADDLE_THROW(args...); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that we don't really need PADDLE_THROW
or EnforceNotMet
; instead, we can call
throw std::runtime_error(...);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I totally agree with you, I will remove EnforceNotMet
and PADDLE_THROW
paddle/platform/enforce.h
Outdated
#define PADDLE_THROW(...) \ | ||
do { \ | ||
throw ::paddle::platform::EnforceNotMet( \ | ||
::paddle::string::Sprintf(__VA_ARGS__), __FILE__, __LINE__); \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that paddle::string
doesn't call paddle::platform
now, so it is safe to make paddle::platform
call paddle::string
. I think this is the right calling direction. Thanks!
#ifndef PADDLE_ONLY_CPU | ||
|
||
template <typename... Args> | ||
inline void throw_on_error(cudaError_t e, const Args&... args) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about we don't make these throw_on_error
variants inline functions, but just normal functions, so we could move their implementations into a .cc file and make this header files concise and clean? It seems that this wouldn't degrade the performance of PADDLE_ENFORECE.
It looks to me that it's reasonable to keep this header file short; currently, the #ifndef PADDLE_ONLY_CPU
check spans over too many lines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good idea, but enforce.h
is always frequently used in almost all source files.
If we separate it to *.h,*.cc
, then almost all files have to compile with libenforce.a
as follows:
cc_library(each_file SRCS each_file.cc DEPS enforce)
That's quite annoying.
#endif // PADDLE_ONLY_CPU | ||
|
||
template <typename... Args> | ||
inline void throw_on_error(int stat, const Args&... args) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition to a int stat
variant, should we also have a bool
variant? I noticed applications like
PADDLE_ENFORCE(paddle::platform::is_cpu_place(self.place()),
"Only CPU tensor can cast to numpy array");
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will double check this, because we already use bool
condition in our tensor implementation, but it didn't throw a error.
The pr modifies many files, does it modify automatically or by hand? |
@QiJune Using IDE or Modern editor like VS CODE can easily achieve this. |
No description provided.