Note that there are some explanatory texts on larger screens.

plurals
  1. POWhere is the virtual function call overhead?
    text
    copied!<p>I'm trying to benchmark the difference between a function pointer call and a virtual function call. To do this, I have written two pieces of code, that do the same mathematical computation over an array. One variant uses an array of pointers to functions and calls those in a loop. The other variant uses an array of pointers to a base class and calls its virtual function, which is overloaded in the derived classes to do absolutely the same thing as the functions in the first variant. Then I print the time elapsed and use a simple shell script to run the benchmark many times and compute the average run time.</p> <p>Here is the code:</p> <pre><code>#include &lt;iostream&gt; #include &lt;cstdlib&gt; #include &lt;ctime&gt; #include &lt;cmath&gt; using namespace std; long long timespecDiff(struct timespec *timeA_p, struct timespec *timeB_p) { return ((timeA_p-&gt;tv_sec * 1000000000) + timeA_p-&gt;tv_nsec) - ((timeB_p-&gt;tv_sec * 1000000000) + timeB_p-&gt;tv_nsec); } void function_not( double *d ) { *d = sin(*d); } void function_and( double *d ) { *d = cos(*d); } void function_or( double *d ) { *d = tan(*d); } void function_xor( double *d ) { *d = sqrt(*d); } void ( * const function_table[4] )( double* ) = { &amp;function_not, &amp;function_and, &amp;function_or, &amp;function_xor }; int main(void) { srand(time(0)); void ( * index_array[100000] )( double * ); double array[100000]; for ( long int i = 0; i &lt; 100000; ++i ) { index_array[i] = function_table[ rand() % 4 ]; array[i] = ( double )( rand() / 1000 ); } struct timespec start, end; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &amp;start); for ( long int i = 0; i &lt; 100000; ++i ) { index_array[i]( &amp;array[i] ); } clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &amp;end); unsigned long long time_elapsed = timespecDiff(&amp;end, &amp;start); cout &lt;&lt; time_elapsed / 1000000000.0 &lt;&lt; endl; } </code></pre> <p>and here is the virtual function variant:</p> <pre><code>#include &lt;iostream&gt; #include &lt;cstdlib&gt; #include &lt;ctime&gt; #include &lt;cmath&gt; using namespace std; long long timespecDiff(struct timespec *timeA_p, struct timespec *timeB_p) { return ((timeA_p-&gt;tv_sec * 1000000000) + timeA_p-&gt;tv_nsec) - ((timeB_p-&gt;tv_sec * 1000000000) + timeB_p-&gt;tv_nsec); } class A { public: virtual void calculate( double *i ) = 0; }; class A1 : public A { public: void calculate( double *i ) { *i = sin(*i); } }; class A2 : public A { public: void calculate( double *i ) { *i = cos(*i); } }; class A3 : public A { public: void calculate( double *i ) { *i = tan(*i); } }; class A4 : public A { public: void calculate( double *i ) { *i = sqrt(*i); } }; int main(void) { srand(time(0)); A *base[100000]; double array[100000]; for ( long int i = 0; i &lt; 100000; ++i ) { array[i] = ( double )( rand() / 1000 ); switch ( rand() % 4 ) { case 0: base[i] = new A1(); break; case 1: base[i] = new A2(); break; case 2: base[i] = new A3(); break; case 3: base[i] = new A4(); break; } } struct timespec start, end; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &amp;start); for ( int i = 0; i &lt; 100000; ++i ) { base[i]-&gt;calculate( &amp;array[i] ); } clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &amp;end); unsigned long long time_elapsed = timespecDiff(&amp;end, &amp;start); cout &lt;&lt; time_elapsed / 1000000000.0 &lt;&lt; endl; } </code></pre> <p>My system is LInux, Fedora 13, gcc 4.4.2. The code is compiled it with g++ -O3. The first one is test1, the second is test2.</p> <p>Now I see this in console:</p> <pre><code>[Ignat@localhost circuit_testing]$ ./test2 &amp;&amp; ./test2 0.0153142 0.0153166 </code></pre> <p>Well, more or less, I think. And then, this:</p> <pre><code>[Ignat@localhost circuit_testing]$ ./test2 &amp;&amp; ./test2 0.01531 0.0152476 </code></pre> <p>Where are the 25% which should be visible? How can the first executable be even slower than the second one?</p> <p>I'm asking this because I'm doing a project which involves calling a lot of small functions in a row like this in order to compute the values of an array, and the code I've inherited does a very complex manipulation to avoid the virtual function call overhead. Now where is this famous call overhead?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload