aboutsummaryrefslogtreecommitdiff
path: root/bench/ffi
diff options
context:
space:
mode:
Diffstat (limited to 'bench/ffi')
-rw-r--r--bench/ffi/ffi-overhead.js106
-rw-r--r--bench/ffi/noop.c6
-rwxr-xr-xbench/ffi/noop.dylibbin16759 -> 16759 bytes
-rw-r--r--bench/ffi/noop.js5
-rw-r--r--bench/ffi/plus100/.gitignore1
-rw-r--r--bench/ffi/plus100/README.md27
-rw-r--r--bench/ffi/plus100/download-napi-plus100.sh7
-rwxr-xr-xbench/ffi/plus100/libadd.dylibbin0 -> 396768 bytes
-rw-r--r--bench/ffi/plus100/package.json12
-rw-r--r--bench/ffi/plus100/plus100.bun.js19
-rw-r--r--bench/ffi/plus100/plus100.c6
-rw-r--r--bench/ffi/plus100/plus100.deno.js18
-rwxr-xr-xbench/ffi/plus100/plus100.dylibbin0 -> 16778 bytes
-rw-r--r--bench/ffi/plus100/plus100.napi.mjs10
14 files changed, 158 insertions, 59 deletions
diff --git a/bench/ffi/ffi-overhead.js b/bench/ffi/ffi-overhead.js
index 841c59992..4f63cebe5 100644
--- a/bench/ffi/ffi-overhead.js
+++ b/bench/ffi/ffi-overhead.js
@@ -12,221 +12,221 @@ import { bench, group, run } from "mitata";
const types = {
returns_true: {
- return_type: "bool",
+ returns: "bool",
args: [],
},
returns_false: {
- return_type: "bool",
+ returns: "bool",
args: [],
},
returns_42_char: {
- return_type: "char",
+ returns: "char",
args: [],
},
// returns_42_float: {
- // return_type: "float",
+ // returns: "float",
// args: [],
// },
// returns_42_double: {
- // return_type: "double",
+ // returns: "double",
// args: [],
// },
returns_42_uint8_t: {
- return_type: "uint8_t",
+ returns: "uint8_t",
args: [],
},
returns_neg_42_int8_t: {
- return_type: "int8_t",
+ returns: "int8_t",
args: [],
},
returns_42_uint16_t: {
- return_type: "uint16_t",
+ returns: "uint16_t",
args: [],
},
returns_42_uint32_t: {
- return_type: "uint32_t",
+ returns: "uint32_t",
args: [],
},
// // returns_42_uint64_t: {
- // // return_type: "uint64_t",
+ // // returns: "uint64_t",
// // args: [],
// // },
returns_neg_42_int16_t: {
- return_type: "int16_t",
+ returns: "int16_t",
args: [],
},
returns_neg_42_int32_t: {
- return_type: "int32_t",
+ returns: "int32_t",
args: [],
},
// returns_neg_42_int64_t: {
- // return_type: "int64_t",
+ // returns: "int64_t",
// args: [],
// },
identity_char: {
- return_type: "char",
+ returns: "char",
args: ["char"],
},
// identity_float: {
- // return_type: "float",
+ // returns: "float",
// args: ["float"],
// },
identity_bool: {
- return_type: "bool",
+ returns: "bool",
args: ["bool"],
},
// identity_double: {
- // return_type: "double",
+ // returns: "double",
// args: ["double"],
// },
identity_int8_t: {
- return_type: "int8_t",
+ returns: "int8_t",
args: ["int8_t"],
},
identity_int16_t: {
- return_type: "int16_t",
+ returns: "int16_t",
args: ["int16_t"],
},
identity_int32_t: {
- return_type: "int32_t",
+ returns: "int32_t",
args: ["int32_t"],
},
// identity_int64_t: {
- // return_type: "int64_t",
+ // returns: "int64_t",
// args: ["int64_t"],
// },
identity_uint8_t: {
- return_type: "uint8_t",
+ returns: "uint8_t",
args: ["uint8_t"],
},
identity_uint16_t: {
- return_type: "uint16_t",
+ returns: "uint16_t",
args: ["uint16_t"],
},
identity_uint32_t: {
- return_type: "uint32_t",
+ returns: "uint32_t",
args: ["uint32_t"],
},
// identity_uint64_t: {
- // return_type: "uint64_t",
+ // returns: "uint64_t",
// args: ["uint64_t"],
// },
add_char: {
- return_type: "char",
+ returns: "char",
args: ["char", "char"],
},
add_float: {
- return_type: "float",
+ returns: "float",
args: ["float", "float"],
},
add_double: {
- return_type: "double",
+ returns: "double",
args: ["double", "double"],
},
add_int8_t: {
- return_type: "int8_t",
+ returns: "int8_t",
args: ["int8_t", "int8_t"],
},
add_int16_t: {
- return_type: "int16_t",
+ returns: "int16_t",
args: ["int16_t", "int16_t"],
},
add_int32_t: {
- return_type: "int32_t",
+ returns: "int32_t",
args: ["int32_t", "int32_t"],
},
// add_int64_t: {
- // return_type: "int64_t",
+ // returns: "int64_t",
// args: ["int64_t", "int64_t"],
// },
add_uint8_t: {
- return_type: "uint8_t",
+ returns: "uint8_t",
args: ["uint8_t", "uint8_t"],
},
add_uint16_t: {
- return_type: "uint16_t",
+ returns: "uint16_t",
args: ["uint16_t", "uint16_t"],
},
add_uint32_t: {
- return_type: "uint32_t",
+ returns: "uint32_t",
args: ["uint32_t", "uint32_t"],
},
does_pointer_equal_42_as_int32_t: {
- return_type: "bool",
+ returns: "bool",
args: ["ptr"],
},
ptr_should_point_to_42_as_int32_t: {
- return_type: "ptr",
+ returns: "ptr",
args: [],
},
identity_ptr: {
- return_type: "ptr",
+ returns: "ptr",
args: ["ptr"],
},
// add_uint64_t: {
- // return_type: "uint64_t",
+ // returns: "uint64_t",
// args: ["uint64_t", "uint64_t"],
// },
cb_identity_true: {
- return_type: "bool",
+ returns: "bool",
args: ["ptr"],
},
cb_identity_false: {
- return_type: "bool",
+ returns: "bool",
args: ["ptr"],
},
cb_identity_42_char: {
- return_type: "char",
+ returns: "char",
args: ["ptr"],
},
// cb_identity_42_float: {
- // return_type: "float",
+ // returns: "float",
// args: ["ptr"],
// },
// cb_identity_42_double: {
- // return_type: "double",
+ // returns: "double",
// args: ["ptr"],
// },
cb_identity_42_uint8_t: {
- return_type: "uint8_t",
+ returns: "uint8_t",
args: ["ptr"],
},
cb_identity_neg_42_int8_t: {
- return_type: "int8_t",
+ returns: "int8_t",
args: ["ptr"],
},
cb_identity_42_uint16_t: {
- return_type: "uint16_t",
+ returns: "uint16_t",
args: ["ptr"],
},
cb_identity_42_uint32_t: {
- return_type: "uint32_t",
+ returns: "uint32_t",
args: ["ptr"],
},
// cb_identity_42_uint64_t: {
- // return_type: "uint64_t",
+ // returns: "uint64_t",
// args: ["ptr"],
// },
cb_identity_neg_42_int16_t: {
- return_type: "int16_t",
+ returns: "int16_t",
args: ["ptr"],
},
cb_identity_neg_42_int32_t: {
- return_type: "int32_t",
+ returns: "int32_t",
args: ["ptr"],
},
// cb_identity_neg_42_int64_t: {
- // return_type: "int64_t",
+ // returns: "int64_t",
// args: ["ptr"],
// },
return_a_function_ptr_to_function_that_returns_true: {
- return_type: "ptr",
+ returns: "ptr",
args: [],
},
};
diff --git a/bench/ffi/noop.c b/bench/ffi/noop.c
index 6b93beeaf..de15eb5e0 100644
--- a/bench/ffi/noop.c
+++ b/bench/ffi/noop.c
@@ -1,5 +1,5 @@
-// clang -O3 -shared -undefined dynamic_lookup ./noop.c -o noop.dylib
+// clang -O3 -shared -mtune=native ./noop.c -o noop.dylib
-int noop();
+void noop();
-int noop() { return 1; } \ No newline at end of file
+void noop() {} \ No newline at end of file
diff --git a/bench/ffi/noop.dylib b/bench/ffi/noop.dylib
index 74a1d3155..66c00c17c 100755
--- a/bench/ffi/noop.dylib
+++ b/bench/ffi/noop.dylib
Binary files differ
diff --git a/bench/ffi/noop.js b/bench/ffi/noop.js
index e28ea0629..13c8aef28 100644
--- a/bench/ffi/noop.js
+++ b/bench/ffi/noop.js
@@ -6,11 +6,10 @@ const {
} = dlopen("./noop.dylib", {
noop: {
args: [],
- return_type: "i32",
+ returns: "void",
},
});
-var raw = Object.keys(noop);
bench("noop", () => {
- raw();
+ noop();
});
run({ collect: false, percentiles: true });
diff --git a/bench/ffi/plus100/.gitignore b/bench/ffi/plus100/.gitignore
new file mode 100644
index 000000000..8911651ed
--- /dev/null
+++ b/bench/ffi/plus100/.gitignore
@@ -0,0 +1 @@
+./napi-plus100
diff --git a/bench/ffi/plus100/README.md b/bench/ffi/plus100/README.md
new file mode 100644
index 000000000..418e7bd34
--- /dev/null
+++ b/bench/ffi/plus100/README.md
@@ -0,0 +1,27 @@
+## FFI overhead comparison
+
+This compares the cost of a simple function call going from JavaScript to native code and back in:
+
+- Bun v0.0.79
+- napi.rs (Node v17.7.1)
+- Deno v1.21.1
+
+To set up:
+
+```bash
+bun setup
+```
+
+To run the benchmark:
+
+```bash
+bun bench
+```
+
+| Overhead | Using | Version | Platform |
+| -------- | ------- | ------- | --------------- |
+| 7ns | bun:ffi | 0.0.79 | macOS (aarch64) |
+| 18ns | napi.rs | 17.7.1 | macOS (aarch64) |
+| 580ns | Deno | 1.21.1 | macOS (aarch64) |
+
+The native [function](./plus100.c) called in Deno & Bun are the same. The function called with napi.rs is from napi's official [package-template](https://github.com/napi-rs/package-template)
diff --git a/bench/ffi/plus100/download-napi-plus100.sh b/bench/ffi/plus100/download-napi-plus100.sh
new file mode 100644
index 000000000..9cd226857
--- /dev/null
+++ b/bench/ffi/plus100/download-napi-plus100.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+rm -rf plus100-napi
+git clone https://github.com/napi-rs/package-template plus100-napi --depth=1
+cd plus100-napi
+npm install
+npm run build
diff --git a/bench/ffi/plus100/libadd.dylib b/bench/ffi/plus100/libadd.dylib
new file mode 100755
index 000000000..a2a1039ee
--- /dev/null
+++ b/bench/ffi/plus100/libadd.dylib
Binary files differ
diff --git a/bench/ffi/plus100/package.json b/bench/ffi/plus100/package.json
new file mode 100644
index 000000000..ba7ef1fd7
--- /dev/null
+++ b/bench/ffi/plus100/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "plus100",
+ "scripts": {
+ "setup": "bun run napi-setup && bun run compile",
+ "bench-deno": "deno run --allow-ffi --unstable -A plus100.deno.js",
+ "napi-setup": "bash download-napi-plus100.sh",
+ "bench-napi": "node plus100.napi.mjs",
+ "bench-bun": "bun run ./plus100.bun.js",
+ "compile": "clang -mtune=native -O3 -shared ./plus100.c -o plus100.dylib",
+ "bench": "echo -e '\n--- Bun:\n' && bun run bench-bun && echo -e '\n--- Node:\n' && bun run bench-napi && echo -e '\n--- Deno:\n' && bun run bench-deno"
+ }
+}
diff --git a/bench/ffi/plus100/plus100.bun.js b/bench/ffi/plus100/plus100.bun.js
new file mode 100644
index 000000000..ca4bf0f64
--- /dev/null
+++ b/bench/ffi/plus100/plus100.bun.js
@@ -0,0 +1,19 @@
+import { run, bench, group, baseline } from "mitata";
+import { dlopen } from "bun:ffi";
+
+const {
+ symbols: { plus100: plus100 },
+ close,
+} = dlopen("./plus100.dylib", {
+ plus100: {
+ params: ["int32_t"],
+ returns: "int32_t",
+ },
+});
+bench("plus100(1) (Bun FFI)", () => {
+ plus100(1);
+});
+
+// collect option collects benchmark returned values into array
+// prevents gc and can help with jit optimizing out functions
+run({ collect: false, percentiles: true });
diff --git a/bench/ffi/plus100/plus100.c b/bench/ffi/plus100/plus100.c
new file mode 100644
index 000000000..c5b7933ea
--- /dev/null
+++ b/bench/ffi/plus100/plus100.c
@@ -0,0 +1,6 @@
+// clang -mtune=native -O3 -shared ./plus100.c -o plus100.dylib
+#include <stdint.h>
+
+int32_t plus100(int32_t a);
+
+int32_t plus100(int32_t a) { return a + 100; }
diff --git a/bench/ffi/plus100/plus100.deno.js b/bench/ffi/plus100/plus100.deno.js
new file mode 100644
index 000000000..e6104efdd
--- /dev/null
+++ b/bench/ffi/plus100/plus100.deno.js
@@ -0,0 +1,18 @@
+import { run, bench, group, baseline } from "https://esm.sh/mitata";
+
+const {
+ symbols: { plus100: plus100 },
+ close,
+} = Deno.dlopen("./plus100.dylib", {
+ plus100: {
+ parameters: ["i32"],
+ result: "i32",
+ },
+});
+bench("plus100(1) (Deno FFI)", () => {
+ plus100(1);
+});
+
+// collect option collects benchmark returned values into array
+// prevents gc and can help with jit optimizing out functions
+run({ collect: false, percentiles: true });
diff --git a/bench/ffi/plus100/plus100.dylib b/bench/ffi/plus100/plus100.dylib
new file mode 100755
index 000000000..030d1afef
--- /dev/null
+++ b/bench/ffi/plus100/plus100.dylib
Binary files differ
diff --git a/bench/ffi/plus100/plus100.napi.mjs b/bench/ffi/plus100/plus100.napi.mjs
new file mode 100644
index 000000000..f4adda8d3
--- /dev/null
+++ b/bench/ffi/plus100/plus100.napi.mjs
@@ -0,0 +1,10 @@
+import { bench, run } from "mitata";
+
+import module from "module";
+
+const { plus100 } = module.createRequire(import.meta.url)("./plus100-napi");
+
+bench("plus100(1) (napi.rs)", () => {
+ plus100(1);
+});
+run({ collect: false, percentiles: true });