jw3126 / Setfield.jl

Update deeply nested immutable structs.
Other
167 stars 17 forks source link

Performance #4

Closed jw3126 closed 6 years ago

jw3126 commented 6 years ago
using Revise
using Setfield
using Setfield: FieldLens, compose, set
using BenchmarkTools
struct AB{A,B}
    a::A
    b::B
end

x = AB(AB(AB(0,1),2),3)

l = mapreduce(FieldLens, compose, Iterators.repeated(:a, 3))

function doit(l, x)
    set(l,x,2)
end

function doit(x)
    @set x.a.a.a = 2
end

function doit_manual(x)
    AB(AB(AB(2, x.a.a.b),x.a.b),x.b)
end

display(@benchmark doit($x))
display(@benchmark doit_manual($x))
display(@benchmark doit($l, $x))
BenchmarkTools.Trial: 
  memory estimate:  0 bytes
  allocs estimate:  0
  --------------
  minimum time:     9.452 ns (0.00% GC)
  median time:      9.453 ns (0.00% GC)
  mean time:        9.546 ns (0.00% GC)
  maximum time:     34.315 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     999

BenchmarkTools.Trial: 
  memory estimate:  0 bytes
  allocs estimate:  0
  --------------
  minimum time:     2.084 ns (0.00% GC)
  median time:      2.097 ns (0.00% GC)
  mean time:        2.162 ns (0.00% GC)
  maximum time:     21.556 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000

BenchmarkTools.Trial: 
  memory estimate:  0 bytes
  allocs estimate:  0
  --------------
  minimum time:     2.086 ns (0.00% GC)
  median time:      2.099 ns (0.00% GC)
  mean time:        2.139 ns (0.00% GC)
  maximum time:     11.284 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000
jw3126 commented 6 years ago

On master they are all fast:

julia> versioninfo()
Julia Version 0.7.0-DEV.2790
Commit e2e6fd2* (2017-12-07 17:55 UTC)
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: Intel(R) Core(TM) i7-3630QM CPU @ 2.40GHz
  WORD_SIZE: 64
  BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Sandybridge)
  LAPACK: libopenblas64_
  LIBM: libopenlibm
  LLVM: libLLVM-3.9.1 (ORCJIT, ivybridge)
Environment:

julia> struct AB{A,B}
           a::A
           b::B
       end

julia> l1 = mapreduce(FieldLens, compose, Iterators.repeated( :a, 3))
(@lens _.a.a.a)

julia> l2 = @lens _.a.a.a
(@lens _.a.a.a)

julia> show_generic(l1)
Setfield.ComposedLens{Setfield.ComposedLens{FieldLens{:a},FieldLens{:a}},FieldLens{:a}}((@lens _.a.a), (@lens _.a))
julia> println()

julia> show_generic(l2)
Setfield.ComposedLens{Setfield.ComposedLens{FieldLens{:a},FieldLens{:a}},FieldLens{:a}}((@lens _.a.a), (@lens _.a))
julia> function doit(l, x)
           set(l,x,2)
       end
doit (generic function with 1 method)

julia> function doit(x)
           @set x.a.a.a = 2
       end
doit (generic function with 2 methods)

julia> function doit_expand_by_hand(x)
           l = @lens _.a.a.a
           set(l, x, 2)
       end
doit_expand_by_hand (generic function with 1 method)

julia> function doit_hand_optimize(x)
           AB(AB(AB(2, x.a.a.b),x.a.b),x.b)
       end
doit_hand_optimize (generic function with 1 method)

julia> x = AB(AB(AB(0,1),2),3)
AB{AB{AB{Int64,Int64},Int64},Int64}(AB{AB{Int64,Int64},Int64}(AB{Int64,Int64}(0, 1), 2), 3)

julia> display(@benchmark doit($x))
BenchmarkTools.Trial: 
  memory estimate:  0 bytes
  allocs estimate:  0
  --------------
  minimum time:     2.142 ns (0.00% GC)
  median time:      2.155 ns (0.00% GC)
  mean time:        2.157 ns (0.00% GC)
  maximum time:     14.195 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000

julia> display(@benchmark doit_hand_optimize($x))
BenchmarkTools.Trial: 
  memory estimate:  0 bytes
  allocs estimate:  0
  --------------
  minimum time:     2.141 ns (0.00% GC)
  median time:      2.155 ns (0.00% GC)
  mean time:        2.155 ns (0.00% GC)
  maximum time:     15.509 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000

julia> display(@benchmark doit_expand_by_hand($x))
BenchmarkTools.Trial: 
  memory estimate:  0 bytes
  allocs estimate:  0
  --------------
  minimum time:     2.084 ns (0.00% GC)
  median time:      2.087 ns (0.00% GC)
  mean time:        2.095 ns (0.00% GC)
  maximum time:     11.137 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000

julia> display(@benchmark doit($l1, $x))
BenchmarkTools.Trial: 
  memory estimate:  0 bytes
  allocs estimate:  0
  --------------
  minimum time:     2.084 ns (0.00% GC)
  median time:      2.086 ns (0.00% GC)
  mean time:        2.098 ns (0.00% GC)
  maximum time:     31.635 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000

julia> display(@benchmark doit($l2, $x))
BenchmarkTools.Trial: 
  memory estimate:  0 bytes
  allocs estimate:  0
  --------------
  minimum time:     2.364 ns (0.00% GC)
  median time:      2.533 ns (0.00% GC)
  mean time:        2.497 ns (0.00% GC)
  maximum time:     17.158 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000