Skip to content
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

perf(serialize): faster serialization and less bundle size #126

Merged
merged 8 commits into from
Mar 1, 2025

Conversation

zsilbi
Copy link
Contributor

@zsilbi zsilbi commented Mar 1, 2025

By removing the additional handlers added to Serializer and handling them directly in serialize() we can further improve performance and reduce bundle size. I understand that this breaks the concept of this class but the performance gains worth it in my opinion.

toComparableString() can also be removed because serialize() will be much faster for simple types. (for comparing strings an additional flag is required to further improve performance)

Benchmarks

   test/benchmarks.bench.ts > benchmarks > all presets 1260ms
     name                  hz     min     max    mean     p75     p99    p995    p999     rme  samples
   · serialize @ main  135.40  6.7750  9.9638  7.3853  7.5288  9.9638  9.9638  9.9638  ±2.03%       68
   · serialize         171.57  5.3166  7.4802  5.8285  6.0204  7.4802  7.4802  7.4802  ±1.23%       86   fastest

 BENCH  Summary

  serialize - test/benchmarks.bench.ts > benchmarks > all presets
    1.27x faster than serialize @ main

  test/benchmarks.bench.ts > benchmarks > serialize @ main 7424ms
     name                                                            hz     min     max    mean     p75     p99    p995    p999     rme  samples
   · count:1, size:small                                     450,209.10  0.0019  1.2116  0.0022  0.0022  0.0034  0.0038  0.0151  ±0.72%   225105   fastest
   · count:1, size:small, circular:true                      281,593.64  0.0031  1.0305  0.0036  0.0035  0.0056  0.0061  0.0171  ±0.49%   140797
   · count:1, size:large                                      40,754.79  0.0202  1.7321  0.0245  0.0229  0.0500  0.0662  0.5412  ±1.55%    20378
   · count:1, size:large, circular:true                          927.70  0.9855  2.0224  1.0779  1.0585  1.6027  1.6757  2.0224  ±1.11%      464
   · count:1024, size:small, referenced:true                  20,354.41  0.0461  0.4633  0.0491  0.0477  0.0831  0.1424  0.2150  ±0.49%    10178
   · count:1024, size:small, circular:true, referenced:true   20,021.87  0.0467  0.4419  0.0499  0.0483  0.0836  0.1841  0.2717  ±0.61%    10011
   · count:512, size:large, referenced:true                   20,406.62  0.0429  0.6675  0.0490  0.0466  0.0897  0.1307  0.5964  ±1.24%    10204
   · count:512, size:large, circular:true, referenced:true       915.19  1.0006  1.7561  1.0927  1.0809  1.5957  1.6037  1.7561  ±0.98%      458
   · count:256, size:small                                     3,591.03  0.2484  0.9587  0.2785  0.2635  0.5999  0.6587  0.8062  ±1.19%     1796
   · count:256, size:small, circular:true                      3,126.17  0.2876  0.9784  0.3199  0.3027  0.6963  0.7509  0.9127  ±1.21%     1564
   · count:128, size:large                                       887.82  0.9846  2.0978  1.1264  1.0708  2.0229  2.0397  2.0978  ±2.07%      444
   · count:128, size:large, circular:true                        471.27  1.9653  3.3482  2.1219  2.1160  2.9526  3.3247  3.3482  ±1.23%      236   slowest

  test/benchmarks.bench.ts > benchmarks > serialize 7490ms
     name                                                            hz     min     max    mean     p75     p99    p995    p999     rme  samples
   · count:1, size:small                                     547,060.21  0.0016  0.3810  0.0018  0.0018  0.0029  0.0031  0.0090  ±0.30%   273531   fastest
   · count:1, size:small, circular:true                      356,617.53  0.0024  1.1083  0.0028  0.0028  0.0047  0.0051  0.0192  ±0.62%   178309
   · count:1, size:large                                      49,299.65  0.0173  1.0041  0.0203  0.0192  0.0400  0.0549  0.4269  ±1.33%    24650
   · count:1, size:large, circular:true                        1,108.82  0.8237  1.5761  0.9019  0.8948  1.2724  1.4699  1.5761  ±0.83%      555
   · count:1024, size:small, referenced:true                  80,183.53  0.0109  0.3043  0.0125  0.0118  0.0237  0.0474  0.1564  ±0.67%    40092
   · count:1024, size:small, circular:true, referenced:true   80,623.58  0.0107  0.4726  0.0124  0.0117  0.0235  0.0508  0.1584  ±0.72%    40312
   · count:512, size:large, referenced:true                   36,843.97  0.0225  0.8207  0.0271  0.0250  0.0559  0.0809  0.5625  ±1.51%    18422
   · count:512, size:large, circular:true, referenced:true     1,108.22  0.8278  1.4586  0.9023  0.8929  1.3573  1.4010  1.4586  ±0.97%      555
   · count:256, size:small                                     5,659.69  0.1592  0.7203  0.1767  0.1674  0.4229  0.4749  0.6181  ±0.99%     2831
   · count:256, size:small, circular:true                      5,000.89  0.1826  0.6197  0.2000  0.1908  0.4081  0.4661  0.5316  ±0.81%     2501
   · count:128, size:large                                     1,195.65  0.7192  2.4965  0.8364  0.7873  1.6309  1.7361  2.4965  ±2.08%      598
   · count:128, size:large, circular:true                        553.78  1.5532  3.4270  1.8058  1.7396  3.3216  3.3655  3.4270  ±2.40%      277   slowest

Bundle size

stdout | test/bundle.test.ts > bundle size > serialize @ main
{ bytes: 2449, gzipSize: 1038 }
   
stdout | test/bundle.test.ts > bundle size > serialize
{ bytes: 2327, gzipSize: 976 }

Notes

This modification resulted in +300% performance gains in some presets.

// Slow
const type = typeof value;
switch (type) {
  case "object":
  case "function": {
    // @ts-ignore
    return this["$" + type].call(this, value);
  }
}

// Fast
switch (typeof value) {
  case "object": {
    return this.$object(value);
  }
  case "function": {
    return this.$function(value);
  }
}

Copy link

codecov bot commented Mar 1, 2025

Codecov Report

Attention: Patch coverage is 96.55172% with 1 line in your changes missing coverage. Please review.

Project coverage is 95.39%. Comparing base (c5173ba) to head (d52a4cc).
Report is 79 commits behind head on main.

Files with missing lines Patch % Lines
src/serialize.ts 96.55% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main     #126       +/-   ##
===========================================
+ Coverage   80.31%   95.39%   +15.07%     
===========================================
  Files           8        8               
  Lines        1006      456      -550     
  Branches      111      114        +3     
===========================================
- Hits          808      435      -373     
+ Misses        198       19      -179     
- Partials        0        2        +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@pi0 pi0 changed the title perf(serialize): Faster serialization perf(serialize): faster serialization and less bundle size Mar 1, 2025
Copy link
Member

@pi0 pi0 left a comment

Choose a reason for hiding this comment

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

Thnx!

@pi0 pi0 merged commit 12aa794 into unjs:main Mar 1, 2025
4 checks passed
@zsilbi zsilbi deleted the perf/serialize branch March 3, 2025 09:54
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.

2 participants