|
infix
A JIT-Powered FFI Library for C
|
A micro-benchmark to measure the performance overhead of an FFI call. More...
Macros | |
| #define | DBLTAP_IMPLEMENTATION |
Functions | |
| int | add_for_benchmark (int a, int b) |
| The simple C function used as the target for all benchmarked calls. | |
| diag ("infix Call Overhead Benchmark") | |
| diag ("Iterations: %d", BENCHMARK_ITERATIONS) | |
| diag ("Target function: int(int, int)") | |
| for (int i=0;i< BENCHMARK_ITERATIONS;++i) accumulator+ | |
| diag ("Direct Call Time: %.4f s (%.2f ns/call)", direct_time, direct_ns_per_call) | |
| if (infix_forward_create_unbound_manual &,,, 2, 2arg_types !=INFIX_SUCCESS) | |
| diag ("infix (Unbound): %.4f s (%.2f ns/call) -> Overhead: ~%.2f ns", unbound_time, unbound_ns, unbound_ns - direct_ns_per_call) | |
| if (infix_forward_create_manual(&bound_t, ret_type, arg_types, 2, 2,(void *) add_for_benchmark) !=INFIX_SUCCESS) bail_out("Failed to create bound trampoline") | |
| diag ("infix (Bound): %.4f s (%.2f ns/call) -> Overhead: ~%.2f ns", bound_time, bound_ns, bound_ns - direct_ns_per_call) | |
| infix_forward_destroy (unbound_t) | |
| infix_forward_destroy (bound_t) | |
| note ("dyncall benchmarking was not enabled.") | |
| pass ("Benchmark completed (final accumulator value: %d)", accumulator) | |
Variables | |
| TEST | |
| const int | BENCHMARK_ITERATIONS = 10000000 |
| volatile int | accumulator = 0 |
| clock_t | start = clock() |
| clock_t | end = clock() |
| double | direct_time = ((double)(end - start)) / CLOCKS_PER_SEC |
| double | direct_ns_per_call = (direct_time / BENCHMARK_ITERATIONS) * 1e9 |
| infix_type * | ret_type = infix_type_create_primitive(INFIX_PRIMITIVE_SINT32) |
| infix_type * | arg_types [] |
| infix_forward_t * | unbound_t = nullptr |
| double | unbound_time = ((double)(end - start)) / CLOCKS_PER_SEC |
| double | unbound_ns = (unbound_time / BENCHMARK_ITERATIONS) * 1e9 |
| infix_forward_t * | bound_t = nullptr |
| infix_cif_func | bound_cif = infix_forward_get_code(bound_t) |
| double | bound_time = ((double)(end - start)) / CLOCKS_PER_SEC |
| double | bound_ns = (bound_time / BENCHMARK_ITERATIONS) * 1e9 |
A micro-benchmark to measure the performance overhead of an FFI call.
This is not a correctness test, but a performance benchmark. Its purpose is to quantify the "cost" of making a C function call through an infix trampoline compared to a direct C call.
The benchmark measures and reports the average time per call for:
infix (Unbound):** A loop calling the same C function via an unbound forward trampoline. This measures the overhead of the most flexible FFI path.infix (Bound):** A loop calling the same C function via a bound forward trampoline. This measures the overhead of the highest-performance FFI path.DYNCALL_BENCHMARK, it also measures the performance of the popular dyncall library for the same function call, providing a useful point of comparison against another FFI library.The output is a "nanoseconds per call" metric, which helps quantify the FFI overhead and track performance regressions or improvements over time.
| #define DBLTAP_IMPLEMENTATION |
| int add_for_benchmark | ( | int | a, |
| int | b | ||
| ) |
The simple C function used as the target for all benchmarked calls.
| diag | ( | "Direct Call Time: %.4f s (%.2f ns/call)" | , |
| direct_time | , | ||
| direct_ns_per_call | |||
| ) |
| diag | ( | "infix (Bound): %.4f s (%.2f ns/call) -> Overhead: ~%.2f ns" | , |
| bound_time | , | ||
| bound_ns | , | ||
| bound_ns - | direct_ns_per_call | ||
| ) |
| diag | ( | "infix (Unbound): %.4f s (%.2f ns/call) -> Overhead: ~%.2f ns" | , |
| unbound_time | , | ||
| unbound_ns | , | ||
| unbound_ns - | direct_ns_per_call | ||
| ) |
| diag | ( | "infix Call Overhead Benchmark" | ) |
| diag | ( | "Iterations: %d" | , |
| BENCHMARK_ITERATIONS | |||
| ) |
| diag | ( | "Target function: int(int, int)" | ) |
| for | ( | ) |
| if | ( | infix_forward_create_manual(&,,, 2, 2, *void | add_for_benchmark | ) |
| if | ( | infix_forward_create_unbound_manual &,,, 2, 2arg_types ! | = INFIX_SUCCESS | ) |
| infix_forward_destroy | ( | bound_t | ) |
| infix_forward_destroy | ( | unbound_t | ) |
| note | ( | "dyncall benchmarking was not enabled." | ) |
| pass | ( | "Benchmark completed (final accumulator value: %d)" | , |
| accumulator | |||
| ) |
| volatile int accumulator = 0 |
| infix_type* arg_types[] |
| const int BENCHMARK_ITERATIONS = 10000000 |
| infix_cif_func bound_cif = infix_forward_get_code(bound_t) |
| double bound_ns = (bound_time / BENCHMARK_ITERATIONS) * 1e9 |
| infix_forward_t* bound_t = nullptr |
| double direct_ns_per_call = (direct_time / BENCHMARK_ITERATIONS) * 1e9 |
| end = clock() |
| infix_type* ret_type = infix_type_create_primitive(INFIX_PRIMITIVE_SINT32) |
| start = clock() |
| double unbound_ns = (unbound_time / BENCHMARK_ITERATIONS) * 1e9 |
| infix_forward_t* unbound_t = nullptr |