Skip to content

Instantly share code, notes, and snippets.

@dfyz
Last active September 26, 2022 02:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dfyz/c53848427bc7b0ec3e04b40d50898534 to your computer and use it in GitHub Desktop.
Save dfyz/c53848427bc7b0ec3e04b40d50898534 to your computer and use it in GitHub Desktop.
Mach-O vs. ELF export benchmark
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <dlfcn.h>
#include <err.h>
#define NSYMS 1000000
#if __linux__
#define LIB_EXT "so"
#elif __APPLE__
#define LIB_EXT "dylib"
#else
#error "huh?"
#endif
struct sym {
char* good_name;
char* bad_name;
int res;
};
struct sym syms[NSYMS] = {
#include "syms.inc"
};
int main(int argc, char* argv[]) {
if (argc != 2) {
err(1, "Usage: %s good|bad", argv[0]);
}
void* lib = dlopen("./lib." LIB_EXT, RTLD_NOW);
if (lib == NULL) {
err(1, "dlopen: %s", dlerror());
}
if (strcmp(argv[1], "good") == 0) {
clock_t good_start = clock();
for (size_t ii = 0; ii < NSYMS; ++ii) {
int(*f)() = dlsym(lib, syms[ii].good_name);
if (f == NULL) {
err(1, "%s: %s", syms[ii].good_name, dlerror());
}
int actual_val = f();
if (actual_val != syms[ii].res) {
err(1, "mismatch: %d vs. %d", actual_val, syms[ii].res);
}
}
clock_t good_end = clock();
printf("Good syms: %.2fms\n", (good_end - good_start) / (double)CLOCKS_PER_SEC * 1e3);
} else if (strcmp(argv[1], "bad") == 0) {
clock_t bad_start = clock();
for (size_t ii = 0; ii < NSYMS; ++ii) {
int(*f)() = dlsym(lib, syms[ii].bad_name);
if (f != NULL) {
err(1, "%s was somehow found", syms[ii].bad_name);
}
}
clock_t bad_end = clock();
printf("Bad syms: %.2fms\n", (bad_end - bad_start) / (double)CLOCKS_PER_SEC * 1e3);
} else {
err(1, "Unknown mode: %s", argv[1]);
}
return 0;
}
import string
import random
def random_snake_case():
return '_'.join(
''.join(random.choices(
string.ascii_lowercase,
k=random.randint(5, 15)
))
for ii in range(random.randint(2, 5))
)
def random_camel_case():
return ''.join(
random.choice(string.ascii_uppercase) + ''.join(random.choices(
string.ascii_lowercase,
k=random.randint(5, 15),
))
for ii in range(random.randint(2, 5))
)
if __name__ == '__main__':
random.seed(42)
N = 1_000_000
func_names = [
(ii, random_camel_case() if ii % 2 == 0 else random_snake_case())
for ii in range(N)
]
with open('lib.c', 'w') as f:
for ii, func_name in func_names:
print(
f'''int {func_name}() {{
return {ii};
}}'''
, file=f)
random.shuffle(func_names)
with open('syms.inc', 'w') as f:
for ii, func_name in func_names:
bad_name = func_name[:-1] + chr(ord(func_name[-1]) + 1)
print(f'{{.good_name = "{func_name}", .bad_name = "{bad_name}", .res = {ii}}},', file=f)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment