mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
This patch changes the NativeModuleLoader to always try to find code cache for native modules when it compiles them, and always produce and store the code cache after compilation. The cache map is protected by a mutex and can be accessed by different threads - including the worker threads and the main thread. Hence any thread can reuse the code cache if the native module has already been compiled by another thread - in particular the cache of the bootstrappers and per_context.js will always be hit when a new thread is spun. This results in a ~6% startup overhead in the worst case (when only the main thread is launched without requiring any additional native module - it now needs to do the extra work of finding and storing caches), which balances out the recent improvements by moving the compilation to C++, but it also leads to a ~60% improvement in the best case (when a worker thread is spun and requires a lot of native modules thus hitting the cache compiled by the main thread). PR-URL: https://github.com/nodejs/node/pull/24950 Reviewed-By: Anna Henningsen <anna@addaleax.net>
75 lines
2.2 KiB
JavaScript
75 lines
2.2 KiB
JavaScript
'use strict';
|
|
|
|
// Flags: --expose-internals
|
|
// This test verifies that if the binary is compiled with code cache,
|
|
// and the cache is used when built in modules are compiled.
|
|
// Otherwise, verifies that no cache is used when compiling builtins.
|
|
|
|
require('../common');
|
|
const assert = require('assert');
|
|
const {
|
|
cachableBuiltins,
|
|
cannotUseCache
|
|
} = require('internal/bootstrap/cache');
|
|
const {
|
|
isMainThread
|
|
} = require('worker_threads');
|
|
|
|
const {
|
|
internalBinding
|
|
} = require('internal/test/binding');
|
|
const {
|
|
getCacheUsage
|
|
} = internalBinding('native_module');
|
|
|
|
for (const key of cachableBuiltins) {
|
|
if (!isMainThread && key === 'trace_events') {
|
|
continue; // Cannot load trace_events in workers
|
|
}
|
|
require(key);
|
|
}
|
|
|
|
// The computation has to be delayed until we have done loading modules
|
|
const {
|
|
compiledWithoutCache,
|
|
compiledWithCache
|
|
} = getCacheUsage();
|
|
|
|
const loadedModules = process.moduleLoadList
|
|
.filter((m) => m.startsWith('NativeModule'))
|
|
.map((m) => m.replace('NativeModule ', ''));
|
|
|
|
// The binary is not configured with code cache, verifies that the builtins
|
|
// are all compiled without cache and we are doing the bookkeeping right.
|
|
if (process.config.variables.node_code_cache_path === undefined) {
|
|
console.log('The binary is not configured with code cache');
|
|
if (isMainThread) {
|
|
assert.deepStrictEqual(compiledWithCache, new Set());
|
|
for (const key of loadedModules) {
|
|
assert(compiledWithoutCache.has(key),
|
|
`"${key}" should've been compiled without code cache`);
|
|
}
|
|
} else {
|
|
// TODO(joyeecheung): create a list of modules whose cache can be shared
|
|
// from the main thread to the worker thread and check that their
|
|
// cache are hit
|
|
assert.notDeepStrictEqual(compiledWithCache, new Set());
|
|
}
|
|
} else {
|
|
console.log('The binary is configured with code cache');
|
|
assert.strictEqual(
|
|
typeof process.config.variables.node_code_cache_path,
|
|
'string'
|
|
);
|
|
|
|
for (const key of loadedModules) {
|
|
if (cannotUseCache.includes(key)) {
|
|
assert(compiledWithoutCache.has(key),
|
|
`"${key}" should've been compiled without code cache`);
|
|
} else {
|
|
assert(compiledWithCache.has(key),
|
|
`"${key}" should've been compiled with code cache`);
|
|
}
|
|
}
|
|
}
|