tailwind-merge icon indicating copy to clipboard operation
tailwind-merge copied to clipboard

vibe optimization

Open quantizor opened this issue 9 months ago • 2 comments

Claude and I jammed on some potential improvements...

base base - best of 3
adjusted, size 500 cache 500 - best of 3
adjusted, size 20k cache 20000 - best of 3

Rationale for increasing cache size is the partials it's storing are quite small and a medium-complexity website may have thousands of them. They probably won't take up much space even in volume.

Roughly a 15% improvement in the cached example... it adds up!

quantizor avatar Mar 16 '25 18:03 quantizor

Hey @quantizor, thanks for optimizing the runtime!

Just took a brief look at the diff and I think it would be good to split this into multiple PRs so I can verify some changes in isolation. If you're up to it, I'll review your changes in more detail tomorrow, probably leave a bunch of comments and let you know how to best split it up.

dcastil avatar Mar 21 '25 21:03 dcastil

Hey @quantizor, thanks for optimizing the runtime!

Just took a brief look at the diff and I think it would be good to split this into multiple PRs so I can verify some changes in isolation. If you're up to it, I'll review your changes in more detail tomorrow, probably leave a bunch of comments and let you know how to best split it up.

Sure thing!

quantizor avatar Mar 21 '25 22:03 quantizor

@dcastil updated per your suggestions

quantizor avatar Sep 01 '25 03:09 quantizor

Bench results after tweaks:

OLD

 ✓ tests/tw-merge.benchmark.ts > twMerge 3061ms
     name                            hz     min      max     mean      p75      p99     p995     p999     rme  samples
   · init                      4,210.32  0.2087   2.7886   0.2375   0.2364   0.5238   0.5781   0.9083  ±1.45%     2106
   · simple                    4,499.52  0.2101   0.5602   0.2222   0.2208   0.3823   0.3990   0.4524  ±0.54%     2250   fastest
   · heavy                     4,086.20  0.2217   2.6981   0.2447   0.2420   0.4962   0.5524   0.6520  ±1.25%     2044
   · collection with cache       608.18  1.4067   7.9597   1.6442   1.5477   5.7333   7.4706   7.9597  ±4.68%      305
   · collection without cache   98.5241  9.5441  10.7708  10.1498  10.4183  10.7708  10.7708  10.7708  ±0.93%       50   slowest

NEW

 ✓ tests/tw-merge.benchmark.ts > twMerge 3054ms
     name                            hz     min      max    mean     p75      p99     p995     p999     rme  samples
   · init                      4,620.76  0.1933   1.3782  0.2164  0.2208   0.3966   0.5028   1.0336  ±1.04%     2311
   · simple                    4,840.87  0.1938   0.5355  0.2066  0.2077   0.3755   0.3942   0.4328  ±0.48%     2421   fastest
   · heavy                     4,616.99  0.2045   0.4501  0.2166  0.2178   0.3655   0.3987   0.4243  ±0.43%     2309
   · collection with cache       724.81  1.2980   3.5978  1.3797  1.3907   1.7990   2.0750   3.5978  ±1.09%      363
   · collection without cache    103.79  8.9342  19.0420  9.6348  9.5288  19.0420  19.0420  19.0420  ±4.38%       52   slowest

quantizor avatar Oct 29 '25 16:10 quantizor

Best of 3 with memory info from #620

main branch

Memory Usage Summary:
  init: 1.57 MB heap
  simple: 1016.39 KB heap
  heavy: 1.01 MB heap
  collection with cache: 2.52 MB heap
    Total footprint: 234.75 MB
    Operations: 1322
  collection without cache: 16.99 MB heap
    Total footprint: 235.13 MB
    Operations: 1322


 ✓ tests/tw-merge.benchmark.ts > twMerge 3136ms
     name                            hz     min      max    mean     p75      p99     p995     p999     rme  samples
   · init                      4,065.35  0.2175   1.8490  0.2460  0.2450   0.4969   0.5517   0.8136  ±1.12%     2033
   · simple                    4,062.11  0.2270   0.7383  0.2462  0.2448   0.4628   0.4756   0.5714  ±0.70%     2032
   · heavy                     3,837.87  0.2374   2.3023  0.2606  0.2597   0.4791   0.5047   0.8659  ±1.06%     1919
   · collection with cache       688.97  1.3773   2.2432  1.4514  1.4654   1.7979   1.9276   2.2432  ±0.68%      345
   · collection without cache    109.09  8.8340  10.2709  9.1664  9.2940  10.2709  10.2709  10.2709  ±0.73%       55

perf branch

Memory Usage Summary:
  init: 1.22 MB heap
  simple: 838.82 KB heap
  heavy: 647.81 KB heap
  collection with cache: 1.79 MB heap
    Total footprint: 171.70 MB
    Operations: 1322
  collection without cache: 13.72 MB heap
    Total footprint: 238.06 MB
    Operations: 1322


 ✓ tests/tw-merge.benchmark.ts > twMerge 3130ms
     name                            hz     min      max    mean     p75      p99     p995     p999     rme  samples
   · init                      4,581.74  0.1975   1.3568  0.2183  0.2220   0.3657   0.4523   0.6930  ±0.89%     2291
   · simple                    4,396.86  0.2133   0.5638  0.2274  0.2274   0.4307   0.4576   0.5137  ±0.55%     2199
   · heavy                     4,182.74  0.2232   0.5723  0.2391  0.2393   0.4502   0.4675   0.5242  ±0.58%     2092
   · collection with cache       724.98  1.3007   3.3782  1.3793  1.4092   1.6660   2.2602   3.3782  ±1.02%      363
   · collection without cache    110.72  8.6614  10.1187  9.0318  9.2184  10.1187  10.1187  10.1187  ±1.10%       56

quantizor avatar Oct 29 '25 19:10 quantizor

CodSpeed Performance Report

Merging #547 will improve performances by 19.21%

Comparing quantizor:perf (16f0482) with main (db06f11)

Summary

⚡ 4 improvements
✅ 1 untouched

Benchmarks breakdown

Benchmark BASE HEAD Change
collection with cache 19.2 ms 17.2 ms +11.56%
heavy 5 ms 4.2 ms +18.89%
init 5.7 ms 5 ms +13.45%
simple 4.7 ms 3.9 ms +19.21%

codspeed-hq[bot] avatar Nov 02 '25 13:11 codspeed-hq[bot]

Just noting here:

Size of total ESM bundle increased from 6.68 kB to 6.96 kB minified + Brotli-compressed which is a 4.2% increase. I think this is fine for the 10-20% perf boost.

dcastil avatar Nov 02 '25 13:11 dcastil

This was addressed in release v3.4.0.

github-actions[bot] avatar Nov 09 '25 12:11 github-actions[bot]