-
-
Notifications
You must be signed in to change notification settings - Fork 33.8k
src: stop copying code cache #47144
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
Conversation
|
Review requested:
|
joyeecheung
left a comment
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.)