Create a gist now

Instantly share code, notes, and snippets.

Embed
What would you like to do?
invoking-relative-references.c
#include <mach/mach_time.h>
#include <mach-o/dyld.h>
#include <inttypes.h>
#include <signal.h>
#include <spawn.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/wait.h>
static const unsigned NUM_CLASSES = 8*8*8*8;
static const unsigned NUM_RUNS = 20*1000;
#if !defined(VARIATION) || VARIATION < 0 || VARIATION > 1
#error "Please pass -DVARIATION=[01] to the compiler. " \
"0 = relative method references; 1 = absolute method pointers"
#endif
#if VARIATION == 0
typedef int method_t;
#else
typedef void (*method_t)(void);
#endif
struct class {
method_t method1;
method_t method2;
method_t method3;
method_t method4;
method_t method5;
method_t method6;
method_t method7;
method_t method8;
};
void method_implementation(void) {}
// Emit something 4096 times
#define LOTS(x) \
x(__COUNTER__) x(__COUNTER__) x(__COUNTER__) x(__COUNTER__) \
x(__COUNTER__) x(__COUNTER__) x(__COUNTER__) x(__COUNTER__)
#define LOTS_AND_LOTS(x) \
LOTS(x) LOTS(x) LOTS(x) LOTS(x) \
LOTS(x) LOTS(x) LOTS(x) LOTS(x)
#define LOTS_AND_LOTS_AND_LOTS(x) \
LOTS_AND_LOTS(x) LOTS_AND_LOTS(x) LOTS_AND_LOTS(x) LOTS_AND_LOTS(x) \
LOTS_AND_LOTS(x) LOTS_AND_LOTS(x) LOTS_AND_LOTS(x) LOTS_AND_LOTS(x)
#define LOTS_AND_LOTS_AND_LOTS_AND_LOTS(x) \
LOTS_AND_LOTS_AND_LOTS(x) LOTS_AND_LOTS_AND_LOTS(x) LOTS_AND_LOTS_AND_LOTS(x) LOTS_AND_LOTS_AND_LOTS(x) \
LOTS_AND_LOTS_AND_LOTS(x) LOTS_AND_LOTS_AND_LOTS(x) LOTS_AND_LOTS_AND_LOTS(x) LOTS_AND_LOTS_AND_LOTS(x)
#define CAT_(a, b) a ## b
#define CAT(a, b) CAT_(a, b)
#if VARIATION == 0
// Variation 0 -- relative references
extern volatile struct class classes[NUM_CLASSES];
// Create 4096 class records.
// We have to generate the classes using global inline assembler, since C does not
// support constant expressions involving arithmetic on integers cast from global
// pointers.
__asm__ (
".section __TEXT, __const\n"
"_classes:\n"
#define CLASS_(nam) \
" .long _method_implementation - .\n" \
" .long _method_implementation - .\n" \
" .long _method_implementation - .\n" \
" .long _method_implementation - .\n" \
" .long _method_implementation - .\n" \
" .long _method_implementation - .\n" \
" .long _method_implementation - .\n" \
" .long _method_implementation - .\n"
#define CLASS(nam) CLASS_(nam)
#define OF_CLASSES(n) CLASS(CAT(class, n))
LOTS_AND_LOTS_AND_LOTS_AND_LOTS(OF_CLASSES)
);
static inline void *resolve_offset(volatile int *offset_ptr) {
uintptr_t base = (uintptr_t)offset_ptr;
uintptr_t offset = (uintptr_t)(intptr_t)*offset_ptr;
return (void*)(base + offset);
}
static inline void invoke_method(volatile int *method_offset) {
void (*method_ptr)(void) = (void (*)(void))resolve_offset(method_offset);
method_ptr();
}
#else
// Variation 1 -- absolute pointers
volatile struct class classes[NUM_CLASSES] = {
#define CLASS_(nam) \
{ \
.method1 = method_implementation, \
.method2 = method_implementation, \
.method3 = method_implementation, \
.method4 = method_implementation, \
.method5 = method_implementation, \
.method6 = method_implementation, \
.method7 = method_implementation, \
.method8 = method_implementation, \
},
#define CLASS(nam) CLASS_(nam)
#define OF_CLASSES(n) CLASS(CAT(class, n))
LOTS_AND_LOTS_AND_LOTS_AND_LOTS(OF_CLASSES)
};
static inline void invoke_method(volatile method_t *method_ptr) {
(*method_ptr)();
}
#endif
int main(int argc, char *argv[], char *envp[]) {
uint64_t start_time = mach_absolute_time();
// Invoke all the methods on all the classes.
for (unsigned i = 0; i < NUM_RUNS; ++i) {
for (volatile struct class *c = classes, *end = classes + NUM_CLASSES;
c != end; ++c) {
invoke_method(&c->method1);
invoke_method(&c->method2);
invoke_method(&c->method3);
invoke_method(&c->method4);
invoke_method(&c->method5);
invoke_method(&c->method6);
invoke_method(&c->method7);
invoke_method(&c->method8);
}
}
uint64_t end_time = mach_absolute_time();
uint64_t elapsed = end_time - start_time;
// Convert mach time units to nanoseconds.
mach_timebase_info_data_t timebase;
mach_timebase_info(&timebase);
typedef unsigned __int128 uint128_t;
uint64_t nanoseconds = (uint128_t)elapsed * (uint128_t)timebase.numer / timebase.denom;
printf("%" PRIu64 " nanoseconds to invoke methods\n", nanoseconds);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment