From 2219fef14e3634b2d878ec906ee68bf01139d07a Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 8 May 2024 01:48:58 +0200 Subject: [PATCH 1/3] fix: remove heap allocation for startup snapshot where possible MONGOSH-1771 --- .evergreen.yml | 4 ++-- .github/workflows/nodejs.yml | 2 +- resources/main-template.cc | 23 +++++++++++++++++++---- src/helpers.ts | 13 +++++++++++++ test/index.ts | 2 +- 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/.evergreen.yml b/.evergreen.yml index 4f13b43..a0edaa6 100644 --- a/.evergreen.yml +++ b/.evergreen.yml @@ -14,7 +14,7 @@ functions: set -e set -x - export NODE_VERSION=20.5.0 + export NODE_VERSION=20.13.0 bash .evergreen/install-node.sh install: - command: shell.exec @@ -106,7 +106,7 @@ tasks: - func: install - func: test vars: - node_version: "20.5.0" + node_version: "20.13.0" - name: check commands: - func: checkout diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index bc4e2ce..293c59b 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -13,7 +13,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - node-version: [14.x, 16.x, 18.x, 19.x] + node-version: [14.x, 16.x, 18.x, 20.x] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 diff --git a/resources/main-template.cc b/resources/main-template.cc index 6aa297a..32955f0 100644 --- a/resources/main-template.cc +++ b/resources/main-template.cc @@ -18,6 +18,7 @@ #include #endif #include // injected code may refer to std::underlying_type +#include using namespace node; using namespace v8; @@ -34,6 +35,12 @@ using namespace v8; #define NODE_VERSION_SUPPORTS_EMBEDDER_SNAPSHOT 1 #endif +// 20.13.0 has https://github.com/nodejs/node/pull/52595 for better startup snapshot +// initialization performance. +#if NODE_VERSION_AT_LEAST(20, 13, 0) +#define NODE_VERSION_SUPPORTS_STRING_VIEW_SNAPSHOT 1 +#endif + // Snapshot config is supported since https://github.com/nodejs/node/pull/50453 #if NODE_VERSION_AT_LEAST(20, 12, 0) && !defined(BOXEDNODE_SNAPSHOT_CONFIG_FLAGS) #define BOXEDNODE_SNAPSHOT_CONFIG_FLAGS (SnapshotFlags::kWithoutCodeCache) @@ -81,6 +88,7 @@ void MarkTime(const char* category, const char* label) { Local GetBoxednodeMainScriptSource(Isolate* isolate); Local GetBoxednodeCodeCacheBuffer(Isolate* isolate); std::vector GetBoxednodeSnapshotBlobVector(); +std::optional GetBoxednodeSnapshotBlobSV(); void GetTimingData(const FunctionCallbackInfo& info) { Isolate* isolate = info.GetIsolate(); @@ -230,11 +238,18 @@ static int RunNodeInstance(MultiIsolatePlatform* platform, ArrayBufferAllocator::Create(); #ifdef BOXEDNODE_CONSUME_SNAPSHOT - std::vector snapshot_blob_vec = boxednode::GetBoxednodeSnapshotBlobVector(); - boxednode::MarkTime("Node.js Instance", "Decoded snapshot"); assert(EmbedderSnapshotData::CanUseCustomSnapshotPerIsolate()); - node::EmbedderSnapshotData::Pointer snapshot_blob = - EmbedderSnapshotData::FromBlob(snapshot_blob_vec); + node::EmbedderSnapshotData::Pointer snapshot_blob; +#ifdef NODE_VERSION_SUPPORTS_STRING_VIEW_SNAPSHOT + if (const auto snapshot_blob_sv = boxednode::GetBoxednodeSnapshotBlobSV()) { + snapshot_blob = EmbedderSnapshotData::FromBlob(snapshot_blob_sv.value()); + } +#endif + if (!snapshot_blob) { + std::vector snapshot_blob_vec = boxednode::GetBoxednodeSnapshotBlobVector(); + boxednode::MarkTime("Node.js Instance", "Decoded snapshot"); + snapshot_blob = EmbedderSnapshotData::FromBlob(snapshot_blob_vec); + } boxednode::MarkTime("Node.js Instance", "Read snapshot"); Isolate* isolate = NewIsolate(allocator, loop, platform, snapshot_blob.get()); #elif NODE_VERSION_AT_LEAST(14, 0, 0) diff --git a/src/helpers.ts b/src/helpers.ts index cee4fc5..38907f7 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -113,6 +113,15 @@ export async function createUncompressedBlobDefinition (fnName: string, source: ${Uint8Array.prototype.toString.call(source) || '0'} }; + std::optional ${fnName}SV() { + return { + { + reinterpret_cast(&${fnName}_source_[0]), + ${source.length} + } + }; + } + std::vector ${fnName}Vector() { return std::vector( reinterpret_cast(&${fnName}_source_[0]), @@ -155,6 +164,10 @@ export async function createCompressedBlobDefinition (fnName: string, source: Ui return dst;`} } + std::optional ${fnName}SV() { + return {}; + } + ${blobTypedArrayAccessors(fnName, source.length)} `; } diff --git a/test/index.ts b/test/index.ts index 723db64..8f0c60e 100644 --- a/test/index.ts +++ b/test/index.ts @@ -218,7 +218,7 @@ describe('basic functionality', () => { it(`works with snapshot support (compressBlobs = ${compressBlobs})`, async function () { this.timeout(2 * 60 * 60 * 1000); // 2 hours await compileJSFileAsBinary({ - nodeVersionRange: '^21.6.2', + nodeVersionRange: '^22.1.0', sourceFile: path.resolve(__dirname, 'resources/snapshot-echo-args.js'), targetFile: path.resolve(__dirname, `resources/snapshot-echo-args${exeSuffix}`), useNodeSnapshot: true, From 7ca80152d35daf3751381fa890c399ab09b29305 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 8 May 2024 10:47:21 +0200 Subject: [PATCH 2/3] ... --- test/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/index.ts b/test/index.ts index 8f0c60e..f0fafbf 100644 --- a/test/index.ts +++ b/test/index.ts @@ -218,7 +218,7 @@ describe('basic functionality', () => { it(`works with snapshot support (compressBlobs = ${compressBlobs})`, async function () { this.timeout(2 * 60 * 60 * 1000); // 2 hours await compileJSFileAsBinary({ - nodeVersionRange: '^22.1.0', + nodeVersionRange: '^20.13.0', sourceFile: path.resolve(__dirname, 'resources/snapshot-echo-args.js'), targetFile: path.resolve(__dirname, `resources/snapshot-echo-args${exeSuffix}`), useNodeSnapshot: true, From 33807086c8fac357a95d5b855c1b17eaae64e727 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Wed, 8 May 2024 12:37:47 +0200 Subject: [PATCH 3/3] ... --- resources/main-template.cc | 2 ++ src/helpers.ts | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/resources/main-template.cc b/resources/main-template.cc index 32955f0..c63b118 100644 --- a/resources/main-template.cc +++ b/resources/main-template.cc @@ -88,7 +88,9 @@ void MarkTime(const char* category, const char* label) { Local GetBoxednodeMainScriptSource(Isolate* isolate); Local GetBoxednodeCodeCacheBuffer(Isolate* isolate); std::vector GetBoxednodeSnapshotBlobVector(); +#ifdef NODE_VERSION_SUPPORTS_STRING_VIEW_SNAPSHOT std::optional GetBoxednodeSnapshotBlobSV(); +#endif void GetTimingData(const FunctionCallbackInfo& info) { Isolate* isolate = info.GetIsolate(); diff --git a/src/helpers.ts b/src/helpers.ts index 38907f7..2b14801 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -113,6 +113,7 @@ export async function createUncompressedBlobDefinition (fnName: string, source: ${Uint8Array.prototype.toString.call(source) || '0'} }; +#ifdef NODE_VERSION_SUPPORTS_STRING_VIEW_SNAPSHOT std::optional ${fnName}SV() { return { { @@ -121,6 +122,7 @@ export async function createUncompressedBlobDefinition (fnName: string, source: } }; } +#endif std::vector ${fnName}Vector() { return std::vector( @@ -164,9 +166,11 @@ export async function createCompressedBlobDefinition (fnName: string, source: Ui return dst;`} } +#ifdef NODE_VERSION_SUPPORTS_STRING_VIEW_SNAPSHOT std::optional ${fnName}SV() { return {}; } +#endif ${blobTypedArrayAccessors(fnName, source.length)} `;