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(array): improve array method perf #75

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open

perf(array): improve array method perf #75

wants to merge 14 commits into from

Conversation

unadlib
Copy link
Owner

@unadlib unadlib commented Jan 3, 2025

We noticed in the Redux community’s benchmarks involving Mutative that the results for remove-related operations were not very satisfactory. reduxjs/redux-toolkit#4793

After analyzing Mutative, we found that whenever an array uses native methods to mutate its contents, the proxy mechanism unnecessarily instantiates a draft for each potentially accessed item. This unnecessary instantiation is the main cause of the poor performance. This PR addresses that issue.

Copy link

github-actions bot commented Jan 3, 2025

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

@unadlib
Copy link
Owner Author

unadlib commented Jan 3, 2025

  • Based on the benchmark comparison from test/performance/benchmark-reducer1.mjs:

Before:

remove: vanilla (freeze: false)
   1.04x faster than remove: vanilla (freeze: true)
   2349.65x faster than remove: immer10 (freeze: true)
   3000.06x faster than remove: mutative (freeze: true)
   3272.53x faster than remove: mutative (freeze: false)
   5046.97x faster than remove: immer10 (freeze: false)

After:

remove: vanilla (freeze: false)
   1.05x faster than remove: vanilla (freeze: true)
   1227.82x faster than remove: mutative (freeze: false)
   1391.1x faster than remove: mutative (freeze: true)
   2315.1x faster than remove: immer10 (freeze: true)
   5021.75x faster than remove: immer10 (freeze: false)

  • Based on the benchmark comparison from test/performance/benchmark-reducer.ts:

Beforce:

[remove]immer:autoFreeze: 237.964ms
[remove]immer:autoFreeze:nextAction(10): 79.223ms
-------------------------------------------------------
[remove]mutative:autoFreeze: 110.817ms
[remove]mutative:autoFreeze:nextAction(10): 152.14ms
-------------------------------------------------------
[remove]immer:noAutoFreeze: 22.608ms
[remove]immer:noAutoFreeze:nextAction(10): 113.472ms
-------------------------------------------------------
[remove]mutative:noAutoFreeze: 13.998ms
[remove]mutative:noAutoFreeze:nextAction(10): 138.987ms
-------------------------------------------------------
[remove]vanilla: 0.133ms
[remove]vanilla:nextAction(10): 3.522ms

After:

[remove]immer:autoFreeze: 239.758ms
[remove]immer:autoFreeze:nextAction(10): 79.93ms
-------------------------------------------------------
[remove]mutative:autoFreeze: 99.946ms
[remove]mutative:autoFreeze:nextAction(10): 65.956ms
-------------------------------------------------------
[remove]immer:noAutoFreeze: 20.47ms
[remove]immer:noAutoFreeze:nextAction(10): 108.389ms
-------------------------------------------------------
[remove]mutative:noAutoFreeze: 7.869ms
[remove]mutative:noAutoFreeze:nextAction(10): 64.314ms
-------------------------------------------------------
[remove]vanilla: 0.207ms
[remove]vanilla:nextAction(10): 0.686ms

From the comparison of the two benchmark tests above, we can see that Mutative’s deletion operation performance has improved by 2–3X.

I will continue adding more test sets to ensure the correctness of immutable updates.

Copy link

github-actions bot commented Jan 4, 2025

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts99.28%98.44%100%100%25
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

Copy link

github-actions bot commented Jan 4, 2025

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts99.28%98.44%100%100%25
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

Copy link

github-actions bot commented Jan 4, 2025

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts99.28%98.44%100%100%25
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

Copy link

github-actions bot commented Jan 4, 2025

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts99.28%98.44%100%100%25
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

Copy link

github-actions bot commented Jan 4, 2025

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts99.28%98.44%100%100%25
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

Copy link

github-actions bot commented Jan 4, 2025

Coverage after merging perf/array into main will be

99.89%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts99.42%99.39%100%99.38%156–157
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts99.28%98.44%100%100%25
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

Copy link

github-actions bot commented Jan 4, 2025

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

@unadlib unadlib changed the title perf(array): improve array remove method perf perf(array): improve array method perf Jan 4, 2025
Copy link

github-actions bot commented Jan 4, 2025

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

Copy link

github-actions bot commented Jan 4, 2025

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

@unadlib
Copy link
Owner Author

unadlib commented Jan 4, 2025

This PR focuses solely on performance optimization for Array operations such as splice, shift, reverse, and unshift, while ensuring the correctness of immutable updates.

However, the optimization makes the draft getters more complex, so we are carefully considering whether to merge this PR into the main branch.

Copy link

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts99.71%99.39%100%100%102
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

Copy link

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts99.71%99.39%100%100%102
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

Copy link

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts99.71%99.39%100%100%102
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

Copy link

Coverage after merging perf/array into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.ts100%100%100%100%
src
   apply.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

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.

1 participant