Overview

Here is a quick overview of the execution time of Koffi calls on three benchmarks, where it is compared to a theoretical ideal FFI implementation (approximated with pre-compiled static N-API glue code):

Linux x86_64 performance Windows x86_64 performance

These results are detailed and explained below, and compared to node-ffi/node-ffi-napi.

Linux x86_64

The results presented below were measured on my x86_64 Linux machine (Intel® Core™ Ultra 9 185H).

rand results

This test is based around repeated calls to a simple standard C function rand, and has three implementations:

rand Iteration time Relative performance Overhead
napi 256 ns x1.00 +0%
koffi 375 ns x0.68 +46%
node-ffi-napi 29783 ns x0.009 +11544%

Because rand is a pretty small function, the FFI overhead is clearly visible.

atoi results

This test is similar to the rand one, but it is based on atoi, which takes a string parameter. Javascript (V8) to C string conversion is relatively slow and heavy.

atoi Iteration time Relative performance Overhead
napi 371 ns x1.00 +0%
koffi 557 ns x0.67 +50%
node-ffi-napi 104340 ns x0.004 +27988%

Because atoi is a pretty small function, the FFI overhead is clearly visible.

Raylib results

This benchmark uses the CPU-based image drawing functions in Raylib. The calls are much heavier than in previous benchmarks, thus the FFI overhead is reduced. In this implementation, Koffi is compared to:

raylib Iteration time Relative performance Overhead
C++ 10.8 µs x1.14 -12%
node-raylib 12.3 µs x1.00 +0%
koffi 13.2 µs x0.92 +8%
node-ffi-napi 80.3 µs x0.15 +555%

Windows x86_64

The results presented below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460).

rand results

This test is based around repeated calls to a simple standard C function rand, and has three implementations:

rand Iteration time Relative performance Overhead
napi 859 ns x1.00 (ref)
koffi 1352 ns x0.64 +57%
node-ffi-napi 35640 ns x0.02 +4048%

Because rand is a pretty small function, the FFI overhead is clearly visible.

atoi results

This test is similar to the rand one, but it is based on atoi, which takes a string parameter. Javascript (V8) to C string conversion is relatively slow and heavy.

The results below were measured on my x86_64 Windows machine (Intel® Core™ i5-4460):

atoi Iteration time Relative performance Overhead
napi 1336 ns x1.00 (ref)
koffi 2440 ns x0.55 +83%
node-ffi-napi 136890 ns x0.010 +10144%

Because atoi is a pretty small function, the FFI overhead is clearly visible.

Raylib results

This benchmark uses the CPU-based image drawing functions in Raylib. The calls are much heavier than in the atoi benchmark, thus the FFI overhead is reduced. In this implementation, Koffi is compared to:

raylib Iteration time Relative performance Overhead
C++ 18.2 µs x1.50 -33%
node-raylib 27.3 µs x1.00 (ref)
koffi 29.8 µs x0.92 +9%
node-ffi-napi 96.3 µs x0.28 +253%

Running benchmarks

Please note that all benchmark results on this page are made with Clang-built binaries.

cd src/koffi
node ../cnoke/cnoke.js --clang --release

cd benchmark
node ../../cnoke/cnoke.js --clang --release

Once everything is built and ready, run:

node benchmark.js