Skip to content

Conversation

@unadlib
Copy link
Owner

@unadlib unadlib commented Sep 17, 2025

This PR primarily refactors the draft cache by changing the original global draft cache into a built-in cache option. This helps to separate unrelated WeakSet caches, thereby improving performance.

Before:

----------------------------------------------- -------------------------------
update: vanilla (freeze: false)   55.98 µs/iter  80.17 µs █
                         (42.71 µs … 393.08 µs)  89.50 µs █               ▂
                        ( 11.11 kb … 295.45 kb)  84.01 kb █▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁█▂▂▁▁

update: immer10 (freeze: false)  445.57 µs/iter 443.38 µs   █
                        (436.04 µs … 851.83 µs) 487.33 µs   ██
                        ( 21.17 kb …   1.33 mb)  87.96 kb ▁▇██▄▂▁▂▂▂▁▁▁▁▁▁▁▁▁▁▁

update: mutative (freeze: false)  12.45 µs/iter   4.29 µs  ▇█
                            (3.67 µs … 1.73 ms)   8.04 µs  ██▆
                        (  3.45 kb … 416.33 kb)  87.49 kb ▂███▅▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁

update: vanilla (freeze: true)    46.82 µs/iter  47.05 µs █ █       █
                          (46.28 µs … 47.32 µs)  47.31 µs █ █       █ ▅ ▅▅   ▅▅
                        (  1.31 kb …   1.31 kb)   1.31 kb █▁█▁▁▁▁▁▁▁█▁█▁██▁▁▁██

update: immer10 (freeze: true)   477.48 µs/iter 476.67 µs █▅▆
                        (472.92 µs … 836.71 µs) 514.42 µs ███
                        ( 83.83 kb …   1.09 mb)  86.20 kb ███▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

update: mutative (freeze: true)   12.06 µs/iter   4.21 µs  █
                            (3.67 µs … 1.68 ms)   7.71 µs  ██▃
                        (  1.02 kb … 384.77 kb)  85.20 kb ▂███▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

summary
  update: mutative (freeze: true)
   1.03x faster than update: mutative (freeze: false)
   3.88x faster than update: vanilla (freeze: true)
   4.64x faster than update: vanilla (freeze: false)
   36.94x faster than update: immer10 (freeze: false)
   39.59x faster than update: immer10 (freeze: true)

After:

----------------------------------------------- -------------------------------
update: vanilla (freeze: false)   53.47 µs/iter  78.17 µs █
                         (40.50 µs … 417.29 µs)  86.88 µs █
                        ( 14.61 kb … 285.95 kb)  84.00 kb █▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁█▂▂▁▁

update: immer10 (freeze: false)  432.56 µs/iter 432.38 µs  █
                        (423.54 µs … 797.04 µs) 483.00 µs  █▄
                        ( 80.33 kb …   1.05 mb)  88.21 kb ▄██▇▅▃▂▁▁▁▁▂▁▁▁▁▁▁▁▁▁

update: mutative (freeze: false)   3.87 µs/iter   3.87 µs     █  ▅
                            (3.83 µs … 3.97 µs)   3.96 µs  ▃█▃█▃▃█▃▃
                        (  1.34 kb …   2.64 kb)   2.56 kb ▄█████████▄▁▁▁▁▁▁▁▁▁█

update: vanilla (freeze: true)    42.82 µs/iter  43.16 µs    █  █             █
                          (42.33 µs … 43.33 µs)  43.28 µs ▅  █ ▅█    ▅▅    ▅  █
                        (  1.31 kb …   1.31 kb)   1.31 kb █▁▁█▁██▁▁▁▁██▁▁▁▁█▁▁█

update: immer10 (freeze: true)   468.23 µs/iter 467.33 µs  █
                        (460.88 µs … 780.83 µs) 512.21 µs  █▆
                        (  5.97 kb … 940.83 kb)  85.95 kb ▆██▆▄▂▁▂▂▂▁▁▁▁▁▁▁▁▁▁▁

update: mutative (freeze: true)    3.73 µs/iter   3.74 µs   ▄▄█   ▄
                            (3.70 µs … 3.84 µs)   3.81 µs   ███▅ ██
                        (  1.31 kb …   3.61 kb)   1.39 kb █████████▅██▅▁▁▁▁▁▁▁▅

summary
  update: mutative (freeze: true)
   1.04x faster than update: mutative (freeze: false)
   11.47x faster than update: vanilla (freeze: true)
   14.33x faster than update: vanilla (freeze: false)
   115.9x faster than update: immer10 (freeze: false)
   125.45x faster than update: immer10 (freeze: true)

Overall, this results in a 2-3X performance improvement for Array operations.

@github-actions
Copy link

Coverage after merging perf-cache 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.ts99.30%98.41%100%100%15
   deepFreeze.ts96.64%93.10%100%100%67–68, 75, 84
   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 merged commit e1134a6 into main Sep 17, 2025
3 checks passed
@unadlib unadlib deleted the perf-cache branch September 17, 2025 16:42
@unadlib
Copy link
Owner Author

unadlib commented Sep 21, 2025

Array performance benchmarking source code: https://github.com/immerjs/immer/tree/main/perf-testing

@unadlib
Copy link
Owner Author

unadlib commented Sep 29, 2025

Complete set of group operation benchmarks:


clk: ~3.03 GHz
cpu: Apple M1 Max
runtime: node 22.17.1 (arm64-darwin)

benchmark                        avg (min … max) p75 / p99    (min … top 1%)
------------------------------------------------ -------------------------------
add: immer10 (freeze: false)      469.42 µs/iter 465.25 µs █                    
                           (459.54 µs … 1.22 ms) 627.83 µs █▃                   
                         ( 25.87 kb … 933.88 kb) 252.40 kb ██▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

add: mutative (freeze: false)      10.46 µs/iter   9.08 µs █                    
                           (8.13 µs … 259.54 µs)  96.25 µs █                    
                         (  5.52 kb … 715.53 kb) 251.90 kb █▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

add: immer10 (freeze: true)       486.01 µs/iter 483.17 µs █                    
                         (478.08 µs … 855.88 µs) 630.88 µs ██                   
                         ( 53.30 kb …   1.36 mb) 255.00 kb ██▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

add: mutative (freeze: true)       10.34 µs/iter  10.33 µs  █                   
                           (10.25 µs … 10.59 µs)  10.51 µs  █ ▇                 
                         (198.13  b … 198.13  b) 198.13  b ▆█▁█▁▁▆▁▁▁▁▁▁▁▁▁▁▁▆▁▆

summary
  add: mutative (freeze: true)
   1.01x faster than add: mutative (freeze: false)
   45.41x faster than add: immer10 (freeze: false)
   47.01x faster than add: immer10 (freeze: true)

------------------------------------------------ -------------------------------
remove: immer10 (freeze: false)    10.24 ms/iter  10.36 ms               ▄█     
                            (9.64 ms … 10.65 ms)  10.60 ms             ▂▅██     
                         ( 11.38 mb …  11.86 mb)  11.60 mb ▅▄▁▁▂▁▅▄▂▁▁▂████▅▄▁▁▅

remove: mutative (freeze: false)    9.35 ms/iter   9.42 ms  ▅ █                 
                            (8.85 ms … 12.47 ms)  11.73 ms  █▆█                 
                         (  2.00 mb …  12.69 mb)   5.57 mb ▄███▇█▃▃▂▁▁▁▁▂▁▁▁▁▁▁▂

remove: immer10 (freeze: true)      5.71 ms/iter   5.82 ms   █                  
                             (5.39 ms … 6.38 ms)   6.31 ms  ▂█      ▅           
                         (  5.64 mb …   7.64 mb)   5.71 mb ▇███▂▁▁▂▂█▃▂▁▁▁▁▂▁▄█▅

remove: mutative (freeze: true)     9.07 ms/iter   9.07 ms    ▂█                
                            (8.70 ms … 11.51 ms)  10.21 ms    ███               
                         (  3.03 mb …  11.78 mb)   5.48 mb ▃▆█████▂▁▁▁▂▁▃▁▁▁▁▂▁▂

summary
  remove: immer10 (freeze: true)
   1.59x faster than remove: mutative (freeze: true)
   1.64x faster than remove: mutative (freeze: false)
   1.79x faster than remove: immer10 (freeze: false)

------------------------------------------------ -------------------------------
filter: immer10 (freeze: false)     8.16 ms/iter   8.27 ms             █        
                             (7.51 ms … 8.85 ms)   8.78 ms            ██        
                         ( 11.54 mb …  11.84 mb)  11.63 mb ▆▃▁▁▁█▃▁▁▅████▄▁▃▂▁▁▂

filter: mutative (freeze: false)    5.78 ms/iter   6.01 ms ▇   █    ▆           
                             (5.18 ms … 8.49 ms)   6.95 ms █  ██   ▃█           
                         (  8.81 mb …   9.90 mb)   8.88 mb █▅▇██▅▂▂██▆██▁▂▁▆▁▃▂▂

filter: immer10 (freeze: true)      3.76 ms/iter   3.98 ms  █                   
                             (3.39 ms … 4.80 ms)   4.69 ms ▂█                   
                         (  4.25 mb …   6.70 mb)   5.69 mb ███▄▂▃▇█▄▂▃▁▂█▇▂▁▂▁▁▁

filter: mutative (freeze: true)     5.55 ms/iter   5.91 ms  █             ▆     
                             (5.09 ms … 6.63 ms)   6.18 ms ▆█   ▂█▆       █▆    
                         (  8.80 mb …  10.66 mb)   8.89 mb ███▂▂███▃▁▂▂▂▁███▃▆▃▂

summary
  filter: immer10 (freeze: true)
   1.48x faster than filter: mutative (freeze: true)
   1.54x faster than filter: mutative (freeze: false)
   2.17x faster than filter: immer10 (freeze: false)

------------------------------------------------ -------------------------------
update: immer10 (freeze: false)   447.77 µs/iter 445.33 µs  █                   
                           (436.83 µs … 1.15 ms) 504.08 µs  ██                  
                         ( 14.70 kb …   1.19 mb)  91.78 kb ▁██▅▂▂▃▂▂▁▂▁▁▁▁▁▁▁▁▁▁

update: mutative (freeze: false)    3.81 µs/iter   3.82 µs ▄ █  █               
                             (3.77 µs … 3.93 µs)   3.88 µs █ █▅██▅              
                         (  2.02 kb …   2.66 kb)   2.60 kb █▅█████▅██▅▁▅▅▁█▁▁▁▅▅

update: immer10 (freeze: true)    479.36 µs/iter 477.79 µs  █                   
                         (473.58 µs … 948.67 µs) 521.46 µs ██▅                  
                         ( 83.83 kb … 999.34 kb)  86.23 kb ███▅▃▂▁▂▁▁▁▁▁▁▁▁▁▁▁▁▁

update: mutative (freeze: true)     3.81 µs/iter   3.82 µs       █ ▅            
                             (3.75 µs … 4.02 µs)   3.93 µs ▆ █▃  █▆█            
                         (  1.31 kb …   3.55 kb)   1.39 kb ████▄████▄█▁▁▁▄▄▁▁▁▁▄

summary
  update: mutative (freeze: false)
   1x faster than update: mutative (freeze: true)
   117.59x faster than update: immer10 (freeze: false)
   125.89x faster than update: immer10 (freeze: true)

------------------------------------------------ -------------------------------
concat: immer10 (freeze: false)    20.63 µs/iter  20.67 µs  █     █             
                           (20.49 µs … 21.04 µs)  20.77 µs ▅█ ▅  ▅█  ▅  ▅     ▅▅
                         (  5.59  b …  33.10  b)  19.34  b ██▁█▁▁██▁▁█▁▁█▁▁▁▁▁██

concat: mutative (freeze: false)   20.36 µs/iter  20.30 µs            █         
                           (20.19 µs … 21.40 µs)  20.35 µs ▅ ▅▅▅   ▅ ▅█  ▅    ▅▅
                         (  2.93  b …   3.94 kb)   1.97 kb █▁███▁▁▁█▁██▁▁█▁▁▁▁██

concat: immer10 (freeze: true)    620.15 µs/iter 621.17 µs ▆█                   
                         (605.79 µs … 993.50 µs) 790.63 µs ███                  
                         ( 75.84 kb …   1.61 mb) 414.53 kb ███▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

concat: mutative (freeze: true)    20.39 µs/iter  20.39 µs █   █     █          
                           (20.17 µs … 21.18 µs)  20.62 µs █▅ ▅█▅    █        ▅▅
                         ( 66.02  b …  66.02  b)  66.02  b ██▁███▁▁▁▁█▁▁▁▁▁▁▁▁██

summary
  concat: mutative (freeze: false)
   1x faster than concat: mutative (freeze: true)
   1.01x faster than concat: immer10 (freeze: false)
   30.46x faster than concat: immer10 (freeze: true)

------------------------------------------------ -------------------------------
reverse: immer10 (freeze: false)   10.45 ms/iter  10.61 ms                ▄ ▆█  
                            (9.85 ms … 10.73 ms)  10.71 ms               ▃████  
                         ( 11.47 mb …  11.75 mb)  11.58 mb ▅▅▃▇▅▃▅▁▁▁▁▁▁▁███████

reverse: mutative (freeze: false)   9.56 ms/iter   9.62 ms     █▃▄              
                            (9.14 ms … 11.97 ms)  10.48 ms    ████              
                         (  2.77 mb …  11.40 mb)   5.44 mb ▆▃▆████▆▆█▃▃█▃▁▁▁▁▁▁▃

reverse: immer10 (freeze: true)     6.02 ms/iter   6.20 ms   █                  
                             (5.66 ms … 6.88 ms)   6.75 ms  ▆█▄            ▂    
                         (  5.59 mb …   7.69 mb)   5.71 mb ▇███▅▂▁▅█▇▃▂▂▂▁▅█▇▁▂▂

reverse: mutative (freeze: true)    9.41 ms/iter   9.45 ms     ▂█               
                            (9.08 ms … 11.34 ms)  10.00 ms    ▅██ ▅▆▃           
                         (  3.27 mb …  11.44 mb)   5.46 mb ▇▇▇███████▃▃▅▇▁▁▁▁▁▇▃

summary
  reverse: immer10 (freeze: true)
   1.56x faster than reverse: mutative (freeze: true)
   1.59x faster than reverse: mutative (freeze: false)
   1.74x faster than reverse: immer10 (freeze: false)

------------------------------------------------ -------------------------------
sort: immer10 (freeze: false)       9.30 ms/iter   9.68 ms  █          ▄  ▄     
                            (8.70 ms … 10.08 ms)   9.99 ms ██▃         █  █▃    
                         (  8.43 mb …   8.66 mb)   8.58 mb ███▃▁▅▃▃▃▇▃▇█▅▅███▃▅▃

sort: mutative (freeze: false)      8.87 ms/iter   9.29 ms █       ▃     ▅      
                             (8.29 ms … 9.76 ms)   9.72 ms █▅     ▇█     █      
                         (  8.57 mb …  11.72 mb)   8.74 mb ██▃▁▁▁▁██▄▃▁▁▃██▄▄▃▃▃

sort: immer10 (freeze: true)        9.52 ms/iter   9.89 ms  █              █    
                            (8.98 ms … 10.30 ms)  10.18 ms ██        ▃ ▅   █    
                         (  8.54 mb …   9.92 mb)   8.64 mb ██▃▃▁█▃▇▁▃█▇█▇▇▅█▃▃▃▃

sort: mutative (freeze: true)       8.79 ms/iter   9.25 ms ▃▃       ▃▄        █ 
                             (8.21 ms … 9.38 ms)   9.36 ms ██       ██       ██ 
                         (  8.25 mb …   8.68 mb)   8.63 mb ██▅▅▁▁▁▁▁██▅▃▃▃▁▁▃██▆

summary
  sort: mutative (freeze: true)
   1.01x faster than sort: mutative (freeze: false)
   1.06x faster than sort: immer10 (freeze: false)
   1.08x faster than sort: immer10 (freeze: true)

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