-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Compare always checking + checking upfront
This is to help emphasize the question "Why even bother with IFUNC"? How much time does it really save?
- Loading branch information
1 parent
3ef2240
commit 63ad2ff
Showing
4 changed files
with
156 additions
and
25 deletions.
There are no files selected for viewing
This file contains 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 file contains 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 file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// This program is part of an experiment to compare the performance of GNU IFUNC | ||
// vs plain-old function pointers. Run `make rigorous_speed_demo` to see a full | ||
// comparison of speeds. | ||
// | ||
// This particular program selects an "appropriate" incrementer function lazily, | ||
// via the GNU IFUNC facility. The choice of incrementer is irrelevant, since | ||
// they are the same; our concern is the cost of invoking the chosen incrementer | ||
// based on what strategy we use to select it. | ||
#include <limits.h> | ||
#include <stddef.h> | ||
static int counter = 0; | ||
|
||
// Use this incrementer algorithm if AVX2 is available. | ||
void avx2_incrementer() { | ||
counter += 1; | ||
} | ||
|
||
// Use this if AVX2 is not available. It's the same as above, because we don't | ||
// actually rely on AVX2. | ||
void normal_incrementer() { | ||
counter += 1; | ||
} | ||
|
||
// This is the ifunc "stub" function. The first time it is called, the | ||
// `resolver` will be invoked in order to select an appropriate "real" function. | ||
// Once the "real" function is selected, its address will be stored in the | ||
// Global Offset Table. When this stub is invoked in the future, the PLT will | ||
// cause the program to jump directly to the selected function. | ||
void increment_counter() { | ||
if (__builtin_cpu_supports("avx2")) { | ||
avx2_incrementer(); | ||
} else { | ||
normal_incrementer(); | ||
} | ||
} | ||
|
||
int main() { | ||
// Count to ~ 2 Billion by calling a dynamically-resolved incrementer | ||
while (counter < INT_MAX) { | ||
increment_counter(); | ||
} | ||
return 0; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// This program is part of an experiment to compare the performance of GNU IFUNC | ||
// vs plain-old function pointers. Run `make rigorous_speed_demo` to see a full | ||
// comparison of speeds. | ||
// | ||
// This particular program selects an "appropriate" incrementer function at the | ||
// beginning of main, before any other work is done. The address of the chosen | ||
// function is stored in a static function pointer. The choice of incrementer | ||
// is irrelevant, since they are the same; our concern is the cost of invoking | ||
// the chosen incrementer based on what strategy we use to select it. | ||
#include <limits.h> | ||
#include <stddef.h> | ||
#include <stdbool.h> | ||
static int counter = 0; | ||
static bool cpu_has_avx2 = false; | ||
|
||
// Use this incrementer algorithm if AVX2 is available. | ||
void avx2_incrementer() { | ||
counter += 1; | ||
} | ||
|
||
// Use this if AVX2 is not available. It's the same as above, because we don't | ||
// actually rely on AVX2. | ||
void normal_incrementer() { | ||
counter += 1; | ||
} | ||
|
||
// Select an "appropriate" incrementer based on CPU features. The actual choice | ||
// doesn't matter in this case, we just need something for the resolver to do. | ||
void increment_counter() { | ||
if (cpu_has_avx2) { | ||
avx2_incrementer(); | ||
} else { | ||
normal_incrementer(); | ||
} | ||
} | ||
|
||
void detect_cpu_features() { | ||
cpu_has_avx2 = __builtin_cpu_supports("avx2"); | ||
} | ||
|
||
int main() { | ||
detect_cpu_features(); | ||
|
||
// Count to ~ 2 Billion by calling a dynamically-resolved incrementer | ||
while (counter < INT_MAX) { | ||
increment_counter(); | ||
} | ||
return 0; | ||
} |