Commit 4c14b9f58a0 for nodejs

commit 4c14b9f58a01dec9ae9586a03a3615ea73d02d32
Author: Donghoon Kang <d159123@naver.com>
Date:   Tue Oct 20 11:50:14 2026 +0900

    ffi: add getFunction cache-miss benchmark

    The existing get-function benchmark reuses the callable cached during
    warmup, so it no longer measures trampoline creation.

    Add a cache-miss benchmark that resolves a function once per library
    instance. Construct the instances before timing to exclude library
    loading while including symbol resolution, signature preparation,
    and callable creation.

    Update the existing benchmark comments to describe cache-hit lookups.

    Signed-off-by: HoonDongKang <d159123@naver.com>
    Assisted-by: Codex:Astra-medium
    PR-URL: https://github.com/nodejs/node/pull/66456
    Refs: https://github.com/nodejs/node/pull/64969
    Refs: https://github.com/nodejs/node/pull/64971
    Reviewed-By: Anna Henningsen <anna@addaleax.net>
    Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>

diff --git a/benchmark/ffi/get-function-cache-miss.js b/benchmark/ffi/get-function-cache-miss.js
new file mode 100644
index 00000000000..9cb559c6ecb
--- /dev/null
+++ b/benchmark/ffi/get-function-cache-miss.js
@@ -0,0 +1,48 @@
+'use strict';
+
+// Measures the first getFunction() call on each library instance. This includes
+// symbol resolution, signature preparation, and callable creation.
+// The `fast` variant is eligible for a generated trampoline on supported
+// platforms; `slow` exceeds the x86_64 register budget and falls back.
+// Library construction and closing are outside the measured region.
+
+const common = require('../common.js');
+const { DynamicLibrary } = require('node:ffi');
+const { libraryPath, ensureFixtureLibrary } = require('./common.js');
+
+const bench = common.createBenchmark(main, {
+  signature: ['fast', 'slow'],
+  n: [1e3],
+});
+
+ensureFixtureLibrary();
+
+const signatures = {
+  fast: { name: 'add_i32', return: 'i32', arguments: ['i32', 'i32'] },
+  slow: {
+    name: 'sum_8_i32',
+    return: 'i32',
+    arguments: ['i32', 'i32', 'i32', 'i32', 'i32', 'i32', 'i32', 'i32'],
+  },
+};
+
+function main({ n, signature }) {
+  const { name, ...definition } = signatures[signature];
+
+  // Warm up one-time initialization without populating the measured caches.
+  const warmup = new DynamicLibrary(libraryPath);
+  warmup.getFunction(name, definition);
+  warmup.close();
+
+  // Each instance has its own cache, so its first lookup creates a callable.
+  const libraries = Array.from({ length: n }, () => new DynamicLibrary(libraryPath));
+  const functions = new Array(n);
+
+  bench.start();
+  for (let i = 0; i < n; ++i)
+    functions[i] = libraries[i].getFunction(name, definition);
+  bench.end(n);
+
+  for (const lib of libraries)
+    lib.close();
+}
diff --git a/benchmark/ffi/get-function.js b/benchmark/ffi/get-function.js
index 939c1630ab6..7b885f1c6bd 100644
--- a/benchmark/ffi/get-function.js
+++ b/benchmark/ffi/get-function.js
@@ -1,13 +1,9 @@
 'use strict';

-// Measures symbol resolution rather than call throughput. Creating a callable
-// for a fast-eligible signature emits a native trampoline, so this benchmark
-// covers the trampoline allocation path that the call benchmarks never reach.
-//
-// The `fast` variant is eligible for a generated trampoline; `slow` exceeds the
-// x86_64 register budget and falls back, so it resolves without allocating one.
-// Comparing the two isolates trampoline creation cost from the rest of symbol
-// resolution.
+// Measures repeated getFunction() calls with a cached callable rather than
+// call throughput. The warmup populates the cache for the measured symbol.
+// See get-function-cache-miss.js for first-time resolution, including trampoline
+// creation for fast-eligible signatures on supported platforms.

 const common = require('../common.js');
 const { DynamicLibrary } = require('node:ffi');
@@ -33,8 +29,7 @@ function main({ n, signature }) {
   const { name, ...definition } = signatures[signature];
   const lib = new DynamicLibrary(libraryPath);

-  // Warm up one-time initialization (libffi setup, executable memory probe) so
-  // it is not attributed to the measured resolutions.
+  // Populate the callable cache before measuring repeated lookups.
   lib.getFunction(name, definition);

   bench.start();