提交 b9163350 编写于 作者: C Chen Weihang 提交者: Tao Luo

Paddle error message stack shaping and optimization (#19895)

* shape and optimize paddle error message stack, test=develop

* limit exception type & add unittest, test=develop

* fix multi-platform problem, test=develop

* fix related unnitest failed, test=develop

* add doc & fix unittest errors, test=develop

* fix function name error, test=develop

* update tensor test exception msg compare, test=develop

* remove unittest on win32, the dir format is different, test=develop

* remove useless package, test=develop

* add paddle enforce handler unittest, test=develop

* add exception checkout, test=develop

* fix coverage failed, test=develop

* fix op registry test failed, test=develop

* refactor whole pr, test=develop

* remove test in CMakelist, test=develop

* fix coverage, test=develop
上级 c8e12587
...@@ -29,17 +29,35 @@ void InsertCallStackInfo(const std::string &type, const AttributeMap &attrs, ...@@ -29,17 +29,35 @@ void InsertCallStackInfo(const std::string &type, const AttributeMap &attrs,
auto &callstack = boost::get<std::vector<std::string>>( auto &callstack = boost::get<std::vector<std::string>>(
attrs.at(OpProtoAndCheckerMaker::OpCreationCallstackAttrName())); attrs.at(OpProtoAndCheckerMaker::OpCreationCallstackAttrName()));
if (callstack.empty()) {
return;
}
std::ostringstream sout; std::ostringstream sout;
sout << "Invoke operator " << type << " error.\n"; std::ostringstream sout_py_trace;
sout << "Python Call stacks: \n"; // Step 1. Construct python call stack string
if (!callstack.empty()) {
sout_py_trace << "\n------------------------------------------\n";
sout_py_trace << "Python Call Stacks (More useful to users):";
sout_py_trace << "\n------------------------------------------\n";
for (auto &line : callstack) { for (auto &line : callstack) {
sout << line; sout_py_trace << line;
}
} }
sout << "C++ Call stacks: \n"; // Step 2. Insert python traceback into err_str_
std::size_t found = exception->err_str_.rfind("PaddleCheckError:");
if (found != std::string::npos) {
exception->err_str_.insert(found, sout_py_trace.str());
exception->err_str_.insert(found + sout_py_trace.str().length(),
"\n----------------------\nError Message "
"Summary:\n----------------------\n");
} else {
exception->err_str_.append(sout_py_trace.str());
}
// Step 3. Construct final call stack
sout << "\n\n--------------------------------------------\n";
sout << "C++ Call Stacks (More useful to developers):";
sout << "\n--------------------------------------------\n";
sout << exception->err_str_; sout << exception->err_str_;
if (!callstack.empty()) {
sout << " [operator < " << type << " > error]";
}
exception->err_str_ = sout.str(); exception->err_str_ = sout.str();
} }
......
...@@ -118,10 +118,8 @@ TEST(OpRegistry, IllegalAttr) { ...@@ -118,10 +118,8 @@ TEST(OpRegistry, IllegalAttr) {
} catch (paddle::platform::EnforceNotMet err) { } catch (paddle::platform::EnforceNotMet err) {
caught = true; caught = true;
std::string msg = "larger_than check fail"; std::string msg = "larger_than check fail";
const char* err_msg = err.what(); std::string err_msg = err.what();
for (size_t i = 0; i < msg.length(); ++i) { ASSERT_TRUE(err_msg.find(msg) != std::string::npos);
ASSERT_EQ(err_msg[i], msg[i]);
}
} }
ASSERT_TRUE(caught); ASSERT_TRUE(caught);
} }
...@@ -154,10 +152,8 @@ TEST(OpRegistry, CustomChecker) { ...@@ -154,10 +152,8 @@ TEST(OpRegistry, CustomChecker) {
} catch (paddle::platform::EnforceNotMet err) { } catch (paddle::platform::EnforceNotMet err) {
caught = true; caught = true;
std::string msg = "Attribute 'test_attr' is required!"; std::string msg = "Attribute 'test_attr' is required!";
const char* err_msg = err.what(); std::string err_msg = err.what();
for (size_t i = 0; i < msg.length(); ++i) { ASSERT_TRUE(err_msg.find(msg) != std::string::npos);
ASSERT_EQ(err_msg[i], msg[i]);
}
} }
ASSERT_TRUE(caught); ASSERT_TRUE(caught);
...@@ -172,10 +168,8 @@ TEST(OpRegistry, CustomChecker) { ...@@ -172,10 +168,8 @@ TEST(OpRegistry, CustomChecker) {
} catch (paddle::platform::EnforceNotMet err) { } catch (paddle::platform::EnforceNotMet err) {
caught = true; caught = true;
std::string msg = "'test_attr' must be even!"; std::string msg = "'test_attr' must be even!";
const char* err_msg = err.what(); std::string err_msg = err.what();
for (size_t i = 0; i < msg.length(); ++i) { ASSERT_TRUE(err_msg.find(msg) != std::string::npos);
ASSERT_EQ(err_msg[i], msg[i]);
}
} }
ASSERT_TRUE(caught); ASSERT_TRUE(caught);
......
...@@ -38,13 +38,11 @@ TEST(Tensor, DataAssert) { ...@@ -38,13 +38,11 @@ TEST(Tensor, DataAssert) {
src_tensor.data<double>(); src_tensor.data<double>();
} catch (platform::EnforceNotMet err) { } catch (platform::EnforceNotMet err) {
caught = true; caught = true;
std::string msg = std::string ex_msg = err.what();
"holder_ should not be null\nTensor holds no memory. Call " EXPECT_TRUE(ex_msg.find("holder_ should not be null\nTensor holds no "
"Tensor::mutable_data first."; "memory. Call "
const char* what = err.what(); "Tensor::mutable_data first.") !=
for (size_t i = 0; i < msg.length(); ++i) { std::string::npos);
ASSERT_EQ(what[i], msg[i]);
}
} }
ASSERT_TRUE(caught); ASSERT_TRUE(caught);
} }
...@@ -155,13 +153,11 @@ TEST(Tensor, ShareDataWith) { ...@@ -155,13 +153,11 @@ TEST(Tensor, ShareDataWith) {
dst_tensor.ShareDataWith(src_tensor); dst_tensor.ShareDataWith(src_tensor);
} catch (paddle::platform::EnforceNotMet err) { } catch (paddle::platform::EnforceNotMet err) {
caught = true; caught = true;
std::string msg = std::string ex_msg = err.what();
"holder_ should not be null\nTensor holds no memory. Call " EXPECT_TRUE(ex_msg.find("holder_ should not be null\nTensor holds no "
"Tensor::mutable_data first."; "memory. Call "
const char* what = err.what(); "Tensor::mutable_data first.") !=
for (size_t i = 0; i < msg.length(); ++i) { std::string::npos);
ASSERT_EQ(what[i], msg[i]);
}
} }
ASSERT_TRUE(caught); ASSERT_TRUE(caught);
......
...@@ -52,6 +52,8 @@ limitations under the License. */ ...@@ -52,6 +52,8 @@ limitations under the License. */
#endif // __APPLE__ #endif // __APPLE__
#endif // PADDLE_WITH_CUDA #endif // PADDLE_WITH_CUDA
#define WITH_SIMPLE_TRACEBACK
namespace paddle { namespace paddle {
namespace platform { namespace platform {
...@@ -72,18 +74,22 @@ inline std::string GetTraceBackString(StrType&& what, const char* file, ...@@ -72,18 +74,22 @@ inline std::string GetTraceBackString(StrType&& what, const char* file,
static constexpr int TRACE_STACK_LIMIT = 100; static constexpr int TRACE_STACK_LIMIT = 100;
std::ostringstream sout; std::ostringstream sout;
sout << string::Sprintf("%s at [%s:%d]", std::forward<StrType>(what), file,
line)
<< std::endl;
sout << "PaddlePaddle Call Stacks: " << std::endl;
#if !defined(_WIN32) #if !defined(_WIN32)
void* call_stack[TRACE_STACK_LIMIT]; void* call_stack[TRACE_STACK_LIMIT];
auto size = backtrace(call_stack, TRACE_STACK_LIMIT); auto size = backtrace(call_stack, TRACE_STACK_LIMIT);
auto symbols = backtrace_symbols(call_stack, size); auto symbols = backtrace_symbols(call_stack, size);
Dl_info info; Dl_info info;
int idx = 0;
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
if (dladdr(call_stack[i], &info) && info.dli_sname) { if (dladdr(call_stack[i], &info) && info.dli_sname) {
auto demangled = demangle(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<char*>(call_stack[i]) - auto addr_offset = static_cast<char*>(call_stack[i]) -
static_cast<char*>(info.dli_saddr); static_cast<char*>(info.dli_saddr);
sout << string::Sprintf("%-3d %*0p %s + %zd\n", i, 2 + sizeof(void*) * 2, sout << string::Sprintf("%-3d %*0p %s + %zd\n", i, 2 + sizeof(void*) * 2,
...@@ -91,12 +97,16 @@ inline std::string GetTraceBackString(StrType&& what, const char* file, ...@@ -91,12 +97,16 @@ inline std::string GetTraceBackString(StrType&& what, const char* file,
} else { } else {
sout << string::Sprintf("%-3d %*0p\n", i, 2 + sizeof(void*) * 2, sout << string::Sprintf("%-3d %*0p\n", i, 2 + sizeof(void*) * 2,
call_stack[i]); call_stack[i]);
#endif
} }
} }
free(symbols); free(symbols);
#else #else
sout << "Windows not support stack backtrace yet."; sout << "Windows not support stack backtrace yet.";
#endif #endif
sout << string::Sprintf("PaddleCheckError: %s at [%s:%d]",
std::forward<StrType>(what), file, line)
<< std::endl;
return sout.str(); return sout.str();
} }
...@@ -338,7 +348,7 @@ DEFINE_CUDA_STATUS_TYPE(ncclResult_t, ncclSuccess); ...@@ -338,7 +348,7 @@ DEFINE_CUDA_STATUS_TYPE(ncclResult_t, ncclSuccess);
* PADDLE_ENFORCE_EQ(a, b); * PADDLE_ENFORCE_EQ(a, b);
* *
* will raise an expression described as follows: * will raise an expression described as follows:
* "Enforce failed. Expected input a == b, but received a(1) != b(2)." * "Expected input a == b, but received a(1) != b(2)."
* with detailed stack information. * with detailed stack information.
* *
* extra messages is also supported, for example: * extra messages is also supported, for example:
...@@ -445,8 +455,8 @@ struct BinaryCompareMessageConverter<false> { ...@@ -445,8 +455,8 @@ struct BinaryCompareMessageConverter<false> {
constexpr bool __kCanToString__ = \ constexpr bool __kCanToString__ = \
::paddle::platform::details::CanToString<__TYPE1__>::kValue && \ ::paddle::platform::details::CanToString<__TYPE1__>::kValue && \
::paddle::platform::details::CanToString<__TYPE2__>::kValue; \ ::paddle::platform::details::CanToString<__TYPE2__>::kValue; \
PADDLE_THROW("Enforce failed. Expected %s " #__CMP \ PADDLE_THROW("Expected %s " #__CMP " %s, but received %s " #__INV_CMP \
" %s, but received %s " #__INV_CMP " %s.\n%s", \ " %s.\n%s", \
#__VAL1, #__VAL2, \ #__VAL1, #__VAL2, \
::paddle::platform::details::BinaryCompareMessageConverter< \ ::paddle::platform::details::BinaryCompareMessageConverter< \
__kCanToString__>::Convert(#__VAL1, __val1), \ __kCanToString__>::Convert(#__VAL1, __val1), \
...@@ -488,8 +498,8 @@ struct BinaryCompareMessageConverter<false> { ...@@ -488,8 +498,8 @@ struct BinaryCompareMessageConverter<false> {
bool __is_not_error = (static_cast<__COMMON_TYPE1__>(__val1))__CMP( \ bool __is_not_error = (static_cast<__COMMON_TYPE1__>(__val1))__CMP( \
static_cast<__COMMON_TYPE2__>(__val2)); \ static_cast<__COMMON_TYPE2__>(__val2)); \
if (UNLIKELY(!__is_not_error)) { \ if (UNLIKELY(!__is_not_error)) { \
PADDLE_THROW("Enforce failed. Expected %s " #__CMP \ PADDLE_THROW("Expected %s " #__CMP " %s, but received %s:%s " #__INV_CMP \
" %s, but received %s:%s " #__INV_CMP " %s:%s.\n%s", \ " %s:%s.\n%s", \
#__VAL1, #__VAL2, #__VAL1, \ #__VAL1, #__VAL2, #__VAL1, \
::paddle::string::to_string(__val1), #__VAL2, \ ::paddle::string::to_string(__val1), #__VAL2, \
::paddle::string::to_string(__val2), \ ::paddle::string::to_string(__val2), \
......
...@@ -17,10 +17,6 @@ limitations under the License. */ ...@@ -17,10 +17,6 @@ limitations under the License. */
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "paddle/fluid/platform/enforce.h" #include "paddle/fluid/platform/enforce.h"
#include "paddle/fluid/string/piece.h"
using StringPiece = paddle::string::Piece;
using paddle::string::HasPrefix;
TEST(ENFORCE, OK) { TEST(ENFORCE, OK) {
PADDLE_ENFORCE(true, "Enforce is ok %d now %f", 123, 0.345); PADDLE_ENFORCE(true, "Enforce is ok %d now %f", 123, 0.345);
...@@ -35,8 +31,9 @@ TEST(ENFORCE, FAILED) { ...@@ -35,8 +31,9 @@ TEST(ENFORCE, FAILED) {
PADDLE_ENFORCE(false, "Enforce is not ok %d at all", 123); PADDLE_ENFORCE(false, "Enforce is not ok %d at all", 123);
} catch (paddle::platform::EnforceNotMet error) { } catch (paddle::platform::EnforceNotMet error) {
caught_exception = true; caught_exception = true;
EXPECT_TRUE( std::string ex_msg = error.what();
HasPrefix(StringPiece(error.what()), "Enforce is not ok 123 at all")); EXPECT_TRUE(ex_msg.find("Enforce is not ok 123 at all") !=
std::string::npos);
} }
EXPECT_TRUE(caught_exception); EXPECT_TRUE(caught_exception);
...@@ -45,8 +42,8 @@ TEST(ENFORCE, FAILED) { ...@@ -45,8 +42,8 @@ TEST(ENFORCE, FAILED) {
PADDLE_ENFORCE(false, "Enforce is not ok at all"); PADDLE_ENFORCE(false, "Enforce is not ok at all");
} catch (paddle::platform::EnforceNotMet error) { } catch (paddle::platform::EnforceNotMet error) {
caught_exception = true; caught_exception = true;
EXPECT_TRUE( std::string ex_msg = error.what();
HasPrefix(StringPiece(error.what()), "Enforce is not ok at all")); EXPECT_TRUE(ex_msg.find("Enforce is not ok at all") != std::string::npos);
} }
EXPECT_TRUE(caught_exception); EXPECT_TRUE(caught_exception);
...@@ -75,9 +72,9 @@ TEST(ENFORCE_EQ, NO_EXTRA_MSG_FAIL) { ...@@ -75,9 +72,9 @@ TEST(ENFORCE_EQ, NO_EXTRA_MSG_FAIL) {
PADDLE_ENFORCE_EQ(a, 1 + 3); PADDLE_ENFORCE_EQ(a, 1 + 3);
} catch (paddle::platform::EnforceNotMet error) { } catch (paddle::platform::EnforceNotMet error) {
caught_exception = true; caught_exception = true;
HasPrefix( std::string ex_msg = error.what();
StringPiece(error.what()), EXPECT_TRUE(ex_msg.find("Expected a == 1 + 3, but received a:2 != 1 "
"Enforce failed. Expected a == 1 + 3, but received a:2 != 1 + 3:4."); "+ 3:4.") != std::string::npos);
} }
EXPECT_TRUE(caught_exception); EXPECT_TRUE(caught_exception);
} }
...@@ -89,9 +86,9 @@ TEST(ENFORCE_EQ, EXTRA_MSG_FAIL) { ...@@ -89,9 +86,9 @@ TEST(ENFORCE_EQ, EXTRA_MSG_FAIL) {
PADDLE_ENFORCE_EQ(a, 1 + 3, "%s size not match", "their"); PADDLE_ENFORCE_EQ(a, 1 + 3, "%s size not match", "their");
} catch (paddle::platform::EnforceNotMet error) { } catch (paddle::platform::EnforceNotMet error) {
caught_exception = true; caught_exception = true;
HasPrefix(StringPiece(error.what()), std::string ex_msg = error.what();
"Enforce failed. Expected a == 1 + 3, but received a:2 != 1 + " EXPECT_TRUE(ex_msg.find("Expected a == 1 + 3, but received a:2 != 1 + "
"3:4.\ntheir size not match"); "3:4.\ntheir size not match") != std::string::npos);
} }
EXPECT_TRUE(caught_exception); EXPECT_TRUE(caught_exception);
} }
...@@ -108,10 +105,9 @@ TEST(ENFORCE_NE, FAIL) { ...@@ -108,10 +105,9 @@ TEST(ENFORCE_NE, FAIL) {
PADDLE_ENFORCE_NE(1.0, 1UL); PADDLE_ENFORCE_NE(1.0, 1UL);
} catch (paddle::platform::EnforceNotMet error) { } catch (paddle::platform::EnforceNotMet error) {
caught_exception = true; caught_exception = true;
EXPECT_TRUE(HasPrefix( std::string ex_msg = error.what();
StringPiece(error.what()), EXPECT_TRUE(ex_msg.find("Expected 1.0 != 1UL, but "
"Enforce failed. Expected 1.0 != 1UL, but received 1.0:1 == 1UL:1.")) "received 1.0:1 == 1UL:1.") != std::string::npos);
<< error.what() << " does not have expected prefix";
} }
EXPECT_TRUE(caught_exception); EXPECT_TRUE(caught_exception);
} }
...@@ -123,9 +119,9 @@ TEST(ENFORCE_GT, FAIL) { ...@@ -123,9 +119,9 @@ TEST(ENFORCE_GT, FAIL) {
PADDLE_ENFORCE_GT(1, 2); PADDLE_ENFORCE_GT(1, 2);
} catch (paddle::platform::EnforceNotMet error) { } catch (paddle::platform::EnforceNotMet error) {
caught_exception = true; caught_exception = true;
EXPECT_TRUE( std::string ex_msg = error.what();
HasPrefix(StringPiece(error.what()), EXPECT_TRUE(ex_msg.find("Expected 1 > 2, but received 1:1 <= 2:2.") !=
"Enforce failed. Expected 1 > 2, but received 1:1 <= 2:2.")); std::string::npos);
} }
EXPECT_TRUE(caught_exception); EXPECT_TRUE(caught_exception);
} }
...@@ -141,9 +137,9 @@ TEST(ENFORCE_GE, FAIL) { ...@@ -141,9 +137,9 @@ TEST(ENFORCE_GE, FAIL) {
PADDLE_ENFORCE_GE(1, 2); PADDLE_ENFORCE_GE(1, 2);
} catch (paddle::platform::EnforceNotMet error) { } catch (paddle::platform::EnforceNotMet error) {
caught_exception = true; caught_exception = true;
EXPECT_TRUE( std::string ex_msg = error.what();
HasPrefix(StringPiece(error.what()), EXPECT_TRUE(ex_msg.find("Expected 1 >= 2, but received 1:1 < 2:2.") !=
"Enforce failed. Expected 1 >= 2, but received 1:1 < 2:2.")); std::string::npos);
} }
EXPECT_TRUE(caught_exception); EXPECT_TRUE(caught_exception);
} }
...@@ -161,9 +157,9 @@ TEST(ENFORCE_LE, FAIL) { ...@@ -161,9 +157,9 @@ TEST(ENFORCE_LE, FAIL) {
PADDLE_ENFORCE_GT(1, 2); PADDLE_ENFORCE_GT(1, 2);
} catch (paddle::platform::EnforceNotMet error) { } catch (paddle::platform::EnforceNotMet error) {
caught_exception = true; caught_exception = true;
EXPECT_TRUE( std::string ex_msg = error.what();
HasPrefix(StringPiece(error.what()), EXPECT_TRUE(ex_msg.find("Expected 1 > 2, but received 1:1 <= 2:2.") !=
"Enforce failed. Expected 1 > 2, but received 1:1 <= 2:2.")); std::string::npos);
} }
EXPECT_TRUE(caught_exception); EXPECT_TRUE(caught_exception);
} }
...@@ -179,9 +175,10 @@ TEST(ENFORCE_LT, FAIL) { ...@@ -179,9 +175,10 @@ TEST(ENFORCE_LT, FAIL) {
PADDLE_ENFORCE_LT(1UL, 0.12); PADDLE_ENFORCE_LT(1UL, 0.12);
} catch (paddle::platform::EnforceNotMet error) { } catch (paddle::platform::EnforceNotMet error) {
caught_exception = true; caught_exception = true;
EXPECT_TRUE(HasPrefix(StringPiece(error.what()), std::string ex_msg = error.what();
"Enforce failed. Expected 1UL < 0.12, but " EXPECT_TRUE(ex_msg.find("Expected 1UL < 0.12, but "
"received 1UL:1 >= 0.12:0.12.")); "received 1UL:1 >= 0.12:0.12.") !=
std::string::npos);
} }
EXPECT_TRUE(caught_exception); EXPECT_TRUE(caught_exception);
} }
...@@ -198,7 +195,8 @@ TEST(ENFORCE_NOT_NULL, FAIL) { ...@@ -198,7 +195,8 @@ TEST(ENFORCE_NOT_NULL, FAIL) {
PADDLE_ENFORCE_NOT_NULL(a); PADDLE_ENFORCE_NOT_NULL(a);
} catch (paddle::platform::EnforceNotMet error) { } catch (paddle::platform::EnforceNotMet error) {
caught_exception = true; caught_exception = true;
EXPECT_TRUE(HasPrefix(StringPiece(error.what()), "a should not be null")); std::string ex_msg = error.what();
EXPECT_TRUE(ex_msg.find("a should not be null") != std::string::npos);
} }
EXPECT_TRUE(caught_exception); EXPECT_TRUE(caught_exception);
} }
...@@ -251,7 +249,8 @@ TEST(EOF_EXCEPTION, THROW_EOF) { ...@@ -251,7 +249,8 @@ TEST(EOF_EXCEPTION, THROW_EOF) {
PADDLE_THROW_EOF(); PADDLE_THROW_EOF();
} catch (paddle::platform::EOFException error) { } catch (paddle::platform::EOFException error) {
caught_eof = true; caught_eof = true;
EXPECT_TRUE(HasPrefix(StringPiece(error.what()), "There is no next data.")); std::string ex_msg = error.what();
EXPECT_TRUE(ex_msg.find("There is no next data.") != std::string::npos);
} }
EXPECT_TRUE(caught_eof); EXPECT_TRUE(caught_eof);
} }
......
...@@ -712,7 +712,8 @@ class Executor(object): ...@@ -712,7 +712,8 @@ class Executor(object):
use_program_cache=use_program_cache) use_program_cache=use_program_cache)
except Exception as e: except Exception as e:
if not isinstance(e, core.EOFException): if not isinstance(e, core.EOFException):
print("!!!A non-EOF exception is thrown.") warnings.warn(
"The following exception is not an EOF exception.")
six.reraise(*sys.exc_info()) six.reraise(*sys.exc_info())
def _run_impl(self, program, feed, fetch_list, feed_var_name, def _run_impl(self, program, feed, fetch_list, feed_var_name,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册