-
-
Notifications
You must be signed in to change notification settings - Fork 909
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
chore: optimize uuid.v4 by 4.3x (430%) (internal stringify by 33x) #597
Conversation
I left the version with validation as it may be useful for development. Please let me know if it should be removed. |
The new How about keeping the public That way this won't be a breaking change either, so it can go out in a regular release. |
All right, but I still find the check's usefulness questionable. It is not a very strict check, it's just checking appearances. A more proper test would validate the input buffer for proper length and version even prior to stringifying. |
cb6396b
to
4327216
Compare
Updated PR according to your suggestions. What's maybe is a missed opportunity is not exposing the validation-free stringify function. Any idea what are the use cases for users using this public |
Is there anything else I should change? |
4327216
to
95a9f69
Compare
Addressed. Thank you for the review. |
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.
Neat! 👍
@ctavan Do you know why the |
The browser tests and bundlewatch both use API keys (for Browserstack and bundlewatch respectively) and therefore don't run on PRs created from branches of forks. They only run on branches of this very repo. The reason is that it would otherwise be trivial to extract those secrets (just I haven't checked in a while if there is a solution for this problem by now. But until then we can also just merge and observe the checks on |
Bundlewatch report for
Bundlewatch report for
Summary:
Lower bundle sizes overall 🙌 |
@broofa are you fine with pulling this in now? |
Thank you for this great contribution, @Rush! 🎉 |
It's my pleasure. Thank you for creating and maintaining this project. 💯 |
It would be great to expose this
|
@andrejewski What's your use case for this? Unless |
Same as calling uuid 1M times per second :) I even think that the unsafe one should be the default. |
@broofa I happen to have my UUIDs represented as class UUID {
readonly bytes: Readonly<Uint8Array>
} When this class is constructed I'm always validating the array is of the right size, so when I go to stringify I don't need to run the additional validation. UUIDs are quite pervasive in my applications, and I definitely have not benchmarked anything, but it is wonky to pay the validation cost twice. @Rush I disagree that the unsafe version should be the default. String types are very pervasive in JS codebases and it's all too easy to pass an arbitrary string when only a UUID is expected. The type error can catch these bugs sooner. On the flip size, passing around a |
@andrejewski The more I think about this, the less inclined I am to expose Since you already have a UUID class, it might make sense for you to inline your preferred |
@andrejewski It's a PITA but since there is a lot of opposition to the idea of exposing the optimized version of stringify maybe you can just copy & paste the stringify function to your codebase and be done with it. Not sure why we would make a statement that doing stringification a million times per second is only reserved to Especially since the optimized version is 30x, yes 30 times faster. |
@Rush You asked previously what the use cases for For what it's worth, part of my reticence here is that I've been down this path before. If you look at the git history of this project, you'll see code and docs for Thus, when we added the new methods back in as part of version 8 we made the decision to be strict about enforcing RFC compliance on inputs. Hence why
It's a maintenance burden thing. As long as this method is internal we're free to change things as we see fit. But once it's made public, we're obligated to support it, even if we find a better solution. For example, we could inline the validation in if (arr.length - offset < 16) throw('Not enough values in array')
if ((arr[offset + 6] >>> 4) & 0x07 > 5) throw ('Invalid version')
if (arr[offset+8] & 0xc0 !== 0x80) throw ('Invalid variant') ... and probably get comparable performance to
... but that's only in the tightest possible loop. As soon as you do anything interesting inside that loop - a network request, a db query, DOM manipulation, file system I/O, basically anything that makes a UUID useful - the loop time increases by 100X and that "30X" becomes "1.03X". In absolute terms,
Please share details of those, because I can't think of any. For example, really big, high-traffic systems like Amazon, Walmart, Facebook... even if you're generating a UUID for every user action, every comment, every purchase, you're talking about maybe 100,000-1,000,000 operations/sec. But that load is spread across 100K's of multi-core servers. The per-core rate is going to be ≪ 1,000 ops/second. It's not just about the ops/second rate. You have to sustain that rate long enough for it to matter. Calling |
Am I correct that this hasn't been released yet? |
…ts (#37) There was a breaking change in ts-morph 16 that broke the ts build, so kept it at 15 dsherret/ts-morph#1325 uuid v9 speedup seems cool uuidjs/uuid#597 TEST=manual started up the app, ran jest tests
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [uuid](https://github.com/uuidjs/uuid) | dependencies | major | [`^8.3.2` -> `^9.0.0`](https://renovatebot.com/diffs/npm/uuid/8.3.2/9.0.0) | | [@types/uuid](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/uuid) ([source](https://github.com/DefinitelyTyped/DefinitelyTyped)) | dependencies | major | [`^8.3.0` -> `^9.0.0`](https://renovatebot.com/diffs/npm/@types%2fuuid/8.3.0/9.0.1) | --- ### Release Notes <details> <summary>uuidjs/uuid</summary> ### [`v9.0.0`](https://github.com/uuidjs/uuid/blob/HEAD/CHANGELOG.md#​900-httpsgithubcomuuidjsuuidcomparev832v900-2022-09-05) [Compare Source](uuidjs/uuid@v8.3.2...v9.0.0) ##### ⚠ BREAKING CHANGES - Drop Node.js 10.x support. This library always aims at supporting one EOLed LTS release which by this time now is 12.x which has reached EOL 30 Apr 2022. - Remove the minified UMD build from the package. Minified code is hard to audit and since this is a widely used library it seems more appropriate nowadays to optimize for auditability than to ship a legacy module format that, at best, serves educational purposes nowadays. For production browser use cases, users should be using a bundler. For educational purposes, today's online sandboxes like replit.com offer convenient ways to load npm modules, so the use case for UMD through repos like UNPKG or jsDelivr has largely vanished. - Drop IE 11 and Safari 10 support. Drop support for browsers that don't correctly implement const/let and default arguments, and no longer transpile the browser build to ES2015. This also removes the fallback on msCrypto instead of the crypto API. Browser tests are run in the first supported version of each supported browser and in the latest (as of this commit) version available on Browserstack. ##### Features - optimize uuid.v1 by 1.3x uuid.v4 by 4.3x (430%) ([#​597](uuidjs/uuid#597)) ([3a033f6](uuidjs/uuid@3a033f6)) - remove UMD build ([#​645](uuidjs/uuid#645)) ([e948a0f](uuidjs/uuid@e948a0f)), closes [#​620](uuidjs/uuid#620) - use native crypto.randomUUID when available ([#​600](uuidjs/uuid#600)) ([c9e076c](uuidjs/uuid@c9e076c)) ##### Bug Fixes - add Jest/jsdom compatibility ([#​642](uuidjs/uuid#642)) ([16f9c46](uuidjs/uuid@16f9c46)) - change default export to named function ([#​545](uuidjs/uuid#545)) ([c57bc5a](uuidjs/uuid@c57bc5a)) - handle error when parameter is not set in v3 and v5 ([#​622](uuidjs/uuid#622)) ([fcd7388](uuidjs/uuid@fcd7388)) - run npm audit fix ([#​644](uuidjs/uuid#644)) ([04686f5](uuidjs/uuid@04686f5)) - upgrading from uuid3 broken link ([#​568](uuidjs/uuid#568)) ([1c849da](uuidjs/uuid@1c849da)) ##### build - drop Node.js 8.x from babel transpile target ([#​603](uuidjs/uuid#603)) ([aa11485](uuidjs/uuid@aa11485)) - drop support for legacy browsers (IE11, Safari 10) ([#​604](uuidjs/uuid#604)) ([0f433e5](uuidjs/uuid@0f433e5)) - drop node 10.x to upgrade dev dependencies ([#​653](uuidjs/uuid#653)) ([28a5712](uuidjs/uuid@28a5712)), closes [#​643](uuidjs/uuid#643) ##### [8.3.2](uuidjs/uuid@v8.3.1...v8.3.2) (2020-12-08) ##### Bug Fixes - lazy load getRandomValues ([#​537](uuidjs/uuid#537)) ([16c8f6d](uuidjs/uuid@16c8f6d)), closes [#​536](uuidjs/uuid#536) ##### [8.3.1](uuidjs/uuid@v8.3.0...v8.3.1) (2020-10-04) ##### Bug Fixes - support expo>=39.0.0 ([#​515](uuidjs/uuid#515)) ([c65a0f3](uuidjs/uuid@c65a0f3)), closes [#​375](uuidjs/uuid#375) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC43NC4yIiwidXBkYXRlZEluVmVyIjoiMzQuNzQuMiJ9--> Co-authored-by: Renovate Bot <renovate@vylpes.com> Reviewed-on: https://gitea.vylpes.xyz/RabbitLabs/Droplet/pulls/111 Reviewed-by: Vylpes <ethan@vylpes.com> Co-authored-by: RenovateBot <renovate@vylpes.com> Co-committed-by: RenovateBot <renovate@vylpes.com>
It turns out that validation in
uuidStringify()
is slowing it down by 33x. Sinceuuidv1()
anduuidv4()
produce valid buffers by the virtue of their algorithm they can safely use a validation-free version of stringify.Benchmark changes
uuidv1()
- faster by 1.3xuuidv4()
- faster by 4.3xthe gains are due to
.unsafeStringify()
with no validation (as it is not required) is 33x faster than the version with validation.The public
uuidStringify()
has been left unchanged but my recommendation would be to also remove validation from this method in the future and just export the unsafe version.Benchmark (Core i9-10900K)
Benchmark prior to changes