Repository navigation
perf(builtin): inline fast paths for slice access and pointer values - #531
Merged
Merged
Conversation
arrayIndex, sliceRange, sliceLen, pointerValue and copyElement are called for nearly every slice element access and pointer dereference, and each tried a long chain of representations. As large functions, engines did not inline them, so every element access in a hot loop was a call whose property loads saw every kind of slice in the program. Split each into a small fast path for the common representations (a window object, a typed slice or a plain array; a variable reference or a struct; a value that is not an object) and a slow function with the existing code for the others. V8 now inlines them into hot loops, where the window that sliceRange makes for an array also need not be allocated. In a benchmark of tensor element access (Cogent Lab tensor.Value with three indexes) under Node 26, an access takes 23 ns instead of 33 ns, plain indexing of a []int field in a loop 17 ns instead of 39 ns, and of a []float32 10 ns instead of 15 ns. Signed-off-by: Randall C. O'Reilly <oreilly@ucdavis.edu>
Contributor
Author
|
Pushed a second commit that gives sliceElems and sliceSlot, which element stores (including compound assignments) go through, the same fast-path split. A read-modify-write of a tensor element went from 34 ns to 29 ns in the same benchmark. Full Go suite, typecheck and vitest still pass. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
arrayIndex, sliceRange, sliceLen, pointerValue and copyElement are called for nearly every slice element access and pointer dereference, and each tried a long chain of representations. As large functions they were not inlined, so every element access in a hot loop was a call, and the property loads inside each helper saw every kind of slice in the program.
This splits each into a small fast path for the common representations (a window object, a typed slice or a plain array; a variable reference or a struct; a value that is not an object) and a slow function holding the existing code for everything else, unchanged. V8 now inlines them into hot loops (checked with --trace-turbo-inlining), where the window that sliceRange makes for a plain array also no longer needs to be allocated.
Measured on a tensor element-access benchmark (Cogent Lab tensor.Value with three indexes, as neural network simulations use for every neuron variable) under Node 26:
In the browser, one trial of an axon simulation (CPU profile in Chrome) went from 3.98 s to 3.26 s of compute.
The full Go test suite (including compliance) passes, as do the TypeScript type check and the vitest suite.