Optimize loops for V8 Smi #6

Merged
101arrowz merged 1 commits from master into master 2021-04-16 15:30:11 +00:00
101arrowz commented 2021-02-11 21:17:51 +00:00 (Migrated from github.com)

This PR modifies the number of iterations that the Adler32 algorithm uses before taking a modulus. The magic numbers were the maximum values that will always ensure B < 2 ** 30 - 1, since that's the largest value that fits in a V8 small integer.

# The magic number we want to find
N = ?
# Maximum possible average value of bytes
# 255 for binary, 207 for UTF-8
M = ?

# maximum initial value of A
# Takes the modulus-but-not-really algorithm into account
# Subtract 1 because will not be able to get 65535 modulo
# 65536 unless we go below the previous 16-bit boundary
A = 15 * ((N * M >> 16) - 1) + 65535

# max initial value of B (assuming previously hit max)
# This isn't perfectly accurate, in theory we should replace
# 2 ** 30 - 1 with B_max but in practice they are close enough
B = 15 * ((2 ** 30 - 1 >> 16) - 1) + 65535

# Try to make this as close to 2 ** 30 - 1 without surpassing
B_max = B + N * A + (N * (N + 1) / 2) * M

This yields N = 2654 for binary and N = 2918 for UTF-8.

If you're wondering why UTF-8 has a maximum average byte value of 207, consider that only one of the four following code point structures are possible:

0bbbbbbb
110bbbbb 10bbbbbb
1110bbbb 10bbbbbb 10bbbbbb
11110bbb 10bbbbbb 10bbbbbb 10bbbbbb

If we check the maximum value for each code point (i.e. set all the b placeholders to 1), we find 127 for the 1-byte variant, 414 for the 2-byte, 621 for the 3-byte, and 820 for the 4-byte. This yields a maximum value of 127/byte, 207/byte, 207/byte, and 205/byte for 1, 2, 3, and 4-byte codes respectively. Taking the max of this, the average value of all bytes in a UTF-8 sequences maxes out at 207, and will almost always be in the low to mid 100s in practice.

I also updated the benchmarks, but my computer doesn't reveal any major differences between any of the magic numbers (though at least now the values are semantically correct).

Hope you find these optimizations useful!

This PR modifies the number of iterations that the Adler32 algorithm uses before taking a modulus. The magic numbers were the maximum values that will always ensure `B < 2 ** 30 - 1`, since that's the largest value that fits in a V8 small integer. ``` # The magic number we want to find N = ? # Maximum possible average value of bytes # 255 for binary, 207 for UTF-8 M = ? # maximum initial value of A # Takes the modulus-but-not-really algorithm into account # Subtract 1 because will not be able to get 65535 modulo # 65536 unless we go below the previous 16-bit boundary A = 15 * ((N * M >> 16) - 1) + 65535 # max initial value of B (assuming previously hit max) # This isn't perfectly accurate, in theory we should replace # 2 ** 30 - 1 with B_max but in practice they are close enough B = 15 * ((2 ** 30 - 1 >> 16) - 1) + 65535 # Try to make this as close to 2 ** 30 - 1 without surpassing B_max = B + N * A + (N * (N + 1) / 2) * M ``` This yields N = 2654 for binary and N = 2918 for UTF-8. If you're wondering why UTF-8 has a maximum average byte value of 207, consider that only one of the four following code point structures are possible: ``` 0bbbbbbb 110bbbbb 10bbbbbb 1110bbbb 10bbbbbb 10bbbbbb 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb ``` If we check the maximum value for each code point (i.e. set all the `b` placeholders to 1), we find 127 for the 1-byte variant, 414 for the 2-byte, 621 for the 3-byte, and 820 for the 4-byte. This yields a maximum value of 127/byte, 207/byte, 207/byte, and 205/byte for 1, 2, 3, and 4-byte codes respectively. Taking the max of this, the average value of all bytes in a UTF-8 sequences maxes out at 207, and will almost always be in the low to mid 100s in practice. I also updated the benchmarks, but my computer doesn't reveal any major differences between any of the magic numbers (though at least now the values are semantically correct). Hope you find these optimizations useful!
coveralls commented 2021-02-11 22:22:46 +00:00 (Migrated from github.com)

Coverage Status

Coverage remained the same at 88.71% when pulling 00ae70e9dd on 101arrowz:master into b40011c6f7 on SheetJS:master.

[![Coverage Status](https://coveralls.io/builds/37072395/badge)](https://coveralls.io/builds/37072395) Coverage remained the same at 88.71% when pulling **00ae70e9dd5c30b2cdd1bea305244782adae4f5b on 101arrowz:master** into **b40011c6f76bb2a0b78126fc8412ff380c905dcd on SheetJS:master**.
101arrowz commented 2021-02-22 04:02:05 +00:00 (Migrated from github.com)

@SheetJSDev Could you take a look?

@SheetJSDev Could you take a look?
Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: sheetjs/js-adler32#6
No description provided.