Rails 6 includes a change
in
Date#advance
method that optimised memory usage
and
time required to perform advance operation.
Previously,
advance
operation on Date
class
used to duplicate options (arguments) passed
to
the method.
These options were used up
and
deleted from the options
hash
in
advance
method.
Before Rails 6
def advance ( options )
options = options . dup
d = self
d = d >> options . delete ( :years ) * 12 if options [ :years ]
d = d >> options . delete ( :months ) if options [ :months ]
d = d + options . delete ( :weeks ) * 7 if options [ :weeks ]
d = d + options . delete ( :days ) if options [ :days ]
d
end
As we can see,
there is really no need to dup
the options
has received in the argument.
After Rails 6
With the pull request
the behavior was changed
to
not duplicate the options
has as given below.
def advance ( options )
d = self
d = d >> options [ :years ] * 12 if options [ :years ]
d = d >> options [ :months ] if options [ :months ]
d = d + options [ :weeks ] * 7 if options [ :weeks ]
d = d + options [ :days ] if options [ :days ]
d
end
This improved the speed of Date#advance
operation
also
it allocates less objects (thus memory)
in order to perform the operation.
Benchmarking
is available
on
this pull request
Mentioning Benchmark performance below for the reference.
Memory comparison:
Options : { :years => 1 , :months => 1 , :weeks => 1 , :days => 1 }
Calculating -------------------------------------
master 576.000 memsize ( 0.000 retained )
5.000 objects ( 0.000 retained )
0.000 strings ( 0.000 retained )
advance_no_dup 288.000 memsize ( 0.000 retained )
4.000 objects ( 0.000 retained )
0.000 strings ( 0.000 retained )
Comparison :
advance_no_dup: 288 allocated
master: 576 allocated - 2.00 x more
Options : { :years => 1 }
Calculating -------------------------------------
master 264.000 memsize ( 0.000 retained )
2.000 objects ( 0.000 retained )
0.000 strings ( 0.000 retained )
advance_no_dup 72.000 memsize ( 0.000 retained )
1.000 objects ( 0.000 retained )
0.000 strings ( 0.000 retained )
Comparison :
advance_no_dup: 72 allocated
master: 264 allocated - 3.67 x more
Options : { :weeks => 1 }
Calculating -------------------------------------
master 264.000 memsize ( 0.000 retained )
2.000 objects ( 0.000 retained )
0.000 strings ( 0.000 retained )
advance_no_dup 72.000 memsize ( 0.000 retained )
1.000 objects ( 0.000 retained )
0.000 strings ( 0.000 retained )
Comparison :
advance_no_dup: 72 allocated
master: 264 allocated - 3.67 x more
Peformance comparison:
Options : { :years => 1 , :months => 1 , :weeks => 1 , :days => 1 }
Warming up --------------------------------------
master 27.740 k i / 100 ms
advance_no_dup 37.705 k i / 100 ms
Calculating -------------------------------------
master 338.511 k ( ± 5.9 % ) i / s - 1.692 M in 5.020333 s
advance_no_dup 572.980 k ( ± 3.7 % ) i / s - 2.866 M in 5.008680 s
Comparison :
advance_no_dup: 572979.7 i / s
master: 338510.9 i / s - 1.69 x slower
Options : { :years => 1 }
Warming up --------------------------------------
master 53.313 k i / 100 ms
advance_no_dup 115.016 k i / 100 ms
Calculating -------------------------------------
master 639.715 k ( ± 1.7 % ) i / s - 3.199 M in 5.001851 s
advance_no_dup 1.579 M ( ± 6.4 % ) i / s - 7.936 M in 5.053876 s
Comparison :
advance_no_dup: 1579251.7 i / s
master: 639714.8 i / s - 2.47 x slower
Options : { :weeks => 1 }
Warming up --------------------------------------
master 57.353 k i / 100 ms
advance_no_dup 129.141 k i / 100 ms
Calculating -------------------------------------
master 674.113 k ( ± 3.4 % ) i / s - 3.384 M in 5.025973 s
advance_no_dup 1.911 M ( ± 2.5 % ) i / s - 9.556 M in 5.004496 s
Comparison :
advance_no_dup: 1910739.3 i / s
master: 674112.6 i / s - 2.83 x slower
Reference