From 974b8a8317855f8280f0d6152d800e4391998073 Mon Sep 17 00:00:00 2001 From: Chen Weihang Date: Thu, 21 Nov 2019 23:17:42 +0800 Subject: [PATCH] Cherry-pick error type support for release1.6 (#21294) * delete paddle infershape enforce marco (#20832) * Polish and arrange code in enforce.h (#20901) * Enrich the type of error and declare the error type interfaces (#21024) * Enrich the type of error and declare the error type interfaces, test=develop * adjust tests to adapt new form, test=develop * add inference deps with error_codes.pb.h, test=develop * restore stack iter start pos, test=develop * polish code based review comments, test=develop * Add dependency for error_codes.proto (#21084) * fix activation_functions deps, test=develop, test=document_fix * add error_codes_proto deps, test=develop, test=document_fix * try delete enforce.h, test=develop, test=document_fix * change cuda enforce & add example (#21142) test=release/1.6 --- cmake/inference_lib.cmake | 4 +- paddle/fluid/framework/tensor_test.cc | 9 +- .../cuda_device_context_allocator.h | 3 +- paddle/fluid/operators/linear_chain_crf_op.cc | 36 +- .../math/detail/activation_functions.h | 4 +- paddle/fluid/operators/metrics/accuracy_op.cc | 27 +- paddle/fluid/operators/metrics/auc_op.cc | 14 +- paddle/fluid/operators/mul_op.cc | 49 +- paddle/fluid/operators/smooth_l1_loss_op.cc | 12 +- .../fluid/operators/squared_l2_distance_op.cc | 14 +- paddle/fluid/platform/CMakeLists.txt | 9 +- paddle/fluid/platform/enforce.h | 602 +++++++++--------- paddle/fluid/platform/enforce_test.cc | 6 +- paddle/fluid/platform/error_codes.proto | 80 +++ paddle/fluid/platform/errors.cc | 79 +++ paddle/fluid/platform/errors.h | 94 +++ paddle/fluid/platform/errors_test.cc | 122 ++++ 17 files changed, 785 insertions(+), 379 deletions(-) create mode 100644 paddle/fluid/platform/error_codes.proto create mode 100644 paddle/fluid/platform/errors.cc create mode 100644 paddle/fluid/platform/errors.h create mode 100644 paddle/fluid/platform/errors_test.cc diff --git a/cmake/inference_lib.cmake b/cmake/inference_lib.cmake index 9dd65438d5d..b3afae79ca3 100644 --- a/cmake/inference_lib.cmake +++ b/cmake/inference_lib.cmake @@ -223,8 +223,8 @@ set(module "platform") set(platform_lib_deps profiler_proto) add_dependencies(fluid_lib_dist ${platform_lib_deps}) copy(fluid_lib_dist - SRCS ${src_dir}/${module}/*.h ${src_dir}/${module}/dynload/*.h ${src_dir}/${module}/details/*.h ${PADDLE_BINARY_DIR}/paddle/fluid/platform/profiler.pb.h - DSTS ${dst_dir}/${module} ${dst_dir}/${module}/dynload ${dst_dir}/${module}/details ${dst_dir}/${module} + SRCS ${src_dir}/${module}/*.h ${src_dir}/${module}/dynload/*.h ${src_dir}/${module}/details/*.h ${PADDLE_BINARY_DIR}/paddle/fluid/platform/profiler.pb.h ${PADDLE_BINARY_DIR}/paddle/fluid/platform/error_codes.pb.h + DSTS ${dst_dir}/${module} ${dst_dir}/${module}/dynload ${dst_dir}/${module}/details ${dst_dir}/${module} ${dst_dir}/${module} ) set(module "string") diff --git a/paddle/fluid/framework/tensor_test.cc b/paddle/fluid/framework/tensor_test.cc index 8438feca652..84f98d339a2 100644 --- a/paddle/fluid/framework/tensor_test.cc +++ b/paddle/fluid/framework/tensor_test.cc @@ -39,8 +39,8 @@ TEST(Tensor, DataAssert) { } catch (platform::EnforceNotMet& err) { caught = true; std::string ex_msg = err.what(); - EXPECT_TRUE(ex_msg.find("holder_ should not be null\nTensor holds no " - "memory. Call " + EXPECT_TRUE(ex_msg.find("holder_ should not be null") != std::string::npos); + EXPECT_TRUE(ex_msg.find("Tensor holds no memory. Call " "Tensor::mutable_data first.") != std::string::npos); } @@ -154,8 +154,9 @@ TEST(Tensor, ShareDataWith) { } catch (paddle::platform::EnforceNotMet& err) { caught = true; std::string ex_msg = err.what(); - EXPECT_TRUE(ex_msg.find("holder_ should not be null\nTensor holds no " - "memory. Call " + EXPECT_TRUE(ex_msg.find("holder_ should not be null") != + std::string::npos); + EXPECT_TRUE(ex_msg.find("Tensor holds no memory. Call " "Tensor::mutable_data first.") != std::string::npos); } diff --git a/paddle/fluid/memory/allocation/cuda_device_context_allocator.h b/paddle/fluid/memory/allocation/cuda_device_context_allocator.h index 1f8ad370bf2..0997f575acc 100644 --- a/paddle/fluid/memory/allocation/cuda_device_context_allocator.h +++ b/paddle/fluid/memory/allocation/cuda_device_context_allocator.h @@ -81,7 +81,8 @@ class CUDADeviceContextAllocator : public Allocator { platform::CUDADeviceGuard guard(place_.device); PADDLE_ENFORCE_CUDA_SUCCESS( cudaEventCreate(&event_, cudaEventDisableTiming), - "Create event failed in CUDADeviceContextAllocator"); + platform::errors::External( + "Create event failed in CUDADeviceContextAllocator")); } ~CUDADeviceContextAllocator() { diff --git a/paddle/fluid/operators/linear_chain_crf_op.cc b/paddle/fluid/operators/linear_chain_crf_op.cc index b6758c8975b..32d9f09e3a2 100644 --- a/paddle/fluid/operators/linear_chain_crf_op.cc +++ b/paddle/fluid/operators/linear_chain_crf_op.cc @@ -184,30 +184,34 @@ class LinearChainCRFOp : public framework::OperatorWithKernel { true, "The Input(Label) should be a 3-D tensor with last " "dimension fixed to 1 or a 2-D tensor in padding mode."); - PADDLE_INFERSHAPE_ENFORCE_EQ( - ctx, emission_dims[0], label_dims[0], - "The batch size of Input(Emission) and Input(Label) " - "should be the same."); - PADDLE_INFERSHAPE_ENFORCE_EQ( - ctx, emission_dims[1], label_dims[1], - "The max length of Input(Emission) and Input(Label) " - "should be the same."); + if (ctx->IsRuntime()) { + PADDLE_ENFORCE_EQ(emission_dims[0], label_dims[0], + "The batch size of Input(Emission) and Input(Label) " + "should be the same."); + PADDLE_ENFORCE_EQ(emission_dims[1], label_dims[1], + "The max length of Input(Emission) and Input(Label) " + "should be the same."); + } } else { PADDLE_ENFORCE_EQ(emission_dims.size(), 2, "The Input(Emission) should be a 2-D tensor."); - PADDLE_INFERSHAPE_ENFORCE_EQ( - ctx, emission_dims[1], transition_dims[1], - "The 2nd dimension of the Input(Emission) and the Input(Transition) " - "should be equal to the tag number."); + if (ctx->IsRuntime()) { + PADDLE_ENFORCE_EQ(emission_dims[1], transition_dims[1], + "The 2nd dimension of the Input(Emission) and the " + "Input(Transition) " + "should be equal to the tag number."); + } auto label_dims = ctx->GetInputDim("Label"); PADDLE_ENFORCE_EQ(label_dims.size(), 2, "The Input(Label) should be a 2-D tensor with the 2nd " "dimensions fixed to 1."); - PADDLE_INFERSHAPE_ENFORCE_EQ( - ctx, emission_dims[0], label_dims[0], - "The height of Input(Emission) and the height of Input(Label) " - "should be the same."); + if (ctx->IsRuntime()) { + PADDLE_ENFORCE_EQ( + emission_dims[0], label_dims[0], + "The height of Input(Emission) and the height of Input(Label) " + "should be the same."); + } } ctx->SetOutputDim("Alpha", emission_dims); ctx->SetOutputDim("EmissionExps", emission_dims); diff --git a/paddle/fluid/operators/math/detail/activation_functions.h b/paddle/fluid/operators/math/detail/activation_functions.h index 24df1f93edd..5476b1a2d33 100644 --- a/paddle/fluid/operators/math/detail/activation_functions.h +++ b/paddle/fluid/operators/math/detail/activation_functions.h @@ -14,9 +14,9 @@ limitations under the License. */ #pragma once #include +#include #include #include "paddle/fluid/platform/cpu_info.h" -#include "paddle/fluid/platform/enforce.h" #include "paddle/fluid/platform/hostdevice.h" namespace paddle { @@ -45,7 +45,7 @@ inline ActivationType GetActivationType(const std::string &type) { } else if (type == "identity" || type == "") { return ActivationType::kIdentity; } - PADDLE_THROW("Not support type %s.", type); + throw std::invalid_argument("The input type is not supported"); } namespace forward { diff --git a/paddle/fluid/operators/metrics/accuracy_op.cc b/paddle/fluid/operators/metrics/accuracy_op.cc index bedcfc6a387..937b987b88c 100644 --- a/paddle/fluid/operators/metrics/accuracy_op.cc +++ b/paddle/fluid/operators/metrics/accuracy_op.cc @@ -45,19 +45,20 @@ class AccuracyOp : public framework::OperatorWithKernel { "ShapeError: label's dimensions of AccuracyOp must be 2. " "But received label's dimensions = %d, label's shape = [%s]", label_dim.size(), label_dim); - PADDLE_INFERSHAPE_ENFORCE_EQ( - ctx, label_dim[1], 1, - "ShapeError: label's second dimension of " - "AccuracyOp must be 1. But received label's " - "second dimension is = %d, label's shape = [%s]", - label_dim[1], label_dim); - PADDLE_INFERSHAPE_ENFORCE_EQ( - ctx, inference_dim[0], label_dim[0], - "ShapeError: the output's num_rows of AccuracyOp must be" - " the same as label's num_rows. But received output's " - "shape = [%s], label's shape = [%s], output's num_rows = %d, label's " - "num_rows = %d", - inference_dim, label_dim, inference_dim[0], label_dim[0]); + if (ctx->IsRuntime()) { + PADDLE_ENFORCE_EQ(label_dim[1], 1, + "ShapeError: label's second dimension of " + "AccuracyOp must be 1. But received label's " + "second dimension is = %d, label's shape = [%s]", + label_dim[1], label_dim); + PADDLE_ENFORCE_EQ( + inference_dim[0], label_dim[0], + "ShapeError: the output's num_rows of AccuracyOp must be" + " the same as label's num_rows. But received output's " + "shape = [%s], label's shape = [%s], output's num_rows = %d, label's " + "num_rows = %d", + inference_dim, label_dim, inference_dim[0], label_dim[0]); + } ctx->SetOutputDim("Accuracy", {1}); ctx->SetOutputDim("Correct", {1}); diff --git a/paddle/fluid/operators/metrics/auc_op.cc b/paddle/fluid/operators/metrics/auc_op.cc index 3543a334935..90734307acc 100644 --- a/paddle/fluid/operators/metrics/auc_op.cc +++ b/paddle/fluid/operators/metrics/auc_op.cc @@ -28,14 +28,18 @@ class AucOp : public framework::OperatorWithKernel { PADDLE_ENFORCE(ctx->HasInput("Label"), "Input of Label should not be null."); auto predict_width = ctx->GetInputDim("Predict")[1]; - PADDLE_INFERSHAPE_ENFORCE_LE(ctx, predict_width, 2, - "Only support binary classification," - "prediction dims[1] should be 1 or 2"); + if (ctx->IsRuntime()) { + PADDLE_ENFORCE_LE(predict_width, 2, + "Only support binary classification," + "prediction dims[1] should be 1 or 2"); + } auto predict_height = ctx->GetInputDim("Predict")[0]; auto label_height = ctx->GetInputDim("Label")[0]; - PADDLE_INFERSHAPE_ENFORCE_EQ(ctx, predict_height, label_height, - "Out and Label should have same height."); + if (ctx->IsRuntime()) { + PADDLE_ENFORCE_EQ(predict_height, label_height, + "Out and Label should have same height."); + } int num_pred_buckets = ctx->Attrs().Get("num_thresholds") + 1; int slide_steps = ctx->Attrs().Get("slide_steps"); diff --git a/paddle/fluid/operators/mul_op.cc b/paddle/fluid/operators/mul_op.cc index 2be2d7b548e..db0786fe636 100644 --- a/paddle/fluid/operators/mul_op.cc +++ b/paddle/fluid/operators/mul_op.cc @@ -48,32 +48,41 @@ class MulOp : public framework::OperatorWithKernel { << " y_num_col_dims=" << y_num_col_dims; PADDLE_ENFORCE_NE(framework::product(y_dims), 0, - "Maybe the Input variable Y(%s) has not " - "been initialized. You may need to confirm " - "if you put exe.run(startup_program) " - "after optimizer.minimize function.", - ctx->Inputs("Y").front()); - PADDLE_ENFORCE_GT(x_dims.size(), x_num_col_dims, - "ShapeError: The input tensor X's dimensions of MulOp " - "should be larger than x_num_col_dims. But received X's " - "dimensions = %d, X's shape = [%s], x_num_col_dims = %d.", - x_dims.size(), x_dims, x_num_col_dims); - PADDLE_ENFORCE_GT(y_dims.size(), y_num_col_dims, - "ShapeError: The input tensor Y's dimensions of MulOp " - "should be larger than y_num_col_dims. But received Y's " - "dimensions = %d, Y's shape = [%s], y_num_col_dims = %d.", - y_dims.size(), y_dims, y_num_col_dims); + platform::errors::PreconditionNotMet( + "Maybe the Input variable Y(%s) has not " + "been initialized. You may need to confirm " + "if you put exe.run(startup_program) " + "after optimizer.minimize function.", + ctx->Inputs("Y").front())); + PADDLE_ENFORCE_GT( + x_dims.size(), x_num_col_dims, + platform::errors::InvalidArgument( + "The input tensor X's dimensions of MulOp " + "should be larger than x_num_col_dims. But received X's " + "dimensions = %d, X's shape = [%s], x_num_col_dims = %d.", + x_dims.size(), x_dims, x_num_col_dims)); + PADDLE_ENFORCE_GT( + y_dims.size(), y_num_col_dims, + platform::errors::InvalidArgument( + "The input tensor Y's dimensions of MulOp " + "should be larger than y_num_col_dims. But received Y's " + "dimensions = %d, Y's shape = [%s], y_num_col_dims = %d.", + y_dims.size(), y_dims, y_num_col_dims)); auto x_mat_dims = framework::flatten_to_2d(x_dims, x_num_col_dims); auto y_mat_dims = framework::flatten_to_2d(y_dims, y_num_col_dims); PADDLE_ENFORCE_EQ( x_mat_dims[1], y_mat_dims[0], - "ShapeError: After flatten the input tensor X and Y to 2-D dimensions " - "matrix X1 and Y1, the matrix X1's width must be equal with matrix " - "Y1's height. But received X's shape = [%s], X1's shape = [%s], X1's " - "width = %s; Y's shape = [%s], Y1's shape = [%s], Y1's height = %s.", - x_dims, x_mat_dims, x_mat_dims[1], y_dims, y_mat_dims, y_mat_dims[0]); + platform::errors::InvalidArgument( + "After flatten the input tensor X and Y to 2-D dimensions " + "matrix X1 and Y1, the matrix X1's width must be equal with matrix " + "Y1's height. But received X's shape = [%s], X1's shape = [%s], " + "X1's " + "width = %s; Y's shape = [%s], Y1's shape = [%s], Y1's height = " + "%s.", + x_dims, x_mat_dims, x_mat_dims[1], y_dims, y_mat_dims, + y_mat_dims[0])); std::vector output_dims; output_dims.reserve( static_cast(x_num_col_dims + y_dims.size() - y_num_col_dims)); diff --git a/paddle/fluid/operators/smooth_l1_loss_op.cc b/paddle/fluid/operators/smooth_l1_loss_op.cc index 22b621248d6..fbfe3331188 100644 --- a/paddle/fluid/operators/smooth_l1_loss_op.cc +++ b/paddle/fluid/operators/smooth_l1_loss_op.cc @@ -135,11 +135,13 @@ class SmoothL1LossGradOp : public framework::OperatorWithKernel { PADDLE_ENFORCE_GE(out_dims.size(), 2, "The tensor rank of Input(Out@Grad) should be 2."); - PADDLE_INFERSHAPE_ENFORCE_EQ(ctx, out_dims[0], in_dims[0], - "The 1st dimension of Input(Out@Grad) must be " - "same as input."); - PADDLE_INFERSHAPE_ENFORCE_EQ( - ctx, out_dims[1], 1, "The 2nd dimension of Input(Out@Grad) must be 1."); + if (ctx->IsRuntime()) { + PADDLE_ENFORCE_EQ(out_dims[0], in_dims[0], + "The 1st dimension of Input(Out@Grad) must be " + "same as input."); + PADDLE_ENFORCE_EQ(out_dims[1], 1, + "The 2nd dimension of Input(Out@Grad) must be 1."); + } auto x_grad_name = framework::GradVarName("X"); auto y_grad_name = framework::GradVarName("Y"); diff --git a/paddle/fluid/operators/squared_l2_distance_op.cc b/paddle/fluid/operators/squared_l2_distance_op.cc index 17538c98fe5..6c0b195decc 100644 --- a/paddle/fluid/operators/squared_l2_distance_op.cc +++ b/paddle/fluid/operators/squared_l2_distance_op.cc @@ -137,12 +137,14 @@ class SquaredL2DistanceGradOp : public framework::OperatorWithKernel { auto out_dims = ctx->GetInputDim(framework::GradVarName("Out")); auto x_dims = ctx->GetInputDim("X"); auto y_dims = ctx->GetInputDim("Y"); - PADDLE_INFERSHAPE_ENFORCE_EQ(ctx, out_dims[0], x_dims[0], - "First dimension of output gradient and " - "input value must be equal."); - PADDLE_INFERSHAPE_ENFORCE_EQ(ctx, out_dims[1], 1, - "Second dimension of output gradient " - "must be 1."); + if (ctx->IsRuntime()) { + PADDLE_ENFORCE_EQ(out_dims[0], x_dims[0], + "First dimension of output gradient and " + "input value must be equal."); + PADDLE_ENFORCE_EQ(out_dims[1], 1, + "Second dimension of output gradient " + "must be 1."); + } auto x_grad_name = framework::GradVarName("X"); auto y_grad_name = framework::GradVarName("Y"); if (ctx->HasOutput(x_grad_name)) ctx->SetOutputDim(x_grad_name, x_dims); diff --git a/paddle/fluid/platform/CMakeLists.txt b/paddle/fluid/platform/CMakeLists.txt index 744b4964874..2c94f939b74 100644 --- a/paddle/fluid/platform/CMakeLists.txt +++ b/paddle/fluid/platform/CMakeLists.txt @@ -1,8 +1,8 @@ proto_library(profiler_proto SRCS profiler.proto DEPS framework_proto simple_threadpool) py_proto_compile(profiler_py_proto SRCS profiler.proto) +proto_library(error_codes_proto SRCS error_codes.proto) add_custom_target(profiler_py_proto_init ALL COMMAND ${CMAKE_COMMAND} -E touch __init__.py) - add_dependencies(profiler_py_proto profiler_py_proto_init) if (NOT WIN32) @@ -22,10 +22,13 @@ endif(NOT WIN32) cc_library(flags SRCS flags.cc DEPS gflags) +cc_library(errors SRCS errors.cc DEPS error_codes_proto) +cc_test(errors_test SRCS errors_test.cc DEPS errors enforce) + if(WITH_GPU) - nv_library(enforce SRCS enforce.cc DEPS flags) + nv_library(enforce SRCS enforce.cc DEPS flags errors) else() - cc_library(enforce SRCS enforce.cc DEPS flags) + cc_library(enforce SRCS enforce.cc DEPS flags errors) endif() cc_test(enforce_test SRCS enforce_test.cc DEPS stringpiece enforce) diff --git a/paddle/fluid/platform/enforce.h b/paddle/fluid/platform/enforce.h index a1dc1718327..8ab00205846 100644 --- a/paddle/fluid/platform/enforce.h +++ b/paddle/fluid/platform/enforce.h @@ -38,6 +38,7 @@ limitations under the License. */ #define GLOG_NO_ABBREVIATED_SEVERITIES // msvc conflict logging with windows.h #include "glog/logging.h" +#include "paddle/fluid/platform/errors.h" #include "paddle/fluid/platform/macros.h" #include "paddle/fluid/platform/port.h" #include "paddle/fluid/string/printf.h" @@ -52,11 +53,30 @@ limitations under the License. */ #endif // __APPLE__ #endif // PADDLE_WITH_CUDA -#define WITH_SIMPLE_TRACEBACK - namespace paddle { namespace platform { +/** HELPER MACROS AND FUNCTIONS **/ + +// 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. __builtin_expect is since C++11. +// For more details, please check https://stackoverflow.com/a/43870188/724872. +#if !defined(_WIN32) +#define UNLIKELY(condition) __builtin_expect(static_cast(condition), 0) +#else +// there is no equivalent intrinsics in msvc. +#define UNLIKELY(condition) (condition) +#endif + +#if !defined(_WIN32) +#define LIKELY(condition) __builtin_expect(static_cast(condition), 1) +#else +// there is no equivalent intrinsics in msvc. +#define LIKELY(condition) (condition) +#endif + #ifdef __GNUC__ inline std::string demangle(std::string name) { int status = -4; // some arbitrary value to eliminate the compiler warning @@ -68,6 +88,82 @@ inline std::string demangle(std::string name) { inline std::string demangle(std::string name) { return name; } #endif +namespace details { +template +inline constexpr bool IsArithmetic() { + return std::is_arithmetic::value; +} + +template +struct TypeConverterImpl { + using Type1 = typename std::common_type::type; + using Type2 = Type1; +}; + +template +struct TypeConverterImpl { + using Type1 = T1; + using Type2 = T2; +}; + +template +struct TypeConverter { + private: + static constexpr bool kIsArithmetic = + IsArithmetic() && IsArithmetic(); + + public: + using Type1 = typename TypeConverterImpl::Type1; + using Type2 = typename TypeConverterImpl::Type2; +}; + +template +using CommonType1 = typename std::add_lvalue_reference< + typename std::add_const::Type1>::type>::type; + +template +using CommonType2 = typename std::add_lvalue_reference< + typename std::add_const::Type2>::type>::type; + +// Here, we use SFINAE to check whether T can be converted to std::string +template +struct CanToString { + private: + using YesType = uint8_t; + using NoType = uint16_t; + + template + static YesType Check(decltype(std::cout << std::declval())) { + return 0; + } + + template + static NoType Check(...) { + return 0; + } + + public: + static constexpr bool kValue = + std::is_same(std::cout))>::value; +}; + +template +struct BinaryCompareMessageConverter { + template + static std::string Convert(const char* expression, const T& value) { + return expression + std::string(":") + string::to_string(value); + } +}; + +template <> +struct BinaryCompareMessageConverter { + template + static const char* Convert(const char* expression, const T& value) { + return expression; + } +}; +} // namespace details + template inline std::string GetTraceBackString(StrType&& what, const char* file, int line) { @@ -86,21 +182,11 @@ inline std::string GetTraceBackString(StrType&& what, const char* file, for (int i = 0; i < size; ++i) { if (dladdr(call_stack[i], &info) && info.dli_sname) { auto demangled = demangle(info.dli_sname); -#ifdef WITH_SIMPLE_TRACEBACK std::string path(info.dli_fname); // C++ traceback info are from core.so if (path.substr(path.length() - 3).compare(".so") == 0) { sout << string::Sprintf("%-3d %s\n", idx++, demangled); } -#else - auto addr_offset = static_cast(call_stack[i]) - - static_cast(info.dli_saddr); - sout << string::Sprintf("%-3d %*0p %s + %zd\n", i, 2 + sizeof(void*) * 2, - call_stack[i], demangled, addr_offset); - } else { - sout << string::Sprintf("%-3d %*0p\n", i, 2 + sizeof(void*) * 2, - call_stack[i]); -#endif } } free(symbols); @@ -109,14 +195,33 @@ inline std::string GetTraceBackString(StrType&& what, const char* file, #endif sout << "\n----------------------\nError Message " "Summary:\n----------------------\n"; - sout << string::Sprintf("PaddleCheckError: %s at [%s:%d]", - std::forward(what), file, line) + sout << string::Sprintf("%s at (%s:%d)", std::forward(what), file, + line) << std::endl; return sout.str(); } +inline bool is_error(bool stat) { return !stat; } + +inline void throw_on_error(bool stat, const std::string& msg) { +#ifndef REPLACE_ENFORCE_GLOG + throw std::runtime_error(msg); +#else + LOG(FATAL) << msg; +#endif +} + +inline void throw_on_error(const platform::ErrorSummary& error) { +#ifndef REPLACE_ENFORCE_GLOG + throw std::runtime_error(error.ToString()); +#else + LOG(FATAL) << error.ToString(); +#endif +} + +/** ENFORCE EXCEPTION AND MACROS **/ + struct EnforceNotMet : public std::exception { - std::string err_str_; EnforceNotMet(std::exception_ptr e, const char* file, int line) { try { std::rethrow_exception(e); @@ -128,9 +233,118 @@ struct EnforceNotMet : public std::exception { EnforceNotMet(const std::string& str, const char* file, int line) : err_str_(GetTraceBackString(str, file, line)) {} + EnforceNotMet(const platform::ErrorSummary& error, const char* file, int line) + : err_str_(GetTraceBackString(error.ToString(), file, line)) {} + const char* what() const noexcept override { return err_str_.c_str(); } + + std::string err_str_; }; +#define PADDLE_THROW(...) \ + do { \ + throw ::paddle::platform::EnforceNotMet( \ + ::paddle::platform::ErrorSummary(__VA_ARGS__), __FILE__, __LINE__); \ + } while (0) + +#define PADDLE_THROW_ERROR(...) \ + do { \ + throw ::paddle::platform::EnforceNotMet( \ + ::paddle::string::Sprintf(__VA_ARGS__), __FILE__, __LINE__); \ + } while (0) + +#if defined(__CUDA_ARCH__) +// For cuda, the assertions can affect performance and it is therefore +// recommended to disable them in production code +// https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#assertion +#define PADDLE_ENFORCE(_IS_NOT_ERROR, __FORMAT, ...) \ + do { \ + if (!(_IS_NOT_ERROR)) { \ + printf("Error: %s:%d Assertion `%s` failed. " __FORMAT "\n", __FILE__, \ + __LINE__, #_IS_NOT_ERROR, ##__VA_ARGS__); \ + asm("trap;"); \ + } \ + } while (0) +#else +#define PADDLE_ENFORCE(COND, ...) \ + do { \ + auto __cond__ = (COND); \ + if (UNLIKELY(::paddle::platform::is_error(__cond__))) { \ + try { \ + ::paddle::platform::throw_on_error( \ + ::paddle::platform::ErrorSummary(__VA_ARGS__)); \ + } catch (...) { \ + throw ::paddle::platform::EnforceNotMet(std::current_exception(), \ + __FILE__, __LINE__); \ + } \ + } \ + } while (0) +#endif + +/* + * Some enforce helpers here, usage: + * int a = 1; + * int b = 2; + * PADDLE_ENFORCE_EQ(a, b); + * + * will raise an expression described as follows: + * "Expected input a == b, but received a(1) != b(2)." + * with detailed stack information. + * + * extra messages is also supported, for example: + * PADDLE_ENFORCE(a, b, "some simple enforce failed between %d numbers", 2) + */ +#define PADDLE_ENFORCE_NOT_NULL(__VAL, ...) \ + do { \ + if (UNLIKELY(nullptr == (__VAL))) { \ + PADDLE_THROW_ERROR( \ + "%s\n [Hint: " #__VAL " should not be null.]", \ + ::paddle::platform::ErrorSummary(__VA_ARGS__).ToString()); \ + } \ + } while (0) + +#define __PADDLE_BINARY_COMPARE(__VAL1, __VAL2, __CMP, __INV_CMP, ...) \ + do { \ + auto __val1 = (__VAL1); \ + auto __val2 = (__VAL2); \ + using __TYPE1__ = decltype(__val1); \ + using __TYPE2__ = decltype(__val2); \ + using __COMMON_TYPE1__ = \ + ::paddle::platform::details::CommonType1<__TYPE1__, __TYPE2__>; \ + using __COMMON_TYPE2__ = \ + ::paddle::platform::details::CommonType2<__TYPE1__, __TYPE2__>; \ + bool __is_not_error = (static_cast<__COMMON_TYPE1__>(__val1))__CMP( \ + static_cast<__COMMON_TYPE2__>(__val2)); \ + if (UNLIKELY(!__is_not_error)) { \ + constexpr bool __kCanToString__ = \ + ::paddle::platform::details::CanToString<__TYPE1__>::kValue && \ + ::paddle::platform::details::CanToString<__TYPE2__>::kValue; \ + PADDLE_THROW_ERROR( \ + "%s\n [Hint: Expected %s " #__CMP \ + " %s, but received %s " #__INV_CMP " %s.]", \ + ::paddle::platform::ErrorSummary(__VA_ARGS__).ToString(), #__VAL1, \ + #__VAL2, ::paddle::platform::details::BinaryCompareMessageConverter< \ + __kCanToString__>::Convert(#__VAL1, __val1), \ + ::paddle::platform::details::BinaryCompareMessageConverter< \ + __kCanToString__>::Convert(#__VAL2, __val2)); \ + } \ + } while (0) + +#define PADDLE_ENFORCE_EQ(__VAL0, __VAL1, ...) \ + __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, ==, !=, __VA_ARGS__) +#define PADDLE_ENFORCE_NE(__VAL0, __VAL1, ...) \ + __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, !=, ==, __VA_ARGS__) +#define PADDLE_ENFORCE_GT(__VAL0, __VAL1, ...) \ + __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, >, <=, __VA_ARGS__) +#define PADDLE_ENFORCE_GE(__VAL0, __VAL1, ...) \ + __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, >=, <, __VA_ARGS__) +#define PADDLE_ENFORCE_LT(__VAL0, __VAL1, ...) \ + __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, <, >=, __VA_ARGS__) +#define PADDLE_ENFORCE_LE(__VAL0, __VAL1, ...) \ + __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, <=, >, __VA_ARGS__) + +/** OTHER EXCEPTION AND ENFORCE **/ + struct EOFException : public std::exception { std::string err_str_; EOFException(const char* err_msg, const char* file, int line) { @@ -140,39 +354,28 @@ struct EOFException : public std::exception { const char* what() const noexcept override { return err_str_.c_str(); } }; -// 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. __builtin_expect is since C++11. -// For more details, please check https://stackoverflow.com/a/43870188/724872. -#if !defined(_WIN32) -#define UNLIKELY(condition) __builtin_expect(static_cast(condition), 0) -#else -// there is no equivalent intrinsics in msvc. -#define UNLIKELY(condition) (condition) -#endif - -#if !defined(_WIN32) -#define LIKELY(condition) __builtin_expect(static_cast(condition), 1) -#else -// there is no equivalent intrinsics in msvc. -#define LIKELY(condition) (condition) -#endif +#define PADDLE_THROW_EOF() \ + do { \ + throw ::paddle::platform::EOFException("There is no next data.", __FILE__, \ + __LINE__); \ + } while (0) -inline bool is_error(bool stat) { return !stat; } +#define PADDLE_THROW_BAD_ALLOC(...) \ + do { \ + throw ::paddle::memory::allocation::BadAlloc( \ + ::paddle::string::Sprintf(__VA_ARGS__), __FILE__, __LINE__); \ + } while (0) -inline void throw_on_error(bool stat, const std::string& msg) { -#ifndef REPLACE_ENFORCE_GLOG - throw std::runtime_error(msg); -#else - LOG(FATAL) << msg; -#endif -} +/** CUDA PADDLE ENFORCE FUNCTIONS AND MACROS **/ #ifdef PADDLE_WITH_CUDA inline bool is_error(cudaError_t e) { return e != cudaSuccess; } +inline std::string build_ex_string(cudaError_t e, const std::string& msg) { + return msg; +} + inline void throw_on_error(cudaError_t e, const std::string& msg) { #ifndef REPLACE_ENFORCE_GLOG throw thrust::system_error(e, thrust::cuda_category(), msg); @@ -185,6 +388,11 @@ inline bool is_error(curandStatus_t stat) { return stat != CURAND_STATUS_SUCCESS; } +inline std::string build_ex_string(curandStatus_t stat, + const std::string& msg) { + return msg; +} + inline void throw_on_error(curandStatus_t stat, const std::string& msg) { #ifndef REPLACE_ENFORCE_GLOG throw thrust::system_error(cudaErrorLaunchFailure, thrust::cuda_category(), @@ -198,11 +406,15 @@ inline bool is_error(cudnnStatus_t stat) { return stat != CUDNN_STATUS_SUCCESS; } +inline std::string build_ex_string(cudnnStatus_t stat, const std::string& msg) { + return msg + "\n [" + platform::dynload::cudnnGetErrorString(stat) + "]"; +} + inline void throw_on_error(cudnnStatus_t stat, const std::string& msg) { #ifndef REPLACE_ENFORCE_GLOG - throw std::runtime_error(platform::dynload::cudnnGetErrorString(stat) + msg); + throw std::runtime_error(msg); #else - LOG(FATAL) << platform::dynload::cudnnGetErrorString(stat) << msg; + LOG(FATAL) << msg; #endif } @@ -210,31 +422,36 @@ inline bool is_error(cublasStatus_t stat) { return stat != CUBLAS_STATUS_SUCCESS; } -inline void throw_on_error(cublasStatus_t stat, const std::string& msg) { +inline std::string build_ex_string(cublasStatus_t stat, + const std::string& msg) { std::string err; if (stat == CUBLAS_STATUS_NOT_INITIALIZED) { - err = "CUBLAS: not initialized, "; + err = "CUBLAS: not initialized."; } else if (stat == CUBLAS_STATUS_ALLOC_FAILED) { - err = "CUBLAS: alloc failed, "; + err = "CUBLAS: alloc failed."; } else if (stat == CUBLAS_STATUS_INVALID_VALUE) { - err = "CUBLAS: invalid value, "; + err = "CUBLAS: invalid value."; } else if (stat == CUBLAS_STATUS_ARCH_MISMATCH) { - err = "CUBLAS: arch mismatch, "; + err = "CUBLAS: arch mismatch."; } else if (stat == CUBLAS_STATUS_MAPPING_ERROR) { - err = "CUBLAS: mapping error, "; + err = "CUBLAS: mapping error."; } else if (stat == CUBLAS_STATUS_EXECUTION_FAILED) { - err = "CUBLAS: execution failed, "; + err = "CUBLAS: execution failed."; } else if (stat == CUBLAS_STATUS_INTERNAL_ERROR) { - err = "CUBLAS: internal error, "; + err = "CUBLAS: internal error."; } else if (stat == CUBLAS_STATUS_NOT_SUPPORTED) { err = "CUBLAS: not supported, "; } else if (stat == CUBLAS_STATUS_LICENSE_ERROR) { - err = "CUBLAS: license error, "; + err = "CUBLAS: license error."; } + return msg + "\n [" + err + "]"; +} + +inline void throw_on_error(cublasStatus_t stat, const std::string& msg) { #ifndef REPLACE_ENFORCE_GLOG - throw std::runtime_error(err + msg); + throw std::runtime_error(msg); #else - LOG(FATAL) << err << msg; + LOG(FATAL) << msg; #endif } @@ -243,14 +460,21 @@ inline bool is_error(ncclResult_t nccl_result) { return nccl_result != ncclSuccess; } -inline void throw_on_error(ncclResult_t stat, const std::string& msg) { +inline std::string build_ex_string(ncclResult_t nccl_result, + const std::string& msg) { + return msg + "\n [" + platform::dynload::ncclGetErrorString(nccl_result) + + "]"; +} + +inline void throw_on_error(ncclResult_t nccl_result, const std::string& msg) { #ifndef REPLACE_ENFORCE_GLOG - throw std::runtime_error(platform::dynload::ncclGetErrorString(stat) + msg); + throw std::runtime_error(msg); #else - LOG(FATAL) << platform::dynload::ncclGetErrorString(stat) << msg; + LOG(FATAL) << msg; #endif } #endif // __APPLE__ and windows + #endif // PADDLE_WITH_CUDA #ifdef PADDLE_WITH_CUDA @@ -276,254 +500,32 @@ DEFINE_CUDA_STATUS_TYPE(ncclResult_t, ncclSuccess); #endif } // namespace details -#endif - -#define PADDLE_THROW(...) \ - do { \ - throw ::paddle::platform::EnforceNotMet( \ - ::paddle::string::Sprintf(__VA_ARGS__), __FILE__, __LINE__); \ - } while (0) - -#if defined(__CUDA_ARCH__) -// For cuda, the assertions can affect performance and it is therefore -// recommended to disable them in production code -// https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#assertion -#define PADDLE_ENFORCE(_IS_NOT_ERROR, __FORMAT, ...) \ - do { \ - if (!(_IS_NOT_ERROR)) { \ - printf("Exception: %s:%d Assertion `%s` failed. " __FORMAT "\n", \ - __FILE__, __LINE__, #_IS_NOT_ERROR, ##__VA_ARGS__); \ - asm("trap;"); \ - } \ - } while (0) -#else -#define PADDLE_ENFORCE(COND, ...) \ - do { \ - auto __cond__ = (COND); \ - if (UNLIKELY(::paddle::platform::is_error(__cond__))) { \ - try { \ - ::paddle::platform::throw_on_error( \ - __cond__, ::paddle::string::Sprintf(__VA_ARGS__)); \ - } catch (...) { \ - throw ::paddle::platform::EnforceNotMet(std::current_exception(), \ - __FILE__, __LINE__); \ - } \ - } \ - } while (0) -#endif +#endif // PADDLE_WITH_CUDA #ifdef PADDLE_WITH_CUDA -#define PADDLE_ENFORCE_CUDA_SUCCESS(COND, ...) \ - do { \ - auto __cond__ = (COND); \ - using __CUDA_STATUS_TYPE__ = decltype(__cond__); \ - constexpr auto __success_type__ = \ - ::paddle::platform::details::CudaStatusType< \ - __CUDA_STATUS_TYPE__>::kSuccess; \ - if (UNLIKELY(__cond__ != __success_type__)) { \ - try { \ - ::paddle::platform::throw_on_error( \ - __cond__, ::paddle::string::Sprintf(__VA_ARGS__)); \ - } catch (...) { \ - throw ::paddle::platform::EnforceNotMet(std::current_exception(), \ - __FILE__, __LINE__); \ - } \ - } \ +#define PADDLE_ENFORCE_CUDA_SUCCESS(COND, ...) \ + do { \ + auto __cond__ = (COND); \ + using __CUDA_STATUS_TYPE__ = decltype(__cond__); \ + constexpr auto __success_type__ = \ + ::paddle::platform::details::CudaStatusType< \ + __CUDA_STATUS_TYPE__>::kSuccess; \ + if (UNLIKELY(__cond__ != __success_type__)) { \ + try { \ + ::paddle::platform::throw_on_error( \ + __cond__, \ + ::paddle::platform::build_ex_string( \ + __cond__, \ + ::paddle::platform::ErrorSummary(__VA_ARGS__).ToString())); \ + } catch (...) { \ + throw ::paddle::platform::EnforceNotMet(std::current_exception(), \ + __FILE__, __LINE__); \ + } \ + } \ } while (0) #undef DEFINE_CUDA_STATUS_TYPE -#endif - -#define PADDLE_THROW_EOF() \ - do { \ - throw ::paddle::platform::EOFException("There is no next data.", __FILE__, \ - __LINE__); \ - } while (0) - -#define PADDLE_THROW_BAD_ALLOC(...) \ - do { \ - throw ::paddle::memory::allocation::BadAlloc( \ - ::paddle::string::Sprintf(__VA_ARGS__), __FILE__, __LINE__); \ - } while (0) - -/* - * Some enforce helpers here, usage: - * int a = 1; - * int b = 2; - * PADDLE_ENFORCE_EQ(a, b); - * - * will raise an expression described as follows: - * "Expected input a == b, but received a(1) != b(2)." - * with detailed stack information. - * - * extra messages is also supported, for example: - * PADDLE_ENFORCE(a, b, "some simple enforce failed between %d numbers", 2) - */ -#define PADDLE_ENFORCE_NOT_NULL(__VAL, ...) \ - do { \ - if (UNLIKELY(nullptr == (__VAL))) { \ - PADDLE_THROW(#__VAL " should not be null\n%s", \ - ::paddle::string::Sprintf(__VA_ARGS__)); \ - } \ - } while (0) - -namespace details { -template -inline constexpr bool IsArithmetic() { - return std::is_arithmetic::value; -} - -template -struct TypeConverterImpl { - using Type1 = typename std::common_type::type; - using Type2 = Type1; -}; - -template -struct TypeConverterImpl { - using Type1 = T1; - using Type2 = T2; -}; - -template -struct TypeConverter { - private: - static constexpr bool kIsArithmetic = - IsArithmetic() && IsArithmetic(); - - public: - using Type1 = typename TypeConverterImpl::Type1; - using Type2 = typename TypeConverterImpl::Type2; -}; - -template -using CommonType1 = typename std::add_lvalue_reference< - typename std::add_const::Type1>::type>::type; - -template -using CommonType2 = typename std::add_lvalue_reference< - typename std::add_const::Type2>::type>::type; - -// Here, we use SFINAE to check whether T can be converted to std::string -template -struct CanToString { - private: - using YesType = uint8_t; - using NoType = uint16_t; - - template - static YesType Check(decltype(std::cout << std::declval())) { - return 0; - } - - template - static NoType Check(...) { - return 0; - } - - public: - static constexpr bool kValue = - std::is_same(std::cout))>::value; -}; - -template -struct BinaryCompareMessageConverter { - template - static std::string Convert(const char* expression, const T& value) { - return expression + std::string(":") + string::to_string(value); - } -}; - -template <> -struct BinaryCompareMessageConverter { - template - static const char* Convert(const char* expression, const T& value) { - return expression; - } -}; - -} // namespace details - -#define __PADDLE_BINARY_COMPARE(__VAL1, __VAL2, __CMP, __INV_CMP, ...) \ - do { \ - auto __val1 = (__VAL1); \ - auto __val2 = (__VAL2); \ - using __TYPE1__ = decltype(__val1); \ - using __TYPE2__ = decltype(__val2); \ - using __COMMON_TYPE1__ = \ - ::paddle::platform::details::CommonType1<__TYPE1__, __TYPE2__>; \ - using __COMMON_TYPE2__ = \ - ::paddle::platform::details::CommonType2<__TYPE1__, __TYPE2__>; \ - bool __is_not_error = (static_cast<__COMMON_TYPE1__>(__val1))__CMP( \ - static_cast<__COMMON_TYPE2__>(__val2)); \ - if (UNLIKELY(!__is_not_error)) { \ - constexpr bool __kCanToString__ = \ - ::paddle::platform::details::CanToString<__TYPE1__>::kValue && \ - ::paddle::platform::details::CanToString<__TYPE2__>::kValue; \ - PADDLE_THROW("Expected %s " #__CMP " %s, but received %s " #__INV_CMP \ - " %s.\n%s", \ - #__VAL1, #__VAL2, \ - ::paddle::platform::details::BinaryCompareMessageConverter< \ - __kCanToString__>::Convert(#__VAL1, __val1), \ - ::paddle::platform::details::BinaryCompareMessageConverter< \ - __kCanToString__>::Convert(#__VAL2, __val2), \ - ::paddle::string::Sprintf(__VA_ARGS__)); \ - } \ - } while (0) - -#define PADDLE_ENFORCE_EQ(__VAL0, __VAL1, ...) \ - __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, ==, !=, __VA_ARGS__) -#define PADDLE_ENFORCE_NE(__VAL0, __VAL1, ...) \ - __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, !=, ==, __VA_ARGS__) -#define PADDLE_ENFORCE_GT(__VAL0, __VAL1, ...) \ - __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, >, <=, __VA_ARGS__) -#define PADDLE_ENFORCE_GE(__VAL0, __VAL1, ...) \ - __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, >=, <, __VA_ARGS__) -#define PADDLE_ENFORCE_LT(__VAL0, __VAL1, ...) \ - __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, <, >=, __VA_ARGS__) -#define PADDLE_ENFORCE_LE(__VAL0, __VAL1, ...) \ - __PADDLE_BINARY_COMPARE(__VAL0, __VAL1, <=, >, __VA_ARGS__) - -#define __PADDLE_INFERSHAPE_BINARY_COMPARE(__CTX, __VAL1, __VAL2, __CMP, \ - __INV_CMP, ...) \ - do { \ - auto __val1 = (__VAL1); \ - auto __val2 = (__VAL2); \ - if (!__CTX->IsRuntime()) { \ - if (__val1 == -1 || __val2 == -1) { \ - break; \ - } \ - } \ - using __TYPE1__ = decltype(__val1); \ - using __TYPE2__ = decltype(__val2); \ - using __COMMON_TYPE1__ = \ - ::paddle::platform::details::CommonType1<__TYPE1__, __TYPE2__>; \ - using __COMMON_TYPE2__ = \ - ::paddle::platform::details::CommonType2<__TYPE1__, __TYPE2__>; \ - bool __is_not_error = (static_cast<__COMMON_TYPE1__>(__val1))__CMP( \ - static_cast<__COMMON_TYPE2__>(__val2)); \ - if (UNLIKELY(!__is_not_error)) { \ - PADDLE_THROW("Expected %s " #__CMP " %s, but received %s:%s " #__INV_CMP \ - " %s:%s.\n%s", \ - #__VAL1, #__VAL2, #__VAL1, \ - ::paddle::string::to_string(__val1), #__VAL2, \ - ::paddle::string::to_string(__val2), \ - ::paddle::string::Sprintf(__VA_ARGS__)); \ - } \ - } while (0) - -#define PADDLE_INFERSHAPE_ENFORCE_EQ(__CTX, __VAL0, __VAL1, ...) \ - __PADDLE_INFERSHAPE_BINARY_COMPARE(__CTX, __VAL0, __VAL1, ==, !=, __VA_ARGS__) -#define PADDLE_INFERSHAPE_ENFORCE_NE(__CTX, __VAL0, __VAL1, ...) \ - __PADDLE_INFERSHAPE_BINARY_COMPARE(__CTX, __VAL0, __VAL1, !=, ==, __VA_ARGS__) -#define PADDLE_INFERSHAPE_ENFORCE_GT(__CTX, __VAL0, __VAL1, ...) \ - __PADDLE_INFERSHAPE_BINARY_COMPARE(__CTX, __VAL0, __VAL1, >, <=, __VA_ARGS__) -#define PADDLE_INFERSHAPE_ENFORCE_GE(__CTX, __VAL0, __VAL1, ...) \ - __PADDLE_INFERSHAPE_BINARY_COMPARE(__CTX, __VAL0, __VAL1, >=, <, __VA_ARGS__) -#define PADDLE_INFERSHAPE_ENFORCE_LT(__CTX, __VAL0, __VAL1, ...) \ - __PADDLE_INFERSHAPE_BINARY_COMPARE(__CTX, __VAL0, __VAL1, <, >=, __VA_ARGS__) -#define PADDLE_INFERSHAPE_ENFORCE_LE(__CTX, __VAL0, __VAL1, ...) \ - __PADDLE_INFERSHAPE_BINARY_COMPARE(__CTX, __VAL0, __VAL1, <=, >, __VA_ARGS__) +#endif // PADDLE_WITH_CUDA } // namespace platform } // namespace paddle diff --git a/paddle/fluid/platform/enforce_test.cc b/paddle/fluid/platform/enforce_test.cc index 8dedfe97049..24d8966e32e 100644 --- a/paddle/fluid/platform/enforce_test.cc +++ b/paddle/fluid/platform/enforce_test.cc @@ -87,8 +87,10 @@ TEST(ENFORCE_EQ, EXTRA_MSG_FAIL) { } catch (paddle::platform::EnforceNotMet& error) { caught_exception = true; std::string ex_msg = error.what(); - EXPECT_TRUE(ex_msg.find("Expected a == 1 + 3, but received a:2 != 1 + " - "3:4.\ntheir size not match") != std::string::npos); + EXPECT_TRUE(ex_msg.find("their size not match") != std::string::npos); + EXPECT_TRUE( + ex_msg.find("Expected a == 1 + 3, but received a:2 != 1 + 3:4.") != + std::string::npos); } EXPECT_TRUE(caught_exception); } diff --git a/paddle/fluid/platform/error_codes.proto b/paddle/fluid/platform/error_codes.proto new file mode 100644 index 00000000000..90ab93dd11d --- /dev/null +++ b/paddle/fluid/platform/error_codes.proto @@ -0,0 +1,80 @@ +/* Copyright (c) 2019 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. */ + +syntax = "proto2"; +option optimize_for = LITE_RUNTIME; +package paddle.platform.error; + +enum Code { + // Legacy error. + // Error type string: "Error" + LEGACY = 0; + + // Client specified an invalid argument. + // Error type string: "InvalidArgumentError" + INVALID_ARGUMENT = 1; + + // Some requested entity (e.g., file or directory) was not found. + // Error type string: "NotFoundError" + NOT_FOUND = 2; + + // Operation tried to iterate past the valid input range. E.g., seeking or + // reading past end of file. + // Error type string: "OutOfRangeError" + OUT_OF_RANGE = 3; + + // Some entity that we attempted to create (e.g., file or directory) + // already exists. + // Error type string: "AlreadyExistsError" + ALREADY_EXISTS = 4; + + // Some resource has been exhausted, perhaps a per-user quota, or + // perhaps the entire file system is out of space. + // Error type string: "ResourceExhaustedError" + RESOURCE_EXHAUSTED = 5; + + // Operation was rejected because the system is not in a state + // required for the operation's execution. + // Error type string: "PreconditionNotMetError" + PRECONDITION_NOT_MET = 6; + + // The caller does not have permission to execute the specified + // operation. + // Error type string: "PermissionDeniedError" + PERMISSION_DENIED = 7; + + // Deadline expired before operation could complete. + // Error type string: "ExecutionTimeout" + EXECUTION_TIMEOUT = 8; + + // Operation is not implemented or not supported/enabled in this service. + // Error type string: "UnimpelmentedError" + UNIMPLEMENTED = 9; + + // The service is currently unavailable. This is a most likely a + // transient condition and may be corrected by retrying with + // a backoff. + // Error type string: "UnavailableError" + UNAVAILABLE = 10; + + // Fatal errors. Means some invariant expected by the underlying + // system has been broken. If you see one of these errors, + // something is very broken. + // Error type string: "FatalError" + FATAL = 11; + + // Third-party library error. + // Error type string: "ExternalError" + EXTERNAL = 12; +} diff --git a/paddle/fluid/platform/errors.cc b/paddle/fluid/platform/errors.cc new file mode 100644 index 00000000000..85beefa59de --- /dev/null +++ b/paddle/fluid/platform/errors.cc @@ -0,0 +1,79 @@ +/* Copyright (c) 2019 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. */ + +#include "paddle/fluid/platform/errors.h" + +#include + +namespace paddle { +namespace platform { + +typedef ::paddle::platform::error::Code Code; + +std::string error_name(Code code) { + switch (code) { + case paddle::platform::error::LEGACY: + return "Error"; + break; + case paddle::platform::error::INVALID_ARGUMENT: + return "InvalidArgumentError"; + break; + case paddle::platform::error::NOT_FOUND: + return "NotFoundError"; + break; + case paddle::platform::error::OUT_OF_RANGE: + return "OutOfRangeError"; + break; + case paddle::platform::error::ALREADY_EXISTS: + return "AlreadyExistsError"; + break; + case paddle::platform::error::RESOURCE_EXHAUSTED: + return "ResourceExhaustedError"; + break; + case paddle::platform::error::PRECONDITION_NOT_MET: + return "PreconditionNotMetError"; + break; + case paddle::platform::error::PERMISSION_DENIED: + return "PermissionDeniedError"; + break; + case paddle::platform::error::EXECUTION_TIMEOUT: + return "ExecutionTimeoutError"; + break; + case paddle::platform::error::UNIMPLEMENTED: + return "UnimplementedError"; + break; + case paddle::platform::error::UNAVAILABLE: + return "UnavailableError"; + break; + case paddle::platform::error::FATAL: + return "FatalError"; + break; + case paddle::platform::error::EXTERNAL: + return "ExternalError"; + break; + default: + throw std::invalid_argument("The error type is undefined."); + break; + } +} + +std::string ErrorSummary::ToString() const { + std::string result(error_name(code())); + result += ": "; + result += error_message(); + return result; +} + +} // namespace platform +} // namespace paddle diff --git a/paddle/fluid/platform/errors.h b/paddle/fluid/platform/errors.h new file mode 100644 index 00000000000..c4184df9eff --- /dev/null +++ b/paddle/fluid/platform/errors.h @@ -0,0 +1,94 @@ +/* Copyright (c) 2019 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 +#include +#include +#include +#include + +#include "paddle/fluid/platform/error_codes.pb.h" +#include "paddle/fluid/string/printf.h" + +namespace paddle { +namespace platform { + +typedef ::paddle::platform::error::Code Code; + +class ErrorSummary { + public: + // Note(chenweihang): Final deprecated constructor + // This constructor is only used to be compatible with + // current existing no error message PADDLE_ENFORCE_* + ErrorSummary() { + code_ = paddle::platform::error::LEGACY; + msg_ = + "Paddle internal Check failed. (Please help us create a new issue, " + "here we need to find the developer to add a user friendly error " + "message)"; + } + + // Note(chenweihang): Final deprecated constructor + // This constructor is used to be compatible with + // current existing untyped PADDLE_ENFORCE_* + // PADDLE_ENFORCE + template + explicit ErrorSummary(Args... args) { + code_ = paddle::platform::error::LEGACY; + msg_ = paddle::string::Sprintf(args...); + } + + // Note(chenweihang): Recommended constructor + explicit ErrorSummary(Code code, std::string msg) : code_(code), msg_(msg) {} + + Code code() const { return code_; } + + const std::string& error_message() const { return msg_; } + + std::string ToString() const; + + private: + Code code_; + std::string msg_; +}; + +namespace errors { + +#define REGISTER_ERROR(FUNC, CONST, ...) \ + template \ + ::paddle::platform::ErrorSummary FUNC(Args... args) { \ + return ::paddle::platform::ErrorSummary( \ + ::paddle::platform::error::CONST, ::paddle::string::Sprintf(args...)); \ + } + +REGISTER_ERROR(InvalidArgument, INVALID_ARGUMENT) +REGISTER_ERROR(NotFound, NOT_FOUND) +REGISTER_ERROR(OutOfRange, OUT_OF_RANGE) +REGISTER_ERROR(AlreadyExists, ALREADY_EXISTS) +REGISTER_ERROR(ResourceExhausted, RESOURCE_EXHAUSTED) +REGISTER_ERROR(PreconditionNotMet, PRECONDITION_NOT_MET) +REGISTER_ERROR(PermissionDenied, PERMISSION_DENIED) +REGISTER_ERROR(ExecutionTimeout, EXECUTION_TIMEOUT) +REGISTER_ERROR(Unimplemented, UNIMPLEMENTED) +REGISTER_ERROR(Unavailable, UNAVAILABLE) +REGISTER_ERROR(Fatal, FATAL) +REGISTER_ERROR(External, EXTERNAL) + +#undef REGISTER_ERROR + +} // namespace errors +} // namespace platform +} // namespace paddle diff --git a/paddle/fluid/platform/errors_test.cc b/paddle/fluid/platform/errors_test.cc new file mode 100644 index 00000000000..3c84215b5e5 --- /dev/null +++ b/paddle/fluid/platform/errors_test.cc @@ -0,0 +1,122 @@ +/* Copyright (c) 2019 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. */ + +#include +#include + +#include "gtest/gtest.h" +#include "paddle/fluid/platform/enforce.h" +#include "paddle/fluid/platform/errors.h" + +using namespace paddle::platform::errors; // NOLINT + +#define CHECK_PADDLE_THROW(EFUNC) \ + do { \ + bool caught_exception = false; \ + try { \ + PADDLE_THROW((EFUNC)("paddle throw test.")); \ + } catch (paddle::platform::EnforceNotMet & error) { \ + caught_exception = true; \ + std::string ex_msg = error.what(); \ + EXPECT_TRUE(ex_msg.find(#EFUNC "Error: paddle throw test.") != \ + std::string::npos); \ + } \ + EXPECT_TRUE(caught_exception); \ + } while (0) + +#define CHECK_PADDLE_ENFORCE(EFUNC) \ + do { \ + bool caught_exception = false; \ + try { \ + PADDLE_ENFORCE(false, (EFUNC)("paddle enforce test.")); \ + } catch (paddle::platform::EnforceNotMet & error) { \ + caught_exception = true; \ + std::string ex_msg = error.what(); \ + EXPECT_TRUE(ex_msg.find(#EFUNC "Error: paddle enforce test.") != \ + std::string::npos); \ + } \ + EXPECT_TRUE(caught_exception); \ + } while (0) + +#define CHECK_PADDLE_ENFORCE_NOT_NULL(EFUNC) \ + do { \ + bool caught_exception = false; \ + try { \ + PADDLE_ENFORCE_NOT_NULL(nullptr, \ + (EFUNC)("paddle enforce not null test.")); \ + } catch (paddle::platform::EnforceNotMet & error) { \ + caught_exception = true; \ + std::string ex_msg = error.what(); \ + EXPECT_TRUE( \ + ex_msg.find(#EFUNC "Error: paddle enforce not null test.") != \ + std::string::npos); \ + } \ + EXPECT_TRUE(caught_exception); \ + } while (0) + +#define CHECK_PADDLE_ENFORCE_EQ(EFUNC) \ + do { \ + bool caught_exception = false; \ + try { \ + PADDLE_ENFORCE_EQ(1, 2, (EFUNC)("paddle enforce equal test.")); \ + } catch (paddle::platform::EnforceNotMet & error) { \ + caught_exception = true; \ + std::string ex_msg = error.what(); \ + EXPECT_TRUE(ex_msg.find(#EFUNC "Error: paddle enforce equal test.") != \ + std::string::npos); \ + } \ + EXPECT_TRUE(caught_exception); \ + } while (0) + +#define CHECK_ALL_PADDLE_EXCEPTION_MACRO(EFUNC) \ + do { \ + CHECK_PADDLE_THROW(EFUNC); \ + CHECK_PADDLE_ENFORCE(EFUNC); \ + CHECK_PADDLE_ENFORCE_NOT_NULL(EFUNC); \ + CHECK_PADDLE_ENFORCE_EQ(EFUNC); \ + } while (0) + +TEST(Errors, InvalidArgument) { + CHECK_ALL_PADDLE_EXCEPTION_MACRO(InvalidArgument); +} + +TEST(Errors, NotFound) { CHECK_ALL_PADDLE_EXCEPTION_MACRO(NotFound); } + +TEST(Errors, OutOfRange) { CHECK_ALL_PADDLE_EXCEPTION_MACRO(OutOfRange); } + +TEST(Errors, AlreadExists) { CHECK_ALL_PADDLE_EXCEPTION_MACRO(AlreadyExists); } + +TEST(Errors, ResourceExhausted) { + CHECK_ALL_PADDLE_EXCEPTION_MACRO(ResourceExhausted); +} + +TEST(Errors, PreconditionNotMet) { + CHECK_ALL_PADDLE_EXCEPTION_MACRO(PreconditionNotMet); +} + +TEST(Errors, PermissionDenied) { + CHECK_ALL_PADDLE_EXCEPTION_MACRO(PermissionDenied); +} + +TEST(Errors, ExecutionTimeout) { + CHECK_ALL_PADDLE_EXCEPTION_MACRO(ExecutionTimeout); +} + +TEST(Errors, Unimplemented) { CHECK_ALL_PADDLE_EXCEPTION_MACRO(Unimplemented); } + +TEST(Errors, Unavailable) { CHECK_ALL_PADDLE_EXCEPTION_MACRO(Unavailable); } + +TEST(Errors, Fatal) { CHECK_ALL_PADDLE_EXCEPTION_MACRO(Fatal); } + +TEST(Errors, External) { CHECK_ALL_PADDLE_EXCEPTION_MACRO(External); } -- GitLab