Skip to content
This repository was archived by the owner on Dec 3, 2022. It is now read-only.

Conversation

@jridgewell
Copy link
Contributor

@jridgewell jridgewell commented Jul 9, 2019

Thinking of #74, I decided to see what v8 would use as the capacity of the segment arrays. Surprisingly, after pushing the first element into a new array, the array's internal capacity expands to 17 elements! For us, that's ~68 wasted bytes!

Debug printing an array's capacity
$ ~/.jsvu/v8-debug --allow-natives-syntax V8 version 7.7.185 d8> segment = [] [] d8> %DebugPrint(segment) DebugPrint: 0x34aee65cb2b9: [JSArray] - map: 0x34ae80c82e89 <Map(PACKED_SMI_ELEMENTS)> [FastProperties] - prototype: 0x34ae41b11859 <JSArray[0]> - elements: 0x34ae57ec0c21 <FixedArray[0]> [PACKED_SMI_ELEMENTS] - length: 0 - properties: 0x34ae57ec0c21 <FixedArray[0]> { #length: 0x34ae489801a9 <AccessorInfo> (const accessor descriptor) } ... d8> segment.push(0) 1 d8> %DebugPrint(segment) DebugPrint: 0x34aee65cb2b9: [JSArray] - map: 0x34ae80c82e89 <Map(PACKED_SMI_ELEMENTS)> [FastProperties] - prototype: 0x34ae41b11859 <JSArray[0]> - elements: 0x34aee65cdd29 <FixedArray[17]> [PACKED_SMI_ELEMENTS] - length: 1 - properties: 0x34ae57ec0c21 <FixedArray[0]> { #length: 0x34ae489801a9 <AccessorInfo> (const accessor descriptor) } - elements: 0x34aee65cdd29 <FixedArray[17]> { 0: 0 1-16: 0x34ae57ec05b1 <the_hole> } ... 

If we instead create fresh array literals, we get arrays with no excess internal capacity.

Pushing array literal constructed from an array elements
V8 version 7.7.185 d8> segment = [1, 2, 3, 4, 5] [1, 2, 3, 4, 5] d8> %DebugPrint([ segment[0] ]) DebugPrint: 0x482e084d851: [JSArray] - map: 0x04824efc2e89 <Map(PACKED_SMI_ELEMENTS)> [FastProperties] - prototype: 0x04822fb51859 <JSArray[0]> - elements: 0x0482e084d839 <FixedArray[1]> [PACKED_SMI_ELEMENTS] - length: 1 - properties: 0x04821a780c21 <FixedArray[0]> { #length: 0x0482375001a9 <AccessorInfo> (const accessor descriptor) } - elements: 0x0482e084d839 <FixedArray[1]> { 0: 1 } d8> %DebugPrint([ segment[0], segment[1], segment[2], segment[3] ]) DebugPrint: 0x482e084daa1: [JSArray] - map: 0x04824efc2e89 <Map(PACKED_SMI_ELEMENTS)> [FastProperties] - prototype: 0x04822fb51859 <JSArray[0]> - elements: 0x0482e084da71 <FixedArray[4]> [PACKED_SMI_ELEMENTS] - length: 4 - properties: 0x04821a780c21 <FixedArray[0]> { #length: 0x0482375001a9 <AccessorInfo> (const accessor descriptor) } - elements: 0x0482e084da71 <FixedArray[4]> { 0: 1 1: 2 2: 3 3: 4 } 

This gets us a ~30% boost in performance (and there's not a good framework for memory benchmarks, but I imagine it's massive):

$ npx node@12 benchmark.js v12.6.0 decode (v1.4.6) x 19,302 ops/sec ±1.02% (91 runs sampled) decode (proposal) x 25,188 ops/sec ±3.22% (92 runs sampled) Fastest is decode (proposal) $ npx node@10 benchmark.js v10.16.0 decode (v1.4.6) x 18,275 ops/sec ±5.84% (82 runs sampled) decode (proposal) x 24,739 ops/sec ±14.43% (74 runs sampled) Fastest is decode (proposal) $ npx node@8 benchmark.js v8.16.0 decode (v1.4.6) x 14,467 ops/sec ±2.10% (86 runs sampled) decode (proposal) x 17,241 ops/sec ±1.32% (91 runs sampled) Fastest is decode (proposal) $ npx node@6 benchmark.js v6.17.1 decode (v1.4.6) x 13,711 ops/sec ±1.70% (92 runs sampled) decode (proposal) x 20,953 ops/sec ±1.33% (91 runs sampled) Fastest is decode (proposal) 
@jridgewell
Copy link
Contributor Author

Combined with #79, this nets us a 4-20x boost over v1.4.5:

$ npx node@12 benchmark.js v12.6.0 decode (v1.4.5) x 6,563 ops/sec ±1.30% (90 runs sampled) decode (proposal) x 25,912 ops/sec ±2.06% (91 runs sampled) Fastest is decode (proposal) $ npx node@10 benchmark.js v10.16.0 decode (v1.4.5) x 1,622 ops/sec ±2.49% (76 runs sampled) decode (proposal) x 27,953 ops/sec ±4.11% (88 runs sampled) Fastest is decode (proposal) $ npx node@8 benchmark.js v8.16.0 decode (v1.4.5) x 6,029 ops/sec ±1.85% (92 runs sampled) decode (proposal) x 17,079 ops/sec ±1.12% (92 runs sampled) Fastest is decode (proposal) $ npx node@6 benchmark.js v6.17.1 decode (v1.4.5) x 1,313 ops/sec ±3.83% (78 runs sampled) decode (proposal) x 21,032 ops/sec ±0.75% (93 runs sampled) Fastest is decode (proposal) 
@jridgewell
Copy link
Contributor Author

Ping @Rich-Harris, anything I can do to get this in?

@jridgewell
Copy link
Contributor Author

Friendly ping.

@jridgewell
Copy link
Contributor Author

@Rich-Harris Rich-Harris merged commit 0de04ae into Rich-Harris:master Jan 16, 2020
@Rich-Harris
Copy link
Owner

Thank you! This is great — released 1.4.8. Apologies for the delayed response, my inbox was a disaster zone until recently, so I missed the pings.

@jridgewell
Copy link
Contributor Author

All good!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

2 participants