-
Notifications
You must be signed in to change notification settings - Fork 2
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
Use virtual functions instead of if-else in switch kernel #152
Conversation
Experimental code of a more dynamic system for handling runtime switching between multiple kernels. Instead of if-else statements in operator(), different classes are created in the kernel creation functions. Switching in the operator() happens using virtual table rather than if-else in the switch kernel's operator() and the actual kernels is access though a pointer (to an abstract base class). This may make handling multiple kernels more flexible or easier and a variation of this seems to be needed for supporting multiple network kernels.
…the initialization did, so not visible until now)
…flexibility and to avoid possible optimization
According to my benchmarks, dynamically implemented kernels (virtual methods/OOP/polymorphism) are just as fast as the statically implemented ones (all kernels instantiated, if statements decide which one to use). A complex static implementation are only as fast as the dynamic implementation in a pure PoPS Core benchmark. In a r.pops.spread benchmark, the dynamic implementation significantly outperforms the static implementation although a simple static implementation is faster as expected and a slightly complex (similar to the original pre-1.0 kernel) is just as fast as the dynamic implementation. Pure PoPS CoreHard-coded kernel in the codehard-coded kernel, rows = 500, cols = 1000, reproductive_rate = 2, all susceptible = 100, all infected = 10, 10 runs (test repetitions), release build, GCC
User-provided kerneluser-provided (variable) kernel, rows = 500, cols = 1000, reproductive_rate = 2, all susceptible = 100, all infected = 10, 10 runs (test repetitions), release build, GCC
r.pops.spread test suitefull test suite for r.pops.spread with modified pops-core, 10 runs (test repetitions), GCC optimizations enabled (-O3), no debug (no -ggdb)
|
The speed-up looks great as we will be using it in r.pops.spread and rpops with full kernel suite. |
…C++14 to have std::make_unique
…ointer in another
…que_ptr without make_unique, which truns this back to C++11
…asses are merged into one called DynamicWrapperKernel
Experimental code of a more dynamic system for handling runtime switching between multiple kernels.
Instead of if-else statements in operator(), different classes are created in the kernel creation functions.
Switching in the operator() happens using virtual table rather than if-else in the switch kernel's operator()
and the actual kernels is access though a pointer (to an abstract base class). This happens within the kernel which switches between natural and anthropogenic kernels. Unlike with switch kernel where all kernels needed to be instantiated, now only the needed ones are and there is no switch kernel for the natural and anthropogenic kernels because the kernel which switches between them uses pointers to access them.
Natural and anthropogenic kernel creation functions moved out of Model class into separate files.
Natural and anthropogenic kernels are now actually different from each other. So far the difference is that anthropogenic kernel has a network kernel.
Newly, random number generator type is a template parameter of Model and Simulation, set as Generator = std::default_random_engine in both cases. Model just passes the type to Simulation. Simulation creates the object as before. The templating is useful in general, but it was needed to make the dynamic kernel generator-independent because while virtual function and template don't work together (that would be indefinite number of functions) while templating the class works (one function for one class).
Model now takes kernel factory (function) as a parameter (in constructor, the type is a template parameter with a default matching the default for the constructor).
This may make handling multiple kernels more flexible or easier and a variation of this seems to be needed for supporting multiple network kernels. One example now is that the switch kernel is not used for natural and anthorpogenic kernels, so they can be now different without need for another version of the switch kernel.
The overflow kernel is still the original implementation and there is still only one network supported.