Skip to content

Commit 6d678be

Browse files
committed
benchmark: add FFI function preparation benchmark
Signed-off-by: umuoy1 <burningdian@gmail.com>
1 parent f4d2a52 commit 6d678be

1 file changed

Lines changed: 76 additions & 0 deletions

File tree

‎benchmark/ffi/prepare-function.js‎

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
'use strict';
2+
3+
const assert = require('node:assert');
4+
const common = require('../common.js');
5+
const { libraryPath, ensureFixtureLibrary } = require('./common.js');
6+
7+
// On x86-64 System V, cover both a register-only plan and one with stack-spilled
8+
// arguments. Both signatures bypass the V8 Fast API so trampoline allocation
9+
// does not dominate function preparation.
10+
const signatures = {
11+
call_int_callback: {
12+
return: 'i32',
13+
arguments: ['function', 'i32'],
14+
},
15+
sum_8_i32: {
16+
return: 'i32',
17+
arguments: [
18+
'i32', 'i32', 'i32', 'i32',
19+
'i32', 'i32', 'i32', 'i32',
20+
],
21+
},
22+
};
23+
24+
const bench = common.createBenchmark(main, {
25+
n: [1e4],
26+
symbol: Object.keys(signatures),
27+
}, {
28+
flags: ['--experimental-ffi', '--expose-gc', '--no-warnings'],
29+
});
30+
31+
ensureFixtureLibrary();
32+
33+
function main({ n, symbol }) {
34+
const ffi = require('node:ffi');
35+
const signature = signatures[symbol];
36+
37+
// Exclude one-time V8 template initialization from the measurement.
38+
{
39+
const library = new ffi.DynamicLibrary(libraryPath);
40+
try {
41+
library.getFunction(symbol, signature);
42+
} finally {
43+
library.close();
44+
}
45+
}
46+
47+
const libraries = new Array(n);
48+
const functions = new Array(n);
49+
50+
try {
51+
// Each library has its own function cache. Resolve symbols before timing so
52+
// the measured work starts at signature parsing and function preparation.
53+
for (let i = 0; i < n; i++) {
54+
const library = new ffi.DynamicLibrary(libraryPath);
55+
libraries[i] = library;
56+
library.getSymbol(symbol);
57+
}
58+
59+
// Avoid carrying garbage from setup into the measured window.
60+
globalThis.gc();
61+
62+
bench.start();
63+
for (let i = 0; i < n; i++) {
64+
functions[i] = libraries[i].getFunction(symbol, signature);
65+
}
66+
bench.end(n);
67+
68+
assert.strictEqual(typeof functions[n - 1], 'function');
69+
} finally {
70+
for (let i = 0; i < n; i++) {
71+
libraries[i]?.close();
72+
}
73+
74+
functions.fill(null);
75+
}
76+
}

0 commit comments

Comments
 (0)