Last active
December 21, 2023 23:25
-
-
Save rianhunter/0be8dc116b120ad5fdd4 to your computer and use it in GitHub Desktop.
Indirect vs Direct Function Call Overhead in C/C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This benchmark shows how indirect function calls have nearly | |
the same overhead costs as direct function calls. | |
This is comparing apples to apples, factoring out the savings | |
due to inlining optimizations that direct calls usually afford. | |
From this, it seems that inlining and other generic interprocedual | |
optimizations are the main drivers of direct function call optimization, | |
not the direct call itself. | |
In other words, unless you implement your functions in header files | |
or compile with LTO (Link Time Optimization), there is virtually no benefit | |
to using direct function calls, aka static dispatch. | |
*/ | |
#include <limits.h> | |
int foo(int a) { | |
return a; | |
} | |
int direct_version() { | |
int i, b = 0; | |
for (i = 0; i < INT_MAX; ++i) { | |
b = foo(b); | |
} | |
return b; | |
} | |
int indirect_version(int (*fn)(int)) { | |
int i, b = 0; | |
for (i = 0; i < INT_MAX; ++i) { | |
b = fn(b); | |
} | |
return b; | |
} | |
int main(int argc, char *argv[]) { | |
if (argc == 2 && argv[1][0] == 'd') { | |
return direct_version(); | |
} | |
else { | |
return indirect_version(&foo); | |
} | |
} | |
/* | |
$ cc -O3 -fno-inline -fomit-frame-pointer call_overhead.c | |
$ time ./a.out d | |
real 0m5.199s | |
user 0m5.155s | |
sys 0m0.021s | |
$ time ./a.out s | |
real 0m5.251s | |
user 0m5.215s | |
sys 0m0.018s | |
*/ |
Additionally, if the function call can be inlined, the indirect version has function call overhead, while the direct version does not.
Where this gets interesting is where the reason for the indirection is the presence or absence of a conditional (or conditional tree) to select a function. I.e. "how many 'if's does one need to eliminate to justify the performance penalties of the function call indirection?"
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for this @rianhunter and the response @abainbridge 👍