-
-
Notifications
You must be signed in to change notification settings - Fork 193
adds macro for making bounds checks a no-op #2423
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
Conversation
If we will be defining a separate macro, which I think is the right call here, might as well give it a more descriptive name? Most of Stan users are not C++ developers and NDEBUG does not mean much to them. Maybe STAN_NO_RANGE_CHECKS or just NO_RANGE_CHECKS. |
As for testing, I think easiest is a Github Action job that runs a list of tests. These standalone short tests are perfect for GHA as its free. |
…attributes to top of meta.hpp
…attributes to top of meta.hpp
…4.1 (tags/RELEASE_600/final)
I have to think about that. Messing with macro's is certainly an advanced user function. I use
Nice! Yeah that makes total sense I'll add the tests and make a gh action |
…4.1 (tags/RELEASE_600/final)
Jenkins Console Log Machine informationProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010CPU: G++: Clang: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment.
stan/math/prim/err/check_bounded.hpp
Outdated
@@ -74,6 +74,7 @@ struct bounded<T_y, T_low, T_high, true> { | |||
template <typename T_y, typename T_low, typename T_high> | |||
inline void check_bounded(const char* function, const char* name, const T_y& y, | |||
const T_low& low, const T_high& high) { | |||
STAN_NO_RANGE_AND_SIZE_CHECK; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used to check that real values are in a certain range (like probabilities are bounded [0, 1]) as well as indexes in range.
It looks like this pull is only turning off range checks, but why not value checks too? I think you'd turn them off in similar situations for the same reasons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Value checks? Like what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not NaN, not infinite, positive definite, valid unit vector, valid simplex -- this sort of thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's a different story which one should be able to turn off separately (if at all), I think. Something like STAN_FAST_MATH (a synonym for "not safe math, do it fast")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we also not going to remove size checks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but what is wrong with two macros which do a more tailored thing themselves
I don't see why one would be useful without another -- unsafe is unsafe and it's just hard to remember multiple things.
not going to remove size checks?
Optimizing out size checks makes sense with this macro I think. check_bounded
is probly the only one that needs to go if we're not using values.
If we're going for STAN_NDEBUG in the future, does it make sense to just start with that? Or STAN_UNSAFE or STAN_NO_DEBUG since Rok pointed out NDEBUG probably doesn't mean much to people? Then in the future if we decide to split that into multiple things we can and the overall super-unsafe easy-mode flag is still there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd like to leave the size checks for another time because it changes the exceptions that are returned for some functions like check_symmetric()
etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going for STAN_NDEBUG in the future, does it make sense to just start with that? Or STAN_UNSAFE or STAN_NO_DEBUG since Rok pointed out NDEBUG probably doesn't mean much to people? Then in the future if we decide to split that into multiple things we can and the overall super-unsafe easy-mode flag is still there.
Let's do this in a separate PR once we sort out what that means. Right now I like just having an option to turn off the range checks, then in another PR or an issue we can sort out what we want turned on and off
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good
You should probably rename that to |
#ifdef __has_attribute | ||
#if __has_attribute(noinline) && __has_attribute(cold) | ||
/** | ||
* Functions tagged with this attribute are not inlined and moved | ||
* to a cold branch to tell the CPU to not attempt to pre-fetch | ||
* the associated function. | ||
*/ | ||
#define STAN_COLD_PATH __attribute__((noinline, cold)) | ||
#else | ||
#define STAN_COLD_PATH | ||
#endif | ||
#else | ||
#define STAN_COLD_PATH | ||
#endif | ||
#else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes seem unrelated to what this PR is doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a little bit of a fix, if someone is using either not gcc or clang then we are not guaranteed __has_attribute
is defined. So to compile on those we want to make sure that macro is defined so that we can then check whether the compiler has the attributes noinline
and cold
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, but you could simplify this into:
#ifdef __has_attribute | |
#if __has_attribute(noinline) && __has_attribute(cold) | |
/** | |
* Functions tagged with this attribute are not inlined and moved | |
* to a cold branch to tell the CPU to not attempt to pre-fetch | |
* the associated function. | |
*/ | |
#define STAN_COLD_PATH __attribute__((noinline, cold)) | |
#else | |
#define STAN_COLD_PATH | |
#endif | |
#else | |
#define STAN_COLD_PATH | |
#endif | |
#else | |
#ifdef __has_attribute | |
#if __has_attribute(noinline) && __has_attribute(cold) | |
/** | |
* Functions tagged with this attribute are not inlined and moved | |
* to a cold branch to tell the CPU to not attempt to pre-fetch | |
* the associated function. | |
*/ | |
#define STAN_COLD_PATH __attribute__((noinline, cold)) | |
#endif | |
#endif | |
#ifndef STAN_COLD_PATH | |
#define STAN_COLD_PATH | |
#endif |
…4.1 (tags/RELEASE_600/final)
Jenkins Console Log Machine informationProductName: Mac OS X ProductVersion: 10.11.6 BuildVersion: 15G22010CPU: G++: Clang: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all looks good to me. Since we've been doing this pull by committee, I'll leave it to someone else to also look over and click the merge button.
@@ -2,13 +2,48 @@ | |||
#define STAN_MATH_PRIM_META_COMPILER_ATTRIBUTES_HPP | |||
|
|||
#ifdef __GNUC__ | |||
#ifndef likely |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it that old gccs didn't have likely and new ones do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another package could have it
Summary
From issue #2420 the default in Stan now is to always perform bounds checks for single index access. This has a noticeable slowdown for users. This PR uses a
STAN_NO_RANGE_CHECKS
macro which if defined then makes the range and bounds checks into no-ops. It does this by defining another macroSTAN_NO_RANGE_CHECK_RETURN
which is equal toreturn;
ifSTAN_NO_RANGE_CHECKS
is defined.At first I thought we could just use
NDEBUG
but it seems that is specifically to turn on and off asserts such aseigen_assert()
or the standardassert()
. Our bounds checks are sort of an assert, though I think it's safer just to have a new macro.It's possible for the user to specify this in the makefile, or we could have an option for the compiler like
-fno-debug
which at the top of the stan model would defineSTAN_NO_RANGE_CHECKS
Tests
tbh I'm not really sure how to test this since it changes behavior in the preprocessor. We could have a separate jenkins node that does the checks just for these errors? Since they are all no-ops it would be pretty fast
Side Effects
Yes this whole PR is a side effect to turn off bounds checks.
Release notes
Adds
STAN_NO_RANGE_CHECKS
macro which if defined turns off bounds and range checksChecklist
Math issue [FR] No bounds checks when NDEBUG flag is set #2420
Copyright holder: Steve Bronder
The copyright holder is typically you or your assignee, such as a university or company. By submitting this pull request, the copyright holder is agreeing to the license the submitted work under the following licenses:
- Code: BSD 3-clause (https://opensource.org/licenses/BSD-3-Clause)
- Documentation: CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/)
the basic tests are passing
./runTests.py test/unit
)make test-headers
)make test-math-dependencies
)make doxygen
)make cpplint
)the code is written in idiomatic C++ and changes are documented in the doxygen
the new changes are tested