mirror of
https://github.com/nodejs/node.git
synced 2024-11-30 07:27:22 +01:00
0858e5d9d8
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>
128 lines
3.3 KiB
JavaScript
128 lines
3.3 KiB
JavaScript
'use strict';
|
|
|
|
// Flags: --expose-internals
|
|
|
|
// This file generates the code cache for builtin modules and
|
|
// writes them into static char arrays of a C++ file that can be
|
|
// compiled into the binary using the `--code-cache-path` option
|
|
// of `configure`.
|
|
|
|
const {
|
|
getCodeCache,
|
|
compileFunction,
|
|
cachableBuiltins
|
|
} = require('internal/bootstrap/cache');
|
|
|
|
const {
|
|
types: {
|
|
isUint8Array
|
|
}
|
|
} = require('util');
|
|
|
|
const fs = require('fs');
|
|
|
|
const resultPath = process.argv[2];
|
|
if (!resultPath) {
|
|
console.error(`Usage: ${process.argv[0]} ${process.argv[1]}` +
|
|
'path/to/node_code_cache.cc');
|
|
process.exit(1);
|
|
}
|
|
|
|
/**
|
|
* Format a number of a size in bytes into human-readable strings
|
|
* @param {number} num
|
|
* @return {string}
|
|
*/
|
|
function formatSize(num) {
|
|
if (num < 1024) {
|
|
return `${(num).toFixed(2)}B`;
|
|
} else if (num < 1024 ** 2) {
|
|
return `${(num / 1024).toFixed(2)}KB`;
|
|
} else if (num < 1024 ** 3) {
|
|
return `${(num / (1024 ** 2)).toFixed(2)}MB`;
|
|
} else {
|
|
return `${(num / (1024 ** 3)).toFixed(2)}GB`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates the source code of definitions of the char arrays
|
|
* that contains the code cache and the source code of the
|
|
* initializers of the code cache.
|
|
*
|
|
* @param {string} key ID of the builtin module
|
|
* @param {Uint8Array} cache Code cache of the builtin module
|
|
* @return { definition: string, initializer: string }
|
|
*/
|
|
function getInitalizer(key, cache) {
|
|
const defName = `${key.replace(/\//g, '_').replace(/-/g, '_')}_raw`;
|
|
const definition = `static const uint8_t ${defName}[] = {\n` +
|
|
`${cache.join(',')}\n};`;
|
|
const dataDef = 'std::make_unique<v8::ScriptCompiler::CachedData>(' +
|
|
`${defName}, static_cast<int>(arraysize(${defName})), ` +
|
|
'policy)';
|
|
const initializer =
|
|
'code_cache_.emplace(\n' +
|
|
` "${key}",\n` +
|
|
` ${dataDef}\n` +
|
|
');';
|
|
return {
|
|
definition, initializer
|
|
};
|
|
}
|
|
|
|
const cacheDefinitions = [];
|
|
const cacheInitializers = [];
|
|
let totalCacheSize = 0;
|
|
|
|
function lexical(a, b) {
|
|
if (a < b) {
|
|
return -1;
|
|
}
|
|
if (a > b) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
for (const key of cachableBuiltins.sort(lexical)) {
|
|
compileFunction(key); // compile it
|
|
const cachedData = getCodeCache(key);
|
|
if (!isUint8Array(cachedData)) {
|
|
console.error(`Failed to generate code cache for '${key}'`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const size = cachedData.byteLength;
|
|
totalCacheSize += size;
|
|
const {
|
|
definition, initializer,
|
|
} = getInitalizer(key, cachedData);
|
|
cacheDefinitions.push(definition);
|
|
cacheInitializers.push(initializer);
|
|
console.log(`Generated cache for '${key}', size = ${formatSize(size)}` +
|
|
`, total = ${formatSize(totalCacheSize)}`);
|
|
}
|
|
|
|
const result = `#include "node_native_module.h"
|
|
#include "node_internals.h"
|
|
|
|
// This file is generated by tools/generate_code_cache.js
|
|
// and is used when configure is run with \`--code-cache-path\`
|
|
|
|
namespace node {
|
|
namespace native_module {
|
|
${cacheDefinitions.join('\n\n')}
|
|
|
|
void NativeModuleLoader::LoadCodeCache() {
|
|
auto policy = v8::ScriptCompiler::CachedData::BufferPolicy::BufferNotOwned;
|
|
${cacheInitializers.join('\n ')}
|
|
}
|
|
|
|
} // namespace native_module
|
|
} // namespace node
|
|
`;
|
|
|
|
fs.writeFileSync(resultPath, result);
|
|
console.log(`Generated code cache C++ file to ${resultPath}`);
|