-
-
Notifications
You must be signed in to change notification settings - Fork 186
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
⚡️ Faster generate process for mapToConstant
#5386
Conversation
The arbitrary `mapToConstant` used to rely on a linear scan to get the entry to be used to generate the element. It used to be sub-optimal for cases implying several entries (a normal scenario for this arbitrary). Our new implementation relies on a dichotomic-lookup that will be way less costly to execute. This change should have a visible impact when generating strings using the `string` arbitrary.
🦋 Changeset detectedLatest commit: cc6fa45 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 69a45fd:
|
👋 A preview of the new documentation is available at: http://6722b15f2dfa537c253b9177--dubzzz-fast-check.netlify.app |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #5386 +/- ##
=======================================
Coverage 95.27% 95.28%
=======================================
Files 234 234
Lines 10478 10497 +19
Branches 2795 2799 +4
=======================================
+ Hits 9983 10002 +19
Misses 495 495
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
packages/fast-check/src/arbitrary/_internals/mappers/IndexToMappedConstant.ts
Outdated
Show resolved
Hide resolved
👋 A preview of the new documentation is available at: http://6722b67c5a7399822b27eac6--dubzzz-fast-check.netlify.app |
Here are the measured improvements linked to this change (main corresponds to the content of the main branch before merging this PR, extra corresponds to main branch with this PR being added on top): ┌──────────────────────────────────────────────────────────────────────────────────────────────────┬────────┬────────────────────┬─────────┬─────────┐
│ Task Name │ ops/s │ Average Time (ns) │ Margin │ Samples │
├──────────────────────────────────────────────────────────────────────────────────────────────────┼────────┼────────────────────┼─────────┼─────────┤
│ fc.char() on 3.22.0 │ 9,368 │ 106738.22999815457 │ ±11.66% │ 100 │
│ fc.char() on main │ 9,663 │ 103479.24999834504 │ ±11.34% │ 100 │
│ fc.char() on extra │ 10,788 │ 92691.67000020389 │ ±7.03% │ 100 │
│ — │ — │ — │ — │ — │
│ fc.string() on 3.22.0 │ 4,215 │ 237237.96000238508 │ ±11.16% │ 100 │
│ fc.string() on main │ 3,345 │ 298905.37999919616 │ ±10.25% │ 100 │
│ fc.string() on extra │ 4,420 │ 226201.57000375912 │ ±12.66% │ 100 │
│ — │ — │ — │ — │ — │
│ fc.constant('').chain(() => fc.string()) on 3.22.0 │ 289 │ 3453428.210000857 │ ±3.82% │ 100 │
│ fc.constant('').chain(() => fc.string()) on main │ 281 │ 3546300.1300010365 │ ±3.86% │ 100 │
│ fc.constant('').chain(() => fc.string()) on extra │ 247 │ 4043440.100001171 │ ±14.11% │ 100 │
│ — │ — │ — │ — │ — │
│ fc.string({ minLength: 0, maxLength: 500, size: 'max' }) on 3.22.0 │ 344 │ 2901300.9500002954 │ ±3.14% │ 100 │
│ fc.string({ minLength: 0, maxLength: 500, size: 'max' }) on main │ 266 │ 3755916.159997578 │ ±4.83% │ 100 │
│ fc.string({ minLength: 0, maxLength: 500, size: 'max' }) on extra │ 343 │ 2908296.8900032574 │ ±2.87% │ 100 │
│ — │ — │ — │ — │ — │
│ fc.string({ minLength: 0, maxLength: 25_000, size: 'max' }) on 3.22.0 │ 5 │ 182296668.1500012 │ ±2.62% │ 100 │
│ fc.string({ minLength: 0, maxLength: 25_000, size: 'max' }) on main │ 4 │ 203494224.3399989 │ ±2.48% │ 100 │
│ fc.string({ minLength: 0, maxLength: 25_000, size: 'max' }) on extra │ 5 │ 187140365.4099995 │ ±2.31% │ 100 │
│ — │ — │ — │ — │ — │
│ fc.string({ unit:'grapheme-composite' }) on 3.22.0 │ 1,723 │ 580309.890001663 │ ±8.94% │ 100 │
│ fc.string({ unit:'grapheme-composite' }) on main │ 1,669 │ 598834.3699945835 │ ±6.99% │ 100 │
│ fc.string({ unit:'grapheme-composite' }) on extra │ 4,020 │ 248739.32000249624 │ ±7.87% │ 100 │
│ — │ — │ — │ — │ — │
│ fc.constant('').chain(() => fc.string({ unit:'grapheme-composite' })) on 3.22.0 │ 248 │ 4032160.359999398 │ ±2.83% │ 100 │
│ fc.constant('').chain(() => fc.string({ unit:'grapheme-composite' })) on main │ 241 │ 4142842.7099983674 │ ±2.91% │ 100 │
│ fc.constant('').chain(() => fc.string({ unit:'grapheme-composite' })) on extra │ 242 │ 4131120.5499991775 │ ±11.21% │ 100 │
│ — │ — │ — │ — │ — │
│ fc.string({ unit:'grapheme-composite', minLength: 0, maxLength: 500, size: 'max' }) on 3.22.0 │ 60 │ 16407039.570002817 │ ±2.32% │ 100 │
│ fc.string({ unit:'grapheme-composite', minLength: 0, maxLength: 500, size: 'max' }) on main │ 57 │ 17454052.590000212 │ ±1.69% │ 100 │
│ fc.string({ unit:'grapheme-composite', minLength: 0, maxLength: 500, size: 'max' }) on extra │ 243 │ 4098511.249999865 │ ±1.81% │ 100 │
│ — │ — │ — │ — │ — │
│ fc.string({ unit:'grapheme-composite', minLength: 0, maxLength: 25_000, size: 'max' }) on 3.22.0 │ 1 │ 870766349.1599966 │ ±1.63% │ 100 │
│ fc.string({ unit:'grapheme-composite', minLength: 0, maxLength: 25_000, size: 'max' }) on main │ 1 │ 948013368.8300028 │ ±1.37% │ 100 │
│ fc.string({ unit:'grapheme-composite', minLength: 0, maxLength: 25_000, size: 'max' }) on extra │ 3 │ 264880956.58000442 │ ±1.83% │ 100 │
│ — │ — │ — │ — │ — │
│ fc.string({ unit:'grapheme' }) on 3.22.0 │ 1,748 │ 572059.8099962808 │ ±10.13% │ 100 │
│ fc.string({ unit:'grapheme' }) on main │ 1,822 │ 548604.5400053263 │ ±5.43% │ 100 │
│ fc.string({ unit:'grapheme' }) on extra │ 3,716 │ 269096.84001118876 │ ±11.96% │ 100 │
│ — │ — │ — │ — │ — │
│ fc.constant('').chain(() => fc.string({ unit:'grapheme' })) on 3.22.0 │ 250 │ 3999905.5099952966 │ ±3.38% │ 100 │
│ fc.constant('').chain(() => fc.string({ unit:'grapheme' })) on main │ 221 │ 4516513.949992368 │ ±14.04% │ 100 │
│ fc.constant('').chain(() => fc.string({ unit:'grapheme' })) on extra │ 278 │ 3587600.650008535 │ ±6.71% │ 100 │
│ — │ — │ — │ — │ — │
│ fc.string({ unit:'grapheme', minLength: 0, maxLength: 500, size: 'max' }) on 3.22.0 │ 58 │ 17235557.719999924 │ ±1.58% │ 100 │
│ fc.string({ unit:'grapheme', minLength: 0, maxLength: 500, size: 'max' }) on main │ 56 │ 17820634.84999584 │ ±1.58% │ 100 │
│ fc.string({ unit:'grapheme', minLength: 0, maxLength: 500, size: 'max' }) on extra │ 224 │ 4454215.3500101995 │ ±1.97% │ 100 │
│ — │ — │ — │ — │ — │
│ fc.string({ unit:'grapheme', minLength: 0, maxLength: 25_000, size: 'max' }) on 3.22.0 │ 1 │ 919136515.0400053 │ ±1.58% │ 100 │
│ fc.string({ unit:'grapheme', minLength: 0, maxLength: 25_000, size: 'max' }) on main │ 1 │ 934689762.1800052 │ ±1.60% │ 100 │
│ fc.string({ unit:'grapheme', minLength: 0, maxLength: 25_000, size: 'max' }) on extra │ 3 │ 274834529.1400014 │ ±2.17% │ 100 │
└──────────────────────────────────────────────────────────────────────────────────────────────────┴────────┴────────────────────┴─────────┴─────────┘ Full run: https://github.com/dubzzz/fast-check-benchmarks/actions/runs/11602785921 |
After the merge we wanted to check how far we were from v3.21.0 notably regarding the performance of ┌─────────┬────────────────────────────────────────────────────┬──────────┬────────────────────┬───────────┬─────────┐
│ (index) │ Task Name │ ops/sec │ Average Time (ns) │ Margin │ Samples │
├─────────┼────────────────────────────────────────────────────┼──────────┼────────────────────┼───────────┼─────────┤
│ 32 │ fc.char() on 3.21.0 │ '6,265' │ 159605.95999960788 │ '±8.45%' │ 100 │
│ 33 │ fc.char() on 3.22.0 │ '7,009' │ 142660.150002921 │ '±7.98%' │ 100 │
│ 34 │ fc.char() on main │ '9,729' │ 102776.86999703292 │ '±8.92%' │ 100 │
│ 35 │ '—' │ '—' │ '—' │ '—' │ '—' │
│ 36 │ fc.string() on 3.21.0 │ '4,974' │ 201044.76999957114 │ '±6.51%' │ 100 │
│ 37 │ fc.string() on 3.22.0 │ '4,051' │ 246812.13000090793 │ '±8.99%' │ 100 │
│ 38 │ fc.string() on main │ '3,952' │ 253003.0700052157 │ '±10.80%' │ 100 │
│ 39 │ '—' │ '—' │ '—' │ '—' │ '—' │
│ 40 │ fc.constant('').chain(() => fc.string()) on 3.21.0 │ '907' │ 1102138.660000055 │ '±16.74%' │ 100 │
│ 41 │ fc.constant('').chain(() => fc.string()) on 3.22.0 │ '285' │ 3505258.7399998447 │ '±14.04%' │ 100 │
│ 42 │ fc.constant('').chain(() => fc.string()) on main │ '312' │ 3201661.3900009543 │ '±7.56%' │ 100 │
└─────────┴────────────────────────────────────────────────────┴──────────┴────────────────────┴───────────┴─────────┘ Full run: https://github.com/dubzzz/fast-check-benchmarks/actions/runs/11608213916 |
Description
The arbitrary
mapToConstant
used to rely on a linear scan to get the entry to be used to generate the element. It used to be sub-optimal for cases implying several entries (a normal scenario for this arbitrary).Our new implementation relies on a dichotomic-lookup that will be way less costly to execute.
This change should have a visible impact when generating strings using the
string
arbitrary.Supersede #5243
Checklist — Don't delete this checklist and make sure you do the following before opening the PR
yarn bump
and flag the impacts properlyAdvanced
mapToConstant
but also any arbitrary derived from it:string
and many others