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
[WIP] Concepts refactor #8
base: main
Are you sure you want to change the base?
Conversation
Ok, it's time to get some eyes on this, the current version appears to work portably and improves the camp test compile time for ICC from 40 seconds to 11 on rztopaz. I still want to get something in as a helper to use the new concepts as constraints on functions and types that let people get them as actual concepts when in that mode, but take a look, maybe see if I'm crazy... @davidbeckingsale, @willkill, @ajkunen Should be overall a compile time improvement for everything that uses raja, especially that uses kernel, somewhere between 10% and 4x depending on exactly what the benchmark does is what I've seen (4x for crazy tuple test of doom). @willkill: hope you don't mind a ping, it touches a bunch of your concept code and if you have the cycles I'd love it if you'd glance over it. |
@trws is there a RAJA branch that compiles with this branch of camp? I tried master and develop and it died immediately. |
Not yet, RAJA will need some work to run with this cleanly, it shouldn’t be much but I’ll do it shortly.
…Sent from my iPhone
On Nov 19, 2019, at 11:45 AM, Rich Hornung <notifications@github.com> wrote:
@trws<https://github.com/trws> is there a RAJA branch that compiles with this branch of camp? I tried master and develop and it died immediately.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#8?email_source=notifications&email_token=AAFBFNIAMVQA6SHXD5G32M3QUQX2ZA5CNFSM4JKVUR52YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEEPI6UA#issuecomment-555650896>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AAFBFNOCV5J5TKHZTVQSUK3QUQX2ZANCNFSM4JKVUR5Q>.
|
Thanks @trws. Let me know when it's ready. I have a few code teams willing to try it out and report their findings to us. |
Commenting so that I get notified when this gets merged. |
This is the beginning of a relatively large concepts/type-traits refactor that is going to come in over the next while. First is factoring out convertible_to so it looks/works more like the standard library version so I can start converting detector into a more user-friendly version we can actually expose. This is a bug for GEOSX and others, and should also make our type_traits more robust once it's all in.
With the is_convertible changes, this is the basis for the whole refactor setup. Concepts will all be defined against the new detector, as will type traits, using the new idiom through the macro so if we need to do this again it wont have to touch them all.
tests integrated, and some concepts ported, more to go
concepts are working again, and actually have tests in detect.cpp, there are new macros for defining detectors, requirements (helper for detectors), concepts, and all-in-one doing a concept and associated traits. It's possible there are breaking changes in here if anyone external is relying on the concepts, but since many of them were broken I'm hoping this will be a net benefit.
Remove unnecessary stl headers, factor out their usage, also use builtins for typelist lookups when available.
In C++17 mode use built-in fold expressions, in 14 use a simpler type. When in 14 mode this buys up to 30% improvement, in 17 mode it's almost four *times* faster to instantiate tuples now. Should help with RAJA compile times where 17 is available.
Turn tuple_storage into an aggregate when possible, turns out this is not possible on nvcc right now, but elsewhere it's a nice little 5-20% bump.
26f26f3
to
51e66d9
Compare
@trws -- I never got the ping on this because my GitHub name has 07 at the end 🤦 What work needs done to get the revised detector idiom working? I originally was applying the |
🤦♂️ ugh, sorry, bonehead mistake on my part. It's working in here as is (or was, hopefully still is) the main rework is to deal with two issues, an EDG issue that only crops up with some nasty template type dependent cases, and the fact we were accidentally using binary results in some tests that weren't subtitution failures so they didn't trigger sfinae. Basically this is the meat of the EDG workaround: #define CAMP_DEF_DETECTOR(name, params, ...) \
template <CAMP_UNQUOTE params, typename __Res = __VA_ARGS__> \
using name = __Res
//usage
CAMP_DEF_DETECTOR(has_begin, (typename T), decltype(val<T>().begin()));
... enable_if<is_detected<has_begin, T>::value> ...; The strange, but useful, thing here is that all the compilers that bug out when doing indirection through a templated type dependent on a type member and all kinds of funny cases like that get it right when the detector or concept itself has a substitution failure in a default parameter. The only other way I found to get this to work is what boost and a bunch of the others do, declaring explicit partial overloads for each of the detected and not cases, which takes more than twice as long to compile. As to the other bit, since the way we were using it in RAJA was throwing out the actual resulting type, some of the conditions we had for things like connectors to the I need to dig back into this and get it ready for actual use again. Much of what's in here is tested and works fine but we held back on it waiting to figure out the plan for C++14 so it's gotten out of sync, and could probably use an interface rework, I'm not sure I love all the extra macros. |
One concrete example I'm reminded of for the second issue is cases like this: template<typename T>
using ht_int = DefineConcept(has_type<int>(val<T>() + val<T>()));
//desugars to
template <typename... T>
constexpr std::true_type
valid_expr(T &&...);
template <typename T, typename U>
constexpr auto has_type(U &&) -> if_<std::is_same<T, U>, std::true_type>;
template<typename T>
using ht_int = decltype(valid_expr(has_type<int>(val<T>() + val<T>())); Since |
So I have a use case where I would like to detect the existence of methods in a protected base class that are made public in a derived class. template< typename T >
class Base
{
public:
T * data()
{ return nullptr; }
};
template< typename T >
class Derived : protected Base< T >
{
public:
using Base< T >::data;
}; I have my own detection logic (which I'd like to replace when this gets merged) but it fails with NVCC on this use case. So I decided to give this a try to see if it worked. I defined a concept as follows CAMP_DEF_REQUIREMENT_T( has_data_method, val<T>().data() );
CAMP_DEF_CONCEPT_T( HasDataMethod, detect< has_data_method, T >() ); It works just fine on Quartz but on Lassen with CAMP_DEF_REQUIREMENT_T( has_data_method, val<T>().data() );
CAMP_DEF_CONCEPT_T( HasDataMethod, detect< has_data_method, T >() );
template< typename T >
class Base
{
public:
void data()
{ return; }
};
template< typename T >
class Derived : protected Base< T >
{
public:
using Base< T >::data;
};
template< bool B >
struct BoolStruct
{
static constexpr bool value = B;
};
TEST(foo, bar)
{
static_assert( CAMP_REQ( HasDataMethod, std::string ), "" );
static_assert( !CAMP_REQ( HasDataMethod, int ), "" );
static_assert( CAMP_REQ( HasDataMethod, Base< int > ), "" );
#if !defined(__CUDACC__)
static_assert( CAMP_REQ( HasDataMethod, Derived< int > ), "" );
#else
// This fails and the inverse does too!
// static_assert( CAMP_REQ( HasDataMethod, Derived< int > ), "" );
// static_assert( !CAMP_REQ( HasDataMethod, Derived< int > ), "" );
#endif
ASSERT_EQ( CAMP_REQ( HasDataMethod, Derived< int > ), true );
// This fails with NVCC even though the above passed.
constexpr bool hasDataMethodAtCompileTime = BoolStruct< CAMP_REQ( HasDataMethod, Derived< int > ) >::value;
ASSERT_EQ( hasDataMethodAtCompileTime, true );
} This has got to be a compiler bug but if you find a way to make it work that would be awesome. |
That is absolutely fascinating, thank you so much for sending the test code @corbett5, finding good tests for this stuff is really tricky. It probably wont, but just in case it matters, were you compiling in c++11 or c++14 mode? |
I was using c++14. |
Well, @corbett5, I have both good and bad news for you. The bad news is that you're completely right that the detection for that pattern is broken, and that even the most resilient version of detector I know of fails on it. It fails, in some fashion, on every EDG compiler I have access to, gcc <= 6.0, clang up to current, and msvc. I know of no other template instantiation bug so prevalent across compilers, which is perversely impressive. @willkill07 put together a great test on godbolt here so you can see what happens on four of them. We're exploring workarounds, but so far the only workaround we've found is that if you do a check on the type of the expression rather than the validity, the check works properly on clang. Unfortunately it's still broken on icc, msvc and nvcc. The "good" news out of all of this is that the approach we're using seems to work as much as any of the approaches do, so we don't have to rework with a slower or more cumbersome one, but this specific case breaks most compilers regardless. I'm going to do at least a bit more digging here for a workaround, but detection of public methods that were protected in base classes is very, very broken at the moment. |
Wow, thanks @trws @willkill07 so much for digging into this! |
I'm putting this here in-progress right now, the goal is to re-factor the concepts stuff into a series of detectors and type-traits that are more separable, portable and reliable.