-
Notifications
You must be signed in to change notification settings - Fork 766
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
[SYCL] Rewrite properties storage #13776
Conversation
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.
ESIMD part looks good.
BTW, if there are some changes/movements in the properties class I'll use the good moment to share the idea, that might be useful for users of properties
class.
In ESIMD we needed the utility functions that add-property-if-not-in-list:
https://github.com/intel/llvm/blob/sycl/sycl/include/sycl/ext/intel/esimd/memory_properties.hpp#L217-L221
and add-or-replace-property-in-list:
https://github.com/intel/llvm/blob/sycl/sycl/include/sycl/ext/intel/esimd/memory_properties.hpp#L253-L257
In ESIMD it was needed only for alignment
. Perhaps some more generic utility could be created and be useful in ext::oneapi::experimental::properties class (in property_utils.hpp)?
moved trivial changes into #13777 to reduce size of this |
d890875
to
972fd2d
Compare
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.
LGTM. pinging @steffenlarsen for his take
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 very interesting! More comments would be good, especially one describing how we use the properties as base-classes for the properties
type.
public: | ||
template <class... T> | ||
constexpr properties(T... v) | ||
: T(v)... {} // T might have different ordering than V |
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 I pass something that isn't a property in the properties
, will this result in a user-friendly message? At first glance I would think the compiler would scream about base classes, which is an implementation detail that the user should not worry about.
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.
Correct. And I agree the message being about base class makes is less user-friendly. On the other hand the message names the property which is the problem which makes it more user-friendly than the static assert (for which we can't include the name in the message). I'm not sure whether the pro/cons is more important. Happy to add a static_assert if you think hiding implementation details is more important than giving the name of the property.
static_assert(has_property<PropertyT>(), | ||
template <class P> static constexpr auto get_property(int = 0) { | ||
using T = detail::mp11::mp_map_find<map, P>; | ||
static_assert(!std::is_same_v<T, void>, |
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 this actually faster than just using has_property
?
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.
propably not. has_property
calls mp_map_contains
which calls mp_map_find
and compares it against void
. And the compiler should memorize the mp_map_find
template instanstiation and therefore it shouldn't matter if it is called twice.
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.
In that case, I would prefer using has_property
as we do so in the other get_property
implementation.
return (!std::is_same<A, B>::value || ...); | ||
} | ||
|
||
template <typename V, typename = void> struct is_property_value { |
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 still part of the extension, so I don't think it should be removed. Even if it is to be removed, it would be more fitting to do in a separate patch.
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.
do you want me to also move the removal of tests for is_property_value and is_property_key into a follow up PR?
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 that would make sense. It really depends on how ingrained it is. Seems like this relates to some of the other changes, as mentioned in my previous comment, so I will leave it up to you whether you want to split it, but it seems like the specification changes related to this is still in review.
let me know what else would benefit from comments |
|
I haven't done any before/after comparison (yet). Before I started I looked at the compilation trace of the header and noticed the impact of std::tuple instanstiation and very slow compilation for long property lists (in particular >10 properties) because of the recursion used for e.g. merge, get, has. While I created multiple prototypes I made sure that those issues are resolved.
I could imagine that it might benefit a bit given that the new implementation is shorter which should benefit parsing. But I haven't looked at any benchmarks for parsing. Note that the instantiation cost does affect users which don't use any properties. Properties are used internally by multiple of our extensions and they instantiate properties, e.g. as part of the default arguments. And it's not just empty property list because there are some default properties used.
I didn't invent anything new.
I don't think it is possible. You can't address the main issue of the recursive instanstiation with builtins. Suggestions for compilation speed improvements beyond this PR:
|
Given bench:
I see ~2s for the new version and ~3.4s for the old version. |
Hi @rolandschulz , thank you for the detailed reply to my questions. Can you please put most of it into the PR description? I think that reasoning is important to preserve/be found easy and I'd like to see it in-tree vs. hosting platform that can be changed in future (however unlikely that is). |
struct is_empty_or_incomplete : std::true_type {}; | ||
template <class T> | ||
struct is_empty_or_incomplete< | ||
T, std::enable_if_t<(sizeof(T) > 0) && !std::is_empty_v<T>>> | ||
: std::false_type {}; |
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.
Did we do the same thing before? I'm worried about "incomplete" part and issues it may cause if the behavior is different when we ask for the same thing both before and after something become "complete" (and that would also be ODR-violation, I guess).
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.
No. And it's unrelated to the storage change. It is related to #13669 which suggests that we allow to define properties as:
inline constexpr property_value<struct bar_key> bar;
If we don't allow incomplete we need to require it to be:
struct bar_key {};
inline constexpr property_value<bar_key> bar;
It has no other advantage besides being less verbose. So if we think this might be a problem we don't need to do this.
Note that it wouldn't be a concern that it would become complete. Because such a key would always just be forward declared.
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.
What do you mean with with your reaction? You prefer to change it or keep it?
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.
Keep it, liked the simplification of it.
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 have similar numbers for your case (3.15s->1.7s), but
To be clear, this is not a request/objection, just an observation. |
: std::bool_constant< | ||
ext::oneapi::experimental::is_property_key_of<PropT, SyclT>::value && | ||
all_props_are_keys_of<SyclT, PropTs...>()> {}; | ||
#if __cplusplus > 201402L |
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.
We require C++17 for the compiler already.
Looks good to me but @steffenlarsen is more fluent with this than I am, so I'm deferring the approval to him. |
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.
Overall, I like the new strategy, but there seems to be parts that require extension spec changes.
PropKey, std::tuple<Props...>>::type, | ||
DefaultPropVal>; | ||
struct GetPropertyValueFromPropList { | ||
using V = |
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.
Nit; Another name that could hit a macro.
struct is_empty_or_incomplete : std::true_type {}; | ||
template <class T> | ||
struct is_empty_or_incomplete< | ||
T, std::enable_if_t<(sizeof(T) > 0) && !std::is_empty_v<T>>> | ||
: std::false_type {}; |
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.
static_assert(has_property<PropertyT>(), | ||
template <class P> static constexpr auto get_property(int = 0) { | ||
using T = detail::mp11::mp_map_find<map, P>; | ||
static_assert(!std::is_same_v<T, void>, |
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.
In that case, I would prefer using has_property
as we do so in the other get_property
implementation.
using A = property_map<PropA>; | ||
using B = property_map<PropB>; |
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 case of potential conflict single-letter names. Maybe PropAMap
or PropMapA
, etc?
return (!std::is_same<A, B>::value || ...); | ||
} | ||
|
||
template <typename V, typename = void> struct is_property_value { |
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 that would make sense. It really depends on how ingrained it is. Seems like this relates to some of the other changes, as mentioned in my previous comment, so I will leave it up to you whether you want to split it, but it seems like the specification changes related to this is still in review.
This is based on @rolandschulz 's #13776. The only remaining boost/mp11 usage is to sort/filter properties, I'm going to remove that in a separate PRs. I've also left multiple utilities (that accept variadic pack) still using `std::tuple` as *their* implementation detail. That can be cleaned up separately as well. Closes #13677.
This pull request is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be automatically closed in 30 days. |
This pull request was closed because it has been stalled for 30 days with no activity. |
Goal is to improve compilation time.
Store all properties as map. A map is type-list of type-lists. The first entry of the inner list is the property key and the 2nd the property value. Allows efficient lookup.
Runtime values are stored as base types. Allows efficient storage and retrieval.
std::tuple usage is removed (slow to instanstiate).