-
Notifications
You must be signed in to change notification settings - Fork 384
Disentangle kernel-manager include tree #3544
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
base: master
Are you sure you want to change the base?
Conversation
…cular include chains
Important to note: I kept the internal API identical. All I've done essentially was to use references to the managers instead which allowed to forward-declare the managers in the kernel_manager.h file. The reason there are that many changes is that including the kernel_manager.h no longer means that one also includes ALL other managers. So each file using a specific manager has to include that manager explicitly. This is much cleaner and will also speed up compilation a bit. |
I have no idea what's supposed to be wrong with the 2 copyright headers. @terhorstd Could you take a look please? |
@JanVogelsang This looks very interesting! Just to make sure I understand your solution correctly: Instead of having the individual managers as actual data members of the This is certainly a great code cleanup. I am just a tiny bit concerned about performance, since we now have essentially pointers to the individual managers. Have you run any benchmarks yet? |
Very strange. Have you tried to run the copyright check locally on your machine? |
@heplesser Yes, this is correct! I benchmarked the performance and the PR's solution is indeed around 5% slower (locally and on Juwels). I have to admit that this surprises me a lot, as while this introduces another pointer, I would have assumed that all these pointers (or mostly just the simulation_manager and event_delivery_manager pointers during simulation) would be cached anyway. This seems to not be possible and I am not sure why. Then again, the cause of the performance degradation might also be something entirely different, for example growing code size which harms instruction cache efficiency due to more function inlining. I implemented two other solutions now, which both require the internal API to change, though:
namespace kernel {
template<typename ManagerT, std::enable_if_t<std::is_base_of_v<ManagerInterface, ManagerT>>* = nullptr>
ManagerT& manager()
{
static ManagerT static_manager;
return static_manager;
}
}
namespace kernel {
template <class T>
inline T g_manager_instance;
template <class T>
T& manager() noexcept {
return g_manager_instance<T>;
}
} I'm currently benchmarking both solutions, but local benchmarks suggest that the second approach performs best. |
I managed to solve this, it was just two empty files which I deleted but somehow they were added back in again, just empty. |
@JanVogelsang Thanks for checking and the new solutions! I slightly prefer the second option, but that is mainly based on the fact that I still haven't entirely wrapped my mind around the Is it necessary to place this into a separate namespace |
@@ -19,23 +19,179 @@ | |||
* along with NEST. If not, see <http://www.gnu.org/licenses/>. | |||
* | |||
*/ | |||
#include "grid_layer.h" | |||
#include "layer.h" | |||
|
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 these lines move the wrong way around? layer.h was deleted, but the _impl file now has all code?
What is the reason for dropping the include-guards?
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.
Thanks for catching this, it definitely wasn't intentional. I think I first removed the layer_impl.h, but then added it back again as there was a circular dependency with the grid_layer.h. So I must have accidentally copied too much from the layer.h over to the layer_impl.h
#include <algorithm> | ||
#include <iostream> | ||
#include <vector> |
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.
@jessica-mitchell, this would be a perfect place to link into the Doxygen documentation instead of copy-pasting some random code file into the RST.
For now however some reference syntax could shorten this somewhat unrelated change in this PR. Isn't there a possibility to link to a code file to be included? Instead of this PR updating the docs with the new file, it would be preferable to have something like:
.. code: cpp
file: ../nestkernel/stopwatch.h
Would avoid this excessive change in an rst file.
@JanVogelsang, this is big work! Thanks a lot for this big cleaning effort! Could you also check the relation to #3465 ? |
That's totally fine as well. The additional/nested namespace ( |
Co-authored-by: Dennis Terhorst <terhorstd@users.noreply.github.com>
It's still compatible with that PR, the role of the kernel manager stays the same. |
Summary of changes
This PR fixes the horrible kernel-manager singleton design and cleans up all circular include chains which were just hidden behind the kernel-manager and plenty "*_impl.h" files.
Even though this PR touches 250+ files, the only functional changes were done in the kernel_manager.h/.cpp and the other changes are just follow-up refactorings enabled by the changes. I also got rid of most of the impl-files, which are not required anymore and just complicated things.
Why this was necessary
Anyone who ever worked on the kernel will immediately know about the pain the kernel-manager caused. As the kernel-manager included ALL other manager in the kernel_manager.h file, any other class using the kernel-manager therefore also included ALL other managers. This resulted in either of two things:
2.1. The kernel-manager could only be included in the .cpp file, which meant that the function using the kernel-manager (and thus any of the other managers) could not be inlined, which in some cases is detrimental for performance.
2.2. We had to create those impl.h files and use the kernel-manager in there. However, impl.h files and correctly including them is a nightmare and leads to various linker issues which are extremely difficult to debug.
The only time when one should use impl.h files is for some template specializations.