Skip to content
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

Add macro BOOST_GET to enrich the error information of boost :: get #24175

Merged

Conversation

chenwhql
Copy link
Contributor

@chenwhql chenwhql commented Apr 26, 2020

boost::get is not a completely safe interface, although it will not go wrong in most cases, but in extreme case, if may fail and directly throw a boost::bad_get exception without any stack information. This kind of problem is difficult to debug.

Related issues:

Now there are nearly 600 boost :: get in paddle without catch exception when used.

In this PR, I add new series macros BOOST_GET{***}, It encapsulates boost :: get as follows:

try {
  boost:get<T>(value);
} catch (boost::bad_get& bad_get) {
  PADDLE_THROW(InvalidArgument("error message"));
}

Use this macro instead of boost :: get, when something goes wrong, we can get richer error information . Including the error file, line number, expected value type and actual value type, this can help users to locate the cause of the error easily.

difficulty

The boost :: get has 4 types of return value, include T, const T, T&, const T&, so here need some tricks to cover these 4 scenarios with only one macro. With the help of @sneaxiy, under the gcc5.4 environment, we solved this problem with only one macro, see the commit 11bbbb2.

But CI now using gcc4.8, the writing above cannot be compiled under gcc4.8, this is a gcc4.8’s bug, gcc official recommends to use a higher version to solve. So I had to write three macros here to solve this problem, as follows:

- BOOST_GET (e.g. return int& or int*)
- BOOST_GET_CONST(e.g. return const int& or const int*)
- BOOST_GET_MUTABLE (e.g. return int or int*)

Examples:

Case 1: Place Get Error

1. original boost::get
  • this is a C++ exception, but using boost::get directly cannot throw C++ error info.

  • code piece

boost::get<platform::CPUPlace>(self); # self is CUDAPlace(0)
  • error result
Traceback (most recent call last):
  File "boost_get_err.py", line 6, in <module>
    new_place = fluid.CUDAPlace(p.gpu_device_id())
RuntimeError: boost::bad_get: failed value get using boost::get
2. new macro BOOST_GET
  • code piece
BOOST_GET_CONST(platform::CPUPlace, self); # self is CUDAPlace(0)
  • error result
Traceback (most recent call last):
  File "boost_get_err.py", line 6, in <module>
    new_place = fluid.CUDAPlace(p.gpu_device_id())
paddle.fluid.core_avx.EnforceNotMet: 

--------------------------------------------
C++ Call Stacks (More useful to developers):
--------------------------------------------
0   std::string paddle::platform::GetTraceBackString<std::string>(std::string&&, char const*, int)
1   paddle::platform::EnforceNotMet::EnforceNotMet(paddle::platform::ErrorSummary const&, char const*, int)
2   std::conditional<std::is_pointer<paddle::platform::Place>::value, paddle::platform::CPUPlace const*, paddle::platform::CPUPlace const&>::type paddle::platform::details::SafeBoostGetConst<paddle::platform::CPUPlace, paddle::platform::Place>(paddle::platform::Place const&, char const*, char const*, int)

----------------------
Error Message Summary:
----------------------
InvalidArgumentError: boost::get failed, cannot get value (self) by type paddle::platform::CPUPlace, its type is paddle::platform::CUDAPlace. at (/work/paddle/paddle/fluid/pybind/pybind.cc:1365)

Case 2: Attr Get Error

1. original boost::get
Traceback (most recent call last):
  File "boost_get_err2.py", line 12, in <module>
    conv = conv2d(data)
  File "/usr/local/lib/python3.5/dist-packages/paddle/fluid/dygraph/layers.py", line 460, in __call__
    outputs = self.forward(*inputs, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/paddle/fluid/dygraph/nn.py", line 234, in forward
    self._act)
  File "</usr/local/lib/python3.5/dist-packages/decorator.py:decorator-gen-22>", line 2, in _append_activation_in_dygraph
  File "/usr/local/lib/python3.5/dist-packages/paddle/fluid/wrapped_decorator.py", line 25, in __impl__
    return wrapped_func(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/paddle/fluid/framework.py", line 216, in __impl__
    return func(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/paddle/fluid/dygraph_utils.py", line 40, in _append_activation_in_dygraph
    return act_op(input, *attrs)
RuntimeError: boost::bad_get: failed value get using boost::get
2. new macro BOOST_GET
Traceback (most recent call last):
  File "boost_get_err2.py", line 12, in <module>
    conv = conv2d(data)
  File "/usr/local/lib/python3.5/dist-packages/paddle/fluid/dygraph/layers.py", line 460, in __call__
    outputs = self.forward(*inputs, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/paddle/fluid/dygraph/nn.py", line 234, in forward
    self._act)
  File "</usr/local/lib/python3.5/dist-packages/decorator.py:decorator-gen-22>", line 2, in _append_activation_in_dygraph
  File "/usr/local/lib/python3.5/dist-packages/paddle/fluid/wrapped_decorator.py", line 25, in __impl__
    return wrapped_func(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/paddle/fluid/framework.py", line 216, in __impl__
    return func(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/paddle/fluid/dygraph_utils.py", line 40, in _append_activation_in_dygraph
    return act_op(input, *attrs)
paddle.fluid.core_avx.EnforceNotMet: 

--------------------------------------------
C++ Call Stacks (More useful to developers):
--------------------------------------------
0   std::string paddle::platform::GetTraceBackString<std::string>(std::string&&, char const*, int)
1   paddle::platform::EnforceNotMet::EnforceNotMet(paddle::platform::ErrorSummary const&, char const*, int)
2   std::conditional<std::is_pointer<boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> >::value, bool const*, bool const&>::type paddle::platform::details::SafeBoostGetConst<bool, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> >(boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> const&, char const*, char const*, int)
3   paddle::operators::ActivationGradOpMaker<(paddle::operators::ActBwdOpFwdDeps)2, paddle::imperative::OpBase>::Apply(paddle::imperative::TracedGradOp*) const
4   paddle::framework::SingleGradOpMaker<paddle::imperative::OpBase>::operator()() const
5   std::_Function_handler<std::shared_ptr<paddle::imperative::GradOpNode> (std::string const&, std::map<std::string, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > >, std::less<std::string>, std::allocator<std::pair<std::string const, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > > > > > const&, std::map<std::string, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > >, std::less<std::string>, std::allocator<std::pair<std::string const, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > > > > > const&, std::unordered_map<std::string, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>, std::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> > > > const&), paddle::framework::details::OpInfoFiller<paddle::operators::ActivationGradOpMaker<(paddle::operators::ActBwdOpFwdDeps)2, paddle::imperative::OpBase>, (paddle::framework::details::OpInfoFillType)7>::operator()(char const*, paddle::framework::OpInfo*) const::{lambda(std::string const&, std::map<std::string, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > >, std::less<std::string>, std::allocator<std::pair<std::string const, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > > > > > const&, std::map<std::string, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > >, std::less<std::string>, std::allocator<std::pair<std::string const, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > > > > > const&, std::unordered_map<std::string, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>, std::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> > > > const&)#1}>::_M_invoke(std::_Any_data const&, std::string const&, std::map<std::string, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > >, std::less<std::string>, std::allocator<std::pair<std::string const, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > > > > > const&, std::map<std::string, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > >, std::less<std::string>, std::allocator<std::pair<std::string const, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > > > > > const&, std::unordered_map<std::string, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>, std::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> > > > const&)
6   paddle::imperative::CreateGradOpNode(paddle::framework::OperatorBase const&, std::map<std::string, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > >, std::less<std::string>, std::allocator<std::pair<std::string const, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > > > > > const&, std::map<std::string, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > >, std::less<std::string>, std::allocator<std::pair<std::string const, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > > > > > const&, std::unordered_map<std::string, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>, std::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> > > > const&, paddle::platform::Place const&)
7   paddle::imperative::Tracer::TraceOp(std::string const&, std::map<std::string, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > >, std::less<std::string>, std::allocator<std::pair<std::string const, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > > > > > const&, std::map<std::string, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > >, std::less<std::string>, std::allocator<std::pair<std::string const, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > > > > > const&, std::unordered_map<std::string, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>, std::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> > > >, paddle::platform::Place const&, bool)
8   paddle::imperative::Tracer::TraceOp(std::string const&, std::map<std::string, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > >, std::less<std::string>, std::allocator<std::pair<std::string const, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > > > > > const&, std::map<std::string, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > >, std::less<std::string>, std::allocator<std::pair<std::string const, std::vector<std::shared_ptr<paddle::imperative::VarBase>, std::allocator<std::shared_ptr<paddle::imperative::VarBase> > > > > > const&, std::unordered_map<std::string, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>, std::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, boost::variant<boost::blank, int, float, std::string, std::vector<int, std::allocator<int> >, std::vector<float, std::allocator<float> >, std::vector<std::string, std::allocator<std::string> >, bool, std::vector<bool, std::allocator<bool> >, paddle::framework::BlockDesc*, long, std::vector<paddle::framework::BlockDesc*, std::allocator<paddle::framework::BlockDesc*> >, std::vector<long, std::allocator<long> >, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_> > > >)

----------------------
Error Message Summary:
----------------------
InvalidArgumentError: boost::get failed, cannot get value (op->GetAttr("use_mkldnn")) by type bool, its type is std::string. at (/work/paddle/paddle/fluid/operators/activation_op.cc:76)

CI check

In order to avoid the direct use of boost :: get, I added a new rule to CI to limit the use of boost :: get. If found, it will remind developer to use the macro BOOST_GET(_**) series macros.

"(%s) by type %s, its type is %s.", \
#__VALUE, paddle::platform::demangle(typeid(__TYPE).name()), \
paddle::platform::demangle(__VALUE.type().name()))); \
} \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个boost::get 除了 bad_get 还有其他情况的异常么, 需要不要 catch(...) 捕获其他的异常

Copy link
Contributor Author

@chenwhql chenwhql Apr 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

仅会抛出bad_get异常
image

看了下源码:https://www.boost.org/doc/libs/1_58_0/boost/variant/get.hpp

里面如果get失败,一律抛出bad_get

@luotao1
Copy link
Contributor

luotao1 commented Apr 27, 2020

可以试下在实际场景中,修改前后的效果么?比如 #23028 有复现代码,也有修好的PR #23047

@chenwhql
Copy link
Contributor Author

可以试下在实际场景中,修改前后的效果么?比如 #23028 有复现代码,也有修好的PR #23047

好的,感谢提醒

@chenwhql chenwhql changed the title Add macro BOOST_GET_SAFELY to enrich the error information of boost :: get Add macro BOOST_GET to enrich the error information of boost :: get May 9, 2020
Copy link
Contributor

@luotao1 luotao1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!!

@chenwhql
Copy link
Contributor Author

chenwhql commented May 9, 2020

可以试下在实际场景中,修改前后的效果么?比如 #23028 有复现代码,也有修好的PR #23047

已更新到PR的描述中,case2对应这个例子

@chenwhql chenwhql merged commit aa0f254 into PaddlePaddle:develop May 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants