import ctypes
import reference_project as r
from reference_project import api
import time
N = 1_000_000
r.init_api("../../../../target/debug/interoptopus_reference_project.dll")
def bench(file, name, f, reference=0):
start = time.perf_counter()
for i in range(N):
f()
end = time.perf_counter()
nanos = (end - start) * 1000 * 1000 * 1000
nanos_per_single = (nanos / N) - reference
name = f"`{name}`"
print("|", name.ljust(50), "| {:,.0f} |".format(nanos_per_single), file=file)
return nanos_per_single
with open("BENCHMARK_RESULTS.md", 'w') as f:
print("""
# FFI Call Overheads
The numbers below are to help FFI design decisions by giving order-of-magnitude estimates how
expensive certain constructs are.
Times were determined by running the given construct 1M times, taking the elapsed time in ticks,
and computing the cost per 1k invocations.
## System
The following system was used:
```
System: i9-9900K, 32 GB RAM; Windows 10
rustc: stable (i.e., 1.53 or later)
profile: --release
Python: 3.10
```
## Results
| Construct | ns per call |
| --- | --- |""", file=f)
reference = bench(f, "empty", lambda: 0)
bench(f, "primitive_void()", lambda: r.api.primitive_void(), reference)
bench(f, "primitive_u8(0)", lambda: r.api.primitive_u8(0), reference)
bench(f, "primitive_u16(0)", lambda: r.api.primitive_u16(0), reference)
bench(f, "primitive_u32(0)", lambda: r.api.primitive_u32(0), reference)
bench(f, "primitive_u64(0)", lambda: r.api.primitive_u64(0), reference)
bench(f, "many_args_5(0, 0, 0, 0, 0)", lambda: r.api.many_args_5(0, 0, 0, 0, 0), reference)
bench(f, "tupled(r.Tupled())", lambda: r.api.tupled(r.Tupled()), reference)
bench(f, "callback(lambda x: x, 0)", lambda: r.api.callback(lambda x: x, 0), reference)