There is a question of the impact on speed from the use of virtual functions. The experiment used here is to use the circuit eq4-2305.ckt from the examples directory, and try several modified versions of the program. I used a 100 point dc sweep, a version between 0.20 and 0.21, and made several modifications for testing purposes. I chose this circuit because it has little to mask the effect, and therefore is sort of a worst case.
I added an int foo to the element class. I made the function il_trload_source call a virtual function virtual_test and stored the result. The local version body has a print call, which should not show, to make sure it calls the other. These functions simply return a constant, determined by which version of the function is called. Run time is compared, with and without this.
With 1 virtual function call (included in load)
user sys total evaluate 13.45 0.11 13.56 load 13.40 0.06 13.47 lu 1.91 0.09 2.00 back 22.35 0.27 22.61 review 0.00 0.00 0.00 output 0.11 0.11 0.22 overhead 0.23 0.19 0.42 total 51.45 0.83 52.28
With 10 virtual function calls (included in load)
user sys total evaluate 13.47 0.09 13.57 load 24.69 0.17 24.87 lu 2.09 0.02 2.11 back 22.17 0.35 22.51 review 0.00 0.00 0.00 output 0.14 0.11 0.25 overhead 0.25 0.25 0.50 total 62.82 0.99 63.81
No extra function calls (included in load)
user sys total evaluate 13.41 0.09 13.50 load 11.75 0.05 11.79 lu 2.04 0.03 2.07 back 22.51 0.33 22.84 review 0.00 0.00 0.00 output 0.08 0.11 0.19 overhead 0.31 0.25 0.56 total 50.10 0.86 50.96
My conclusion is that in this context, even a single virtual function call is significant (10-15% of the load time), but not so significant as to prohibit their use. The load loop here calls one virtual function inside a loop. The virtual function calls an ordinary member function. Therefore, about 30% of the load time is function call overhead.
The impact should be less significant for complex models like transistors because the calculation time is much higher and would serve to hide this better.
Spice uses a different architecture, where a single function evaluates and loads all elements of a given type. This avoids these two calls.
For this test, il_trload_source is not inline. Contrast to "No extra function calls" and "1 virtual function" above, in which this function is inline.
user sys total evaluate 13.44 0.15 13.60 load 13.85 0.14 13.99 lu 1.73 0.02 1.75 back 22.89 0.35 23.24 review 0.00 0.00 0.00 overhead 0.45 0.17 0.63 total 52.50 0.94 53.44
This shows (crudely) that the overhead of an ordinary private member function call (called from another member function in the same class) is significant here. The cost of a virtual function call is comparable to the cost of an ordinary private member function call.