-
Notifications
You must be signed in to change notification settings - Fork 192
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
Allow multiple callbacks on same component #6334
Allow multiple callbacks on same component #6334
Conversation
src/Parallel/Callback.hpp
Outdated
* \brief Returns if this callback is equal to the one passed in. | ||
* | ||
* \details If the `std::optional` doesn't have a value, then the pointer | ||
* cast between the two callbacks failed. If it does have a value, then the |
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's some sort of context missing for this documentation. There doesn't seem to be any mention of pointers or casts anywhere else.
src/Parallel/Callback.hpp
Outdated
std::optional<bool> is_equal_to(const Callback& rhs) const override { | ||
const auto* downcast_ptr = dynamic_cast<const SimpleActionCallback*>(&rhs); | ||
if (downcast_ptr == nullptr) { | ||
return std::nullopt; |
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.
Why this distinction instead of just returning false?
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.
It was particularly useful in debugging to know if the callbacks were different types, or if they were the same but had different arguments. At some point, I would like to put debugging info/prints into the cache and this kind of info would be useful, but that's beyond this PR so I just left the return types as optional<bool>
for now
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.
Just return a bool. If you want to know if the types are the same for debugging you can check that directly without complicating the public interface.
const std::optional<bool> callback_2_equal_to_vec_end = | ||
callback_2.is_equal_to(*callbacks.back()); | ||
SPECTRE_PARALLEL_REQUIRE(callback_2_equal_to_vec_end.has_value()); | ||
SPECTRE_PARALLEL_REQUIRE_FALSE(callback_2_equal_to_vec_end.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.
[optional] callback_2_equal_to_vec_end == std::optional{false}
seems clearer to me than these two lines.
|
||
namespace Parallel { | ||
namespace detail { | ||
// Not all tuple arguments are guaranteed to have operator==, so we check the | ||
// ones we can. |
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'm a bit worried about silently ignoring entries. What types typically occur that cause problems?
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.
The problematic types were proxies and I didn't want to deal with how to evaluate equivalence of those
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. charmplusplus/charm#3848 is probably the real fix, for what it's worth, but we can't wait for that.
Looks good. Squash. |
@wthrowe I realized I inadvertently added a bug related to removing an unnecessary callback if the cache item was mutated and is now ready. I added a new commit and a new fixup, so let me know if you need more of a explanation, or if the code is enough. |
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.
Good catch. Test isn't compiling, though.
// array component id still has callbacks before trying to remove them. | ||
if (callbacks.contains(array_component_id)) { | ||
if (callbacks.at(array_component_id).empty()) { | ||
callbacks.erase(array_component_id); |
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.
Check if the vector is empty after removing the element, instead of before.
src/Parallel/Callback.hpp
Outdated
@@ -115,6 +119,11 @@ class SimpleActionCallback : public Callback { | |||
"," + pretty_type::name<Proxy>() + ")"; | |||
} | |||
|
|||
std::unique_ptr<Callback> get_clone() override { | |||
return std::make_unique<SimpleActionCallback<SimpleAction, Proxy, Args...>>( | |||
proxy_, args_); |
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.
[optional] Using the copy constructor is simpler. (Also several other places.)
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.
Just a couple small things you can squash with everything else.
src/Parallel/GlobalCache.hpp
Outdated
callbacks.erase(array_component_id); | ||
} else { | ||
// If this callback was a duplicate, we'll have to search through all | ||
// callbacks to determine which to remove. If it wasn't a dupliate, |
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.
dupliate
-> duplicate
src/Parallel/GlobalCache.hpp
Outdated
auto& vec_callbacks = callbacks.at(array_component_id); | ||
auto it_to_erase = vec_callbacks.begin(); | ||
for (; it_to_erase != vec_callbacks.end(); it_to_erase++) { | ||
if ((*it_to_erase)->is_equal_to(*clone_of_optional_callback)) { | ||
vec_callbacks.erase(it_to_erase); | ||
break; | ||
} | ||
} |
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 this can be done with
vec_callbacks.erase(std::find(vec_callbacks.begin(), vec_callbacks.end(),
[&clone_of_optional_callback](const auto& t) {
return t.is_equal_to(*clone_of_optional_callback);
});
Looks good. Squash. |
a77a380
to
0f096a3
Compare
Proposed changes
It is possible for multiple unique callbacks to be registered to the same parallel component (size control system does this). Previously, we only took the first callback and discarded the rest (because the elements would register multiple identical callbacks and we only needed one). Now we still discard identical callbacks, but keep unique callbacks on the same component.
This was found while debugging the nodegroup implementation of our algorithm, but I believe this is also a bug on develop. I guess we just have been lucky and haven't hit this so far.
Upgrade instructions
Code review checklist
make doc
to generate the documentation locally intoBUILD_DIR/docs/html
.Then open
index.html
.code review guide.
bugfix
ornew feature
if appropriate.Further comments