Skip to content

Benchmark value slice, update function#261

Merged
blakeembrey merged 1 commit intomasterfrom
be/benchmark-value-slice
Feb 13, 2026
Merged

Benchmark value slice, update function#261
blakeembrey merged 1 commit intomasterfrom
be/benchmark-value-slice

Conversation

@blakeembrey
Copy link
Member

Related to #259, I did end up running a bunch of tests and it's fairly inconclusive overall. So the other thing I hoped was another approach might compress smaller, but that turned out to be untrue too. However, I did incorporate a change into the code as a result of these experiments based on node (V8) + bun (WebKit) performance. Benchmarks:

Node:

 ✓ benchmarks/value-slice.bench.ts > valueSlice 'test=example' 37156ms
     name                                                   hz     min     max    mean     p75     p99    p995    p999     rme   samples
   · two while                                   30,355,526.30  0.0000  0.0448  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  15177764
   · two while (exit early)                      30,628,186.10  0.0000  0.0429  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.06%  15314094
   · two do...while                              30,821,931.84  0.0000  0.0415  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  15410967
   · two do...while (exit early)                 31,239,502.63  0.0000  0.0413  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  15619752
   · do...while then while                       31,301,625.81  0.0000  0.4552  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.19%  15650814
   · do...while then while (exit early)          31,354,796.18  0.0000  0.0472  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  15677399
   · do...while then while (empty string check)  30,835,515.41  0.0000  0.0613  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.09%  15417759
   · slice then trim                             23,821,463.67  0.0000  0.0450  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.06%  11910732

 ✓ benchmarks/value-slice.bench.ts > valueSlice 'test=' 36900ms
     name                                                   hz     min     max    mean     p75     p99    p995    p999     rme   samples
   · two while                                   33,368,393.67  0.0000  0.0427  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  16684197
   · two while (exit early)                      32,921,324.02  0.0000  0.0512  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  16460663
   · two do...while                              27,951,559.16  0.0000  0.0558  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.09%  13975780
   · two do...while (exit early)                 33,048,940.22  0.0000  0.0431  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  16524471
   · do...while then while                       28,426,065.15  0.0000  0.1068  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  14213033
   · do...while then while (exit early)          32,995,597.56  0.0000  0.0419  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  16497800
   · do...while then while (empty string check)  28,253,548.76  0.0000  0.0405  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.09%  14126775
   · slice then trim                             28,900,726.27  0.0000  0.0481  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  14450364

 ✓ benchmarks/value-slice.bench.ts > valueSlice 'test= example ' 29907ms
     name                                                   hz     min     max    mean     p75     p99    p995    p999     rme   samples
   · two while                                   26,821,807.89  0.0000  0.0426  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  13410904
   · two while (exit early)                      26,888,680.55  0.0000  0.0453  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  13444341
   · two do...while                              22,466,395.68  0.0000  0.0426  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.06%  11233198
   · two do...while (exit early)                 26,714,464.61  0.0000  0.0490  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  13357233
   · do...while then while                       22,652,703.73  0.0000  0.0373  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.06%  11326352
   · do...while then while (exit early)          27,072,771.13  0.0000  0.0437  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  13536386
   · do...while then while (empty string check)  22,739,166.95  0.0000  0.0563  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.08%  11369584
   · slice then trim                             21,590,465.48  0.0000  0.0577  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.08%  10795233

 ✓ benchmarks/value-slice.bench.ts > valueSlice 'test=example ' 32117ms
     name                                                   hz     min     max    mean     p75     p99    p995    p999     rme   samples
   · two while                                   28,611,706.68  0.0000  0.0430  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.09%  14305854
   · two while (exit early)                      28,429,908.92  0.0000  0.0415  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  14214955
   · two do...while                              25,594,946.00  0.0000  3.9939  0.0000  0.0000  0.0000  0.0000  0.0001  ±1.57%  12797474
   · two do...while (exit early)                 28,253,423.43  0.0000  0.0458  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  14126712
   · do...while then while                       26,125,660.75  0.0000  0.0505  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.09%  13062831
   · do...while then while (exit early)          28,741,426.85  0.0000  0.0474  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  14370714
   · do...while then while (empty string check)  26,103,359.22  0.0000  0.0436  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  13051680
   · slice then trim                             21,717,296.26  0.0000  0.0428  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.07%  10858649

 ✓ benchmarks/value-slice.bench.ts > valueSlice 'test= example' 30375ms
     name                                                   hz     min     max    mean     p75     p99    p995    p999     rme   samples
   · two while                                   28,010,682.26  0.0000  0.0374  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  14005342
   · two while (exit early)                      28,036,134.09  0.0000  0.0589  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  14018068
   · two do...while                              23,431,597.25  0.0000  0.0408  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.07%  11715799
   · two do...while (exit early)                 28,017,946.71  0.0000  0.0431  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  14008974
   · do...while then while                       23,471,875.62  0.0000  0.0486  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.07%  11735938
   · do...while then while (exit early)          28,363,529.72  0.0000  0.0423  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.06%  14181765
   · do...while then while (empty string check)  23,577,776.91  0.0000  0.0422  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.06%  11788889
   · slice then trim                             21,669,899.74  0.0000  0.0726  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.09%  10834950

 BENCH  Summary

  do...while then while (exit early) - benchmarks/value-slice.bench.ts > valueSlice 'test=example'
    1.00x faster than do...while then while
    1.00x faster than two do...while (exit early)
    1.02x faster than do...while then while (empty string check)
    1.02x faster than two do...while
    1.02x faster than two while (exit early)
    1.03x faster than two while
    1.32x faster than slice then trim

  two while - benchmarks/value-slice.bench.ts > valueSlice 'test='
    1.01x faster than two do...while (exit early)
    1.01x faster than do...while then while (exit early)
    1.01x faster than two while (exit early)
    1.15x faster than slice then trim
    1.17x faster than do...while then while
    1.18x faster than do...while then while (empty string check)
    1.19x faster than two do...while

  do...while then while (exit early) - benchmarks/value-slice.bench.ts > valueSlice 'test= example '
    1.01x faster than two while (exit early)
    1.01x faster than two while
    1.01x faster than two do...while (exit early)
    1.19x faster than do...while then while (empty string check)
    1.20x faster than do...while then while
    1.21x faster than two do...while
    1.25x faster than slice then trim

  do...while then while (exit early) - benchmarks/value-slice.bench.ts > valueSlice 'test=example '
    1.00x faster than two while
    1.01x faster than two while (exit early)
    1.02x faster than two do...while (exit early)
    1.10x faster than do...while then while
    1.10x faster than do...while then while (empty string check)
    1.12x faster than two do...while
    1.32x faster than slice then trim

  do...while then while (exit early) - benchmarks/value-slice.bench.ts > valueSlice 'test= example'
    1.01x faster than two while (exit early)
    1.01x faster than two do...while (exit early)
    1.01x faster than two while
    1.20x faster than do...while then while (empty string check)
    1.21x faster than do...while then while
    1.21x faster than two do...while
    1.31x faster than slice then trim

Bun:

 ✓ benchmarks/value-slice.bench.ts > valueSlice 'test=example' 36657ms
     name                                                   hz     min     max    mean     p75     p99    p995    p999     rme   samples
   · two while                                   30,201,224.19  0.0000  0.0541  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.09%  15100613
   · two while (exit early)                      30,544,971.21  0.0000  0.0441  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  15272486
   · two do...while                              30,932,244.39  0.0000  0.0437  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  15466123
   · two do...while (exit early)                 31,236,160.63  0.0000  0.0565  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  15618081
   · do...while then while                       31,171,001.19  0.0000  0.0597  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  15585501
   · do...while then while (exit early)          30,525,968.05  0.0000  0.0569  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  15262985
   · do...while then while (empty string check)  30,545,387.82  0.0000  0.0839  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.09%  15272694
   · slice then trim                             23,635,701.91  0.0000  0.0456  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.07%  11817851

 ✓ benchmarks/value-slice.bench.ts > valueSlice 'test=' 36603ms
     name                                                   hz     min     max    mean     p75     p99    p995    p999     rme   samples
   · two while                                   33,152,904.67  0.0000  0.0545  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.09%  16576453
   · two while (exit early)                      32,761,673.38  0.0000  0.0461  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.09%  16380838
   · two do...while                              28,131,521.21  0.0000  0.0420  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  14065761
   · two do...while (exit early)                 33,079,505.55  0.0000  0.0539  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  16539754
   · do...while then while                       28,624,025.20  0.0000  0.0442  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  14312013
   · do...while then while (exit early)          32,492,189.61  0.0000  0.0467  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  16246095
   · do...while then while (empty string check)  28,337,116.47  0.0000  0.0437  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.05%  14168559
   · slice then trim                             28,833,275.87  0.0000  0.0418  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  14416639

 ✓ benchmarks/value-slice.bench.ts > valueSlice 'test= example ' 29844ms
     name                                                   hz     min     max    mean     p75     p99    p995    p999     rme   samples
   · two while                                   26,855,700.76  0.0000  0.0442  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  13427851
   · two while (exit early)                      26,619,334.24  0.0000  0.0683  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  13309668
   · two do...while                              22,725,227.09  0.0000  0.0429  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.08%  11362614
   · two do...while (exit early)                 27,119,893.94  0.0000  0.0432  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.06%  13559948
   · do...while then while                       22,731,196.32  0.0000  0.0605  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.08%  11365599
   · do...while then while (exit early)          27,176,267.77  0.0000  0.0357  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  13588135
   · do...while then while (empty string check)  22,694,373.95  0.0000  0.0410  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.07%  11347187
   · slice then trim                             21,607,639.09  0.0000  0.0483  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.08%  10803820

 ✓ benchmarks/value-slice.bench.ts > valueSlice 'test=example ' 32029ms
     name                                                   hz     min     max    mean     p75     p99    p995    p999     rme   samples
   · two while                                   28,759,071.14  0.0000  0.0471  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  14379536
   · two while (exit early)                      28,485,855.49  0.0000  0.4816  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.21%  14242928
   · two do...while                              26,180,835.06  0.0000  0.0406  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  13090418
   · two do...while (exit early)                 28,742,275.54  0.0000  0.0797  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.09%  14371138
   · do...while then while                       26,199,000.17  0.0000  0.0703  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  13099501
   · do...while then while (exit early)          28,669,399.48  0.0000  0.4334  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.25%  14334700
   · do...while then while (empty string check)  26,152,887.22  0.0000  0.0470  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  13076444
   · slice then trim                             21,668,532.96  0.0000  0.0578  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.08%  10834267

 ✓ benchmarks/value-slice.bench.ts > valueSlice 'test= example' 30163ms
     name                                                   hz     min     max    mean     p75     p99    p995    p999     rme   samples
   · two while                                   27,980,614.10  0.0000  0.0407  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  13990308
   · two while (exit early)                      27,769,191.67  0.0000  0.0572  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.08%  13884596
   · two do...while                              23,788,108.86  0.0000  0.0469  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.06%  11894055
   · two do...while (exit early)                 28,525,562.34  0.0000  0.0448  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  14262782
   · do...while then while                       23,183,084.56  0.0000  0.0498  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.07%  11591543
   · do...while then while (exit early)          28,241,291.77  0.0000  0.0598  0.0000  0.0000  0.0000  0.0000  0.0001  ±0.07%  14120646
   · do...while then while (empty string check)  23,527,274.92  0.0000  0.0473  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.07%  11763638
   · slice then trim                             21,669,010.70  0.0000  2.0421  0.0000  0.0000  0.0001  0.0001  0.0001  ±0.80%  10834506

 BENCH  Summary

  two do...while (exit early) - benchmarks/value-slice.bench.ts > valueSlice 'test=example'
    1.00x faster than do...while then while
    1.01x faster than two do...while
    1.02x faster than do...while then while (empty string check)
    1.02x faster than two while (exit early)
    1.02x faster than do...while then while (exit early)
    1.03x faster than two while
    1.32x faster than slice then trim

  two while - benchmarks/value-slice.bench.ts > valueSlice 'test='
    1.00x faster than two do...while (exit early)
    1.01x faster than two while (exit early)
    1.02x faster than do...while then while (exit early)
    1.15x faster than slice then trim
    1.16x faster than do...while then while
    1.17x faster than do...while then while (empty string check)
    1.18x faster than two do...while

  do...while then while (exit early) - benchmarks/value-slice.bench.ts > valueSlice 'test= example '
    1.00x faster than two do...while (exit early)
    1.01x faster than two while
    1.02x faster than two while (exit early)
    1.20x faster than do...while then while
    1.20x faster than two do...while
    1.20x faster than do...while then while (empty string check)
    1.26x faster than slice then trim

  two while - benchmarks/value-slice.bench.ts > valueSlice 'test=example '
    1.00x faster than two do...while (exit early)
    1.00x faster than do...while then while (exit early)
    1.01x faster than two while (exit early)
    1.10x faster than do...while then while
    1.10x faster than two do...while
    1.10x faster than do...while then while (empty string check)
    1.33x faster than slice then trim

  two do...while (exit early) - benchmarks/value-slice.bench.ts > valueSlice 'test= example'
    1.01x faster than do...while then while (exit early)
    1.02x faster than two while
    1.03x faster than two while (exit early)
    1.20x faster than two do...while
    1.21x faster than do...while then while (empty string check)
    1.23x faster than do...while then while
    1.32x faster than slice then trim

Results change each run, but two things seem clear:

  1. Exiting early appears to be helping the performance of non empty cases
  2. The best way to optimize the truly empty case is two while loops

I didn't expect both these things to be true, so the implementation change in this PR feels like the "best" outcome of the performance testing. It's consistently one of the top results, and logically it makes sense - the real world usage will typically either be it's completely empty ('') or it's a cookie with some values and no whitespace. Which means it would be the minimum number of checks in both cases. The only case it would result in more checks is when the text is only whitespace (e.g. ' ').

@socket-security
Copy link

socket-security bot commented Jan 26, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​size-limit/​preset-small-lib@​12.0.0991005284100
Addedsize-limit@​12.0.01001008084100

View full report

@blakeembrey blakeembrey force-pushed the be/benchmark-value-slice branch from a523875 to 9fa784b Compare January 26, 2026 23:08
@blakeembrey
Copy link
Member Author

After more consideration I decided to just stick with the do..while then while I already had. It feels more technically clean and easy to follow since it doesn't rely on the .slice(4, 3) (second number smaller than first) to work, and it's the way it was originally written so I must have thought it was clearest the first time 🤷 The extra check in the majority case isn't worth the compromise in readability or the tiny de-optimization caused by sending strings of whitespace.

So I guess in the end the code ended up being the same as @Ayoub-Mabrouk, but it includes benchmarks and package size checks.

"size": "size-limit",
"specs": "ts-scripts specs",
"test": "ts-scripts test"
"test": "ts-scripts test && npm run size"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you intend to keep this or was it for debugging?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see in your comment that it is intentionally added

Copy link
Member

@bjohansebas bjohansebas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@blakeembrey blakeembrey merged commit 15a2b38 into master Feb 13, 2026
11 checks passed
@blakeembrey blakeembrey deleted the be/benchmark-value-slice branch February 13, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants