Allow multiple callbacks on same component#6334
Allow multiple callbacks on same component#6334nilsdeppe merged 3 commits intosxs-collaboration:developfrom
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.
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.
Why this distinction instead of just returning false?
There was a problem hiding this comment.
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.
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.
[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.
I'm a bit worried about silently ignoring entries. What types typically occur that cause problems?
There was a problem hiding this comment.
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.
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. |
wthrowe
left a comment
There was a problem hiding this comment.
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.
Check if the vector is empty after removing the element, instead of before.
src/Parallel/Callback.hpp
Outdated
|
|
||
| std::unique_ptr<Callback> get_clone() override { | ||
| return std::make_unique<SimpleActionCallback<SimpleAction, Proxy, Args...>>( | ||
| proxy_, args_); |
There was a problem hiding this comment.
[optional] Using the copy constructor is simpler. (Also several other places.)
nilsdeppe
left a comment
There was a problem hiding this comment.
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, |
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.
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 docto generate the documentation locally intoBUILD_DIR/docs/html.Then open
index.html.code review guide.
bugfixornew featureif appropriate.Further comments