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

Use string concatenation to increase performance #336

Merged
merged 1 commit into from
Dec 26, 2023
Merged

Conversation

jonkoops
Copy link
Collaborator

@jonkoops jonkoops commented Dec 24, 2023

Replaces the logic that holds class names in an array and joins them together in the end with direct string concatenation, this results in ~30% performance increase across the board. The following benchmarks were ran on my 2021 MacBook Pro 14-inch with an M1 Pro chip running macOS Sonoma (14.2.1):

Node.js (v21.5.0)

Benchmarking 'strings'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 15,670,038 63.81605063010916 ±0.54% 7835020
default/npm 9,005,011 111.04927211649938 ±0.68% 4502506
bind/local 14,077,263 71.0365342300473 ±0.18% 7038632
bind/npm 8,883,553 112.56756055795418 ±1.65% 4441778
dedupe/local 4,010,081 249.37146821418366 ±0.67% 2005041
dedupe/npm 3,966,145 252.13396834126922 ±0.79% 1983073

Benchmarking 'object'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 15,088,614 66.27513948224117 ±0.45% 7544308
default/npm 9,035,877 110.6699331265635 ±0.78% 4517939
bind/local 14,505,287 68.9403796737236 ±0.61% 7252644
bind/npm 9,165,639 109.10313123727286 ±2.22% 4582821
dedupe/local 7,044,533 141.95404891256982 ±0.25% 3522267
dedupe/npm 7,053,860 141.76634671966156 ±0.28% 3526931

Benchmarking 'strings, object'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 11,889,170 84.1101583861762 ±0.83% 5944586
default/npm 8,038,085 124.40774010214119 ±1.08% 4019043
bind/local 11,455,585 87.29365778405887 ±1.05% 5727793
bind/npm 7,692,922 129.98961253129508 ±5.85% 3846462
dedupe/local 4,153,793 240.74381156052277 ±0.58% 2076897
dedupe/npm 4,116,693 242.91337563553066 ±0.75% 2058347

Benchmarking 'mix'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 7,100,003 140.84500547435223 ±0.64% 3551048
default/npm 5,585,523 179.03423958009992 ±0.56% 2792762
bind/local 6,472,166 154.50776833942365 ±0.88% 3236084
bind/npm 5,365,742 186.3674964740023 ±0.74% 2682872
dedupe/local 1,893,257 528.1902508800174 ±1.25% 946629
dedupe/npm 1,891,497 528.6815476395074 ±1.31% 945749

Benchmarking 'arrays'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 4,751,718 210.45016288852892 ±1.19% 2375860
default/npm 2,278,957 438.7971853808807 ±1.68% 1139479
bind/local 4,583,286 218.18406698385684 ±0.33% 2291644
bind/npm 2,235,513 447.32461197963715 ±0.51% 1117793
dedupe/local 1,944,499 514.2710681414202 ±0.59% 972250
dedupe/npm 1,939,009 515.727295888415 ±0.64% 969505

Firefox (v121.0)

Benchmarking 'strings'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 11.082.202 90.23477464135738 ±8.76% 5541101
default/npm 8.781.416 113.87685084045673 ±8.78% 4390708
bind/local 10.911.630 91.64533621466269 ±8.76% 5455815
bind/npm 8.855.560 112.92340631196672 ±8.76% 4427780
dedupe/local 3.758.688 266.05028137477757 ±8.78% 1879344
dedupe/npm 3.703.718 269.9989578040229 ±8.76% 1851859

Benchmarking 'object'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 9.902.228 100.9873737506347 ±9.02% 4951114
default/npm 7.651.803 130.68813576510846 ±8.76% 3825902
bind/local 9.526.018 104.97565719485308 ±8.76% 4763009
bind/npm 7.701.092 129.85171453606839 ±8.76% 3850546
dedupe/local 6.055.330 165.14376590540894 ±8.76% 3027665
dedupe/npm 5.919.786 168.92502533030753 ±8.76% 2959893

Benchmarking 'strings, object'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 8.606.194 116.19538207016946 ±8.76% 4303097
default/npm 7.293.585 137.10676750778015 ±8.76% 3646793
bind/local 8.921.412 112.08987994277139 ±8.76% 4460706
bind/npm 7.089.890 141.04591185476784 ±8.76% 3544945
dedupe/local 3.760.398 265.9292979094234 ±8.76% 1880199
dedupe/npm 3.856.122 259.3278947087255 ±8.76% 1928061

Benchmarking 'mix'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 3.315.880 301.57906800004827 ±8.76% 1657940
default/npm 5.127.774 195.01639502833004 ±8.76% 2563887
bind/local 3.431.400 291.4262400186513 ±8.76% 1715700
bind/npm 4.773.864 209.47391882131538 ±8.76% 2386932
dedupe/local 2.001.092 499.7271489766588 ±8.76% 1000546
dedupe/npm 1.711.712 584.2104279224543 ±10.93% 855856

Benchmarking 'arrays'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 2.531.368 395.0433125487878 ±8.76% 1265684
default/npm 2.500.206 399.96704271568024 ±8.76% 1250103
bind/local 2.544.506 393.00359283884575 ±8.76% 1272253
bind/npm 2.372.800 421.4430209035738 ±8.76% 1186400
dedupe/local 1.806.554 553.5400547118991 ±8.76% 903277
dedupe/npm 1.843.511 542.4429024600871 ±8.76% 921756

Chrome (v20.0.6099.129)

Benchmarking 'strings'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 6,079,274 164.4933220836579 ±2.80% 3040245
default/npm 4,827,402 207.15073913080562 ±2.77% 2414184
bind/local 6,118,850 163.4293964407515 ±2.77% 3060037
bind/npm 4,807,954 207.98866106037292 ±2.79% 2404458
dedupe/local 2,917,242 342.78946037163405 ±2.77% 1458913
dedupe/npm 2,871,063 348.30292881615543 ±2.77% 1435532

Benchmarking 'object'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 6,176,334 161.908323175497 ±2.79% 3088785
default/npm 4,955,749 201.78580437204536 ±2.77% 2477875
bind/local 6,167,353 162.1440896724422 ±2.77% 3083677
bind/npm 5,012,723 199.49235358612975 ±2.77% 2506863
dedupe/local 4,133,939 241.89997920043166 ±2.78% 2066970
dedupe/npm 4,245,313 235.55383654192497 ±2.77% 2122657

Benchmarking 'strings, object'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 5,586,087 179.01615585086677 ±2.77% 2793044
default/npm 4,579,777 218.35119518934383 ±2.77% 2289889
bind/local 5,512,019 181.4216929550079 ±2.77% 2756010
bind/npm 4,528,696 220.81410242391937 ±2.78% 2264801
dedupe/local 2,963,723 337.41342015640504 ±2.78% 1482158
dedupe/npm 3,005,034 332.7748270203765 ±2.78% 1502818

Benchmarking 'mix'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 4,398,837 227.3327637891942 ±2.78% 2199419
default/npm 3,769,216 265.307150980395 ±2.78% 1884985
bind/local 4,192,641 238.51312036674304 ±2.79% 2096740
bind/npm 3,750,153 266.6557181862266 ±2.82% 1875452
dedupe/local 1,826,352 547.5393574600067 ±2.77% 913359
dedupe/npm 1,807,754 553.1724734357562 ±2.77% 904058

Benchmarking 'arrays'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 3,592,981 278.3203478357115 ±2.77% 1796491
default/npm 2,113,115 473.2347869279158 ±2.77% 1056558
bind/local 3,417,504 292.6112156708522 ±2.77% 1708752
bind/npm 1,992,925 501.7749246898604 ±2.78% 996662
dedupe/local 1,716,015 582.745149236976 ±2.77% 858008
dedupe/npm 1,716,579 582.5536823261664 ±2.78% 858290

Safari (v17.2.1)

Benchmarking 'strings'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 7,532,417 132.75950840292913 ±8.76% 3773741
default/npm 5,796,919 172.50539941900684 ±8.76% 2898460
bind/local 7,685,053 130.12270493154236 ±8.76% 3850212
bind/npm 5,561,678 179.8018303897954 ±8.76% 2786401
dedupe/local 2,236,914 447.0444549946936 ±8.76% 1118457
dedupe/npm 2,166,442 461.58632448964704 ±8.76% 1083221

Benchmarking 'object'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 5,919,285 168.9393106601643 ±8.76% 2965562
default/npm 4,568,952 218.86856745935216 ±8.76% 2289045
bind/local 5,793,287 172.6135657724745 ±8.76% 2902437
bind/npm 4,735,435 211.1737968795424 ±8.76% 2367718
dedupe/local 3,391,844 294.8248528523692 ±8.76% 1699314
dedupe/npm 3,494,561 286.1588948772532 ±8.76% 1747281

Benchmarking 'strings, object'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 4,921,678 203.18270911088743 ±8.76% 2465761
default/npm 3,938,425 253.90859594625869 ±8.76% 1973151
bind/local 4,910,563 203.64259584033266 ±8.76% 2455282
bind/npm 4,075,674 245.35819106238623 ±8.76% 2037837
dedupe/local 2,119,897 471.7208092087724 ±8.76% 1059949
dedupe/npm 2,065,503 484.14333741311833 ±8.76% 1032752

Benchmarking 'mix'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 3,388,411 295.12356900406314 ±8.76% 1697594
default/npm 3,483,523 287.0656266470641 ±8.76% 1741762
bind/local 3,233,233 309.2878970274846 ±8.76% 1619850
bind/npm 3,505,233 285.28769641283355 ±8.76% 1756122
dedupe/local 1,262,257 792.231388492154 ±8.75% 632391
dedupe/npm 1,239,339 806.8815237015174 ±8.75% 620909

Benchmarking 'arrays'.

Task Name ops/sec Average Time (ns) Margin Samples
default/local 1,665,982 600.246568350727 ±8.75% 834657
default/npm 1,681,845 594.5847598413388 ±8.76% 840923
bind/local 1,649,921 606.0892575528342 ±8.76% 824961
bind/npm 1,651,295 605.5851632842516 ±8.75% 827299
dedupe/local 989,731 1010.3745256291603 ±8.76% 494866
dedupe/npm 960,853 1040.7408409602594 ±8.76% 480427

@jonkoops
Copy link
Collaborator Author

jonkoops commented Dec 24, 2023

@JedWatson @dcousens Since this refactors a pretty large swath of code from the core part of the library, I'd like to have a more formal review on this one. Let me know if you're available.

@jonkoops jonkoops force-pushed the string-concat branch 2 times, most recently from b4a328e to a246c8c Compare December 24, 2023 19:34
@dcousens
Copy link
Collaborator

Happy with this conceptually, but, probably need to verify this result across different browsers, the node benchmarks are marginally helpful at best.

@dcousens
Copy link
Collaborator

Similar to #292

@jonkoops
Copy link
Collaborator Author

Sure, I can run some browser benchmarks and get back to this 👍

@jonkoops
Copy link
Collaborator Author

@dcousens updated the PR description with benchmarks in all the latest versions of major browsers. And added some code to easily format the results as markdown.

@dcousens
Copy link
Collaborator

dcousens commented Dec 26, 2023

Numbers LGTM, limited regressions and the major usecases 'strings, object', and string are improvements.

@dcousens dcousens merged commit a6391d4 into main Dec 26, 2023
5 checks passed
@dcousens dcousens deleted the string-concat branch December 26, 2023 00:47
CrispyBaguette pushed a commit to CrispyBaguette/wasm-palette-converter that referenced this pull request Nov 8, 2024
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [classnames](https://github.com/JedWatson/classnames) | dependencies | minor | [`2.3.1` -> `2.5.1`](https://renovatebot.com/diffs/npm/classnames/2.3.1/2.5.1) |

---

### Release Notes

<details>
<summary>JedWatson/classnames (classnames)</summary>

### [`v2.5.1`](https://github.com/JedWatson/classnames/blob/HEAD/HISTORY.md#v251--2023-12-29)

[Compare Source](JedWatson/classnames@v2.5.0...v2.5.1)

-   Remove `workspaces` field from package ([#&#8203;350](JedWatson/classnames#350))

### [`v2.5.0`](https://github.com/JedWatson/classnames/blob/HEAD/HISTORY.md#v250--2023-12-27)

[Compare Source](JedWatson/classnames@v2.4.0...v2.5.0)

-   Restore ability to pass a TypeScript `interface` ([#&#8203;341](JedWatson/classnames#341))
-   Add `exports` field to package ([#&#8203;342](JedWatson/classnames#342))

### [`v2.4.0`](https://github.com/JedWatson/classnames/blob/HEAD/HISTORY.md#v240--2023-12-26)

[Compare Source](JedWatson/classnames@v2.3.3...v2.4.0)

-   Use string concatenation to increase performance thanks [Jon Koops](https://github.com/jonkoops) ([#&#8203;336](JedWatson/classnames#336))

### [`v2.3.3`](https://github.com/JedWatson/classnames/blob/HEAD/HISTORY.md#v233--2023-12-21)

[Compare Source](JedWatson/classnames@v2.3.2...v2.3.3)

-   Fix default export, thanks [Remco Haszing](https://github.com/remcohaszing) ([#&#8203;301](JedWatson/classnames#301))
-   Fix types for read-only arrays, thanks [Ben Thompson](https://github.com/BenGearset) ([#&#8203;307](JedWatson/classnames#307))
-   Replace README examples with functional-style components, thanks [JoeDGit](https://github.com/JoeDGit) ([#&#8203;303](JedWatson/classnames#303))

### [`v2.3.2`](https://github.com/JedWatson/classnames/blob/HEAD/HISTORY.md#v232--2022-09-13)

[Compare Source](JedWatson/classnames@v2.3.1...v2.3.2)

-   Fix TypeScript types when using require, thanks [Mark Dalgleish](https://github.com/markdalgleish) ([#&#8203;276](JedWatson/classnames#276))
-   Fix toString as `[Object object]` in a vm, thanks [Remco Haszing](https://github.com/remcohaszing) ([#&#8203;281](JedWatson/classnames#281))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update 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:eyJjcmVhdGVkSW5WZXIiOiIzOC4xNDIuNSIsInVwZGF0ZWRJblZlciI6IjM4LjE0Mi41IiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=-->

Reviewed-on: https://gitea.bruyant.xyz/alexandre/PaletteSwitcher/pulls/48
Co-authored-by: Renovate <renovate@bruyant.xyz>
Co-committed-by: Renovate <renovate@bruyant.xyz>
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