-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
src: stop copying code cache #47144
src: stop copying code cache #47144
Conversation
Review requested:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM % nits
For 2) I think we can just document in node.h that the snapshot data must outlive the isolate/Environment. That's already the case internally. |
I added a line about this to the documentation of |
src/node.h
Outdated
// The snapshot *must* be kept alive during the execution of the environment / | ||
// isolate that it is derived from. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// The snapshot *must* be kept alive during the execution of the environment / | |
// isolate that it is derived from. | |
// The snapshot *must* be kept alive during the execution of the Isolate | |
// that derives from it. |
or
// The snapshot *must* be kept alive during the execution of the environment / | |
// isolate that it is derived from. | |
// The snapshot *must* be kept alive during the execution of the Isolate | |
// that was created using it. |
(this header refers to Isolate
/Environment
as capitalized names to distinguish them from the regular English-language words; Environment
instances do not outlive their Isolate
instances; and the Isolate
derives from the snapshot in this scenario, not the other way around, since this is about the case in which the snapshot is being consumed, not when it is being built)
The code cache is quite large - around 1.3 MiB. Change the code to use non-owning buffers to avoid copying it. For starting up an otherwise empty main isolate, this saves around 1.3 MiB of unique set size memory (9.9 MiB -> 8.6 MiB) and 1.1ms elapsed time (22.9 ms -> 21.8 ms). Copying the code cache is unnecessary since: 1. for the builtin snapshot, the code cache data has static lifetime. 2. for non-builtin snapshots, we create copies of the code cache data in `SnapshotDeserializer::ReadVector`. These copies are owned by the `Environment` (through `IsolateData` -> `SnapshotData`), so they won't be deallocated. 3. a worker thread can copy a parent's isolate's code cache, but in that case we still know that the parent isolate will outlive the worker isolate. (Admittedly point (2) feels a little fragile from a lifetime perspective, and I would be happy to restrict this optimization to the builtin snapshot.) ```console $ perf stat -r 100 -e ... ./node -e 0 Performance counter stats for './node -e 0' (100 runs): 21.78 msec task-clock 2760 page-faults 113161604 instructions 18437648 branches 423230 branch-misses 853093 cache-references 41474 cache-misses 0.0225473 +- 0.0000504 seconds time elapsed ( +- 0.22% ) $ perf stat -r 100 -e ... ./node-main -e 0 Performance counter stats for './node-main -e 0' (100 runs): 22.91 msec task-clock 3102 page-faults 114890673 instructions 18751329 branches 428909 branch-misses 895721 cache-references 45202 cache-misses 0.0233760 +- 0.0000741 seconds time elapsed ( +- 0.32% ) ```
f4833ff
to
eb99a86
Compare
I reworded the comment to @addaleax's suggestion. Test failures look like obvious flakes. PTAL. |
Landed in 1e6e5a9 |
The code cache is quite large - around 1.3 MiB. Change the code to use non-owning buffers to avoid copying it. For starting up an otherwise empty main isolate, this saves around 1.3 MiB of unique set size memory (9.9 MiB -> 8.6 MiB) and 1.1ms elapsed time (22.9 ms -> 21.8 ms). Copying the code cache is unnecessary since: 1. for the builtin snapshot, the code cache data has static lifetime. 2. for non-builtin snapshots, we create copies of the code cache data in `SnapshotDeserializer::ReadVector`. These copies are owned by the `Environment` (through `IsolateData` -> `SnapshotData`), so they won't be deallocated. 3. a worker thread can copy a parent's isolate's code cache, but in that case we still know that the parent isolate will outlive the worker isolate. (Admittedly point (2) feels a little fragile from a lifetime perspective, and I would be happy to restrict this optimization to the builtin snapshot.) ```console $ perf stat -r 100 -e ... ./node -e 0 Performance counter stats for './node -e 0' (100 runs): 21.78 msec task-clock 2760 page-faults 113161604 instructions 18437648 branches 423230 branch-misses 853093 cache-references 41474 cache-misses 0.0225473 +- 0.0000504 seconds time elapsed ( +- 0.22% ) $ perf stat -r 100 -e ... ./node-main -e 0 Performance counter stats for './node-main -e 0' (100 runs): 22.91 msec task-clock 3102 page-faults 114890673 instructions 18751329 branches 428909 branch-misses 895721 cache-references 45202 cache-misses 0.0233760 +- 0.0000741 seconds time elapsed ( +- 0.32% ) ``` PR-URL: #47144 Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Chengzhong Wu <[email protected]>
The code cache is quite large - around 1.3 MiB. Change the code to use non-owning buffers to avoid copying it. For starting up an otherwise empty main isolate, this saves around 1.3 MiB of unique set size memory (9.9 MiB -> 8.6 MiB) and 1.1ms elapsed time (22.9 ms -> 21.8 ms).
Copying the code cache is unnecessary since:
SnapshotDeserializer::ReadVector
. These copies are owned by theEnvironment
(throughIsolateData
->SnapshotData
), so they won't be deallocated.(Admittedly point (2) feels a little fragile from a lifetime perspective, and I would be happy to restrict this optimization to the builtin snapshot.)