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

Performance in structs #3

Closed
davidanthoff opened this issue May 13, 2017 · 4 comments
Closed

Performance in structs #3

davidanthoff opened this issue May 13, 2017 · 4 comments

Comments

@davidanthoff
Copy link

Very excited to see this! A very basic question: the optimizations for Union{T,Null} are not in base yet, right? I.e. this is more in prep for once that is there, right?

I'm asking because I just compared the following:

struct Foo
    v::Union{Float64,Null}
end

struct Foo2
    v::Nullable{Float64}
end

function foo1()
    a = Foo(3.)
    b = Foo(2.)
    c = a.v + b.v
    return c
end

function foo2()
    a = Foo2(Nullable(3.))
    b = Foo2(Nullable(2.))
    c = get(a.v) + get(b.v)
    return c
end

When I benchmark these two, I get this:

julia> @benchmark foo1()
BenchmarkTools.Trial:
  memory estimate:  16 bytes
  allocs estimate:  1
  --------------
  minimum time:     19.018 ns (0.00% GC)
  median time:      20.527 ns (0.00% GC)
  mean time:        22.870 ns (3.06% GC)
  maximum time:     1.201 μs (97.81% GC)
  --------------
  samples:          10000
  evals/sample:     1000

julia> @benchmark foo2()
BenchmarkTools.Trial:
  memory estimate:  0 bytes
  allocs estimate:  0
  --------------
  minimum time:     2.716 ns (0.00% GC)
  median time:      3.019 ns (0.00% GC)
  mean time:        3.292 ns (0.00% GC)
  maximum time:     30.187 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000

The Nullable implementation here is almost an order of magnitude faster.

I'm pretty sure that I could use Union{T,Null} for Query.jl if the kind of example here was as fast as the Nullable implementation.

@ararslan
Copy link
Member

ararslan commented May 13, 2017

Correct, the Base optimizations are not yet in place. The purpose of this so far is to try to nail down a good design.

@quinnj
Copy link
Member

quinnj commented May 13, 2017

Yeah, we're a bit pre-emptive to the optimizations needed for this approach, but @vtjnash has mentioned that they should be forth-coming now that 0.6 is being released. This is definitely an effort to jumpstart the design & experimentation; I'm particularly interested to see if this can help simplify some things in the DataStreams framework and help coordinate efforts among a bunch of data-related packages (from DB, to "table"-type packages, to stats and machine learning).

@quinnj
Copy link
Member

quinnj commented May 13, 2017

Would definitely appreciate your input and feedback! It's pretty small and simple for now (which hopefully how it can stay!), but we definitely want to cover any use-cases you'd run into w/ IterableTables + Query.jl and related packages.

@quinnj
Copy link
Member

quinnj commented Sep 27, 2017

The optimizations are now in Base; there is still one outstanding codegen issue w/ inferred Union types, but I'm assured it will be resolved soon and there exists a current workaround. So w/ the current workaround in the original benchmarks I now see

julia> struct Foo
           v::Union{Float64,Null}
       end

julia> struct Foo2
           v::Nullable{Float64}
       end

julia> function foo1()
           a = Foo(3.)
           b = 2.
           v = a.v
           if v isa Null
               return null
           else
               return v + b
           end
       end
foo1 (generic function with 2 methods)

julia> function foo2()
           a = Foo2(Nullable(3.))
           b = Foo2(Nullable(2.))
           c = get(a.v) + get(b.v)
           return c
       end
foo2 (generic function with 1 method)

julia> b = @benchmarkable foo1()
Benchmark(evals=1, seconds=5.0, samples=10000)

julia> tune!(b)
Benchmark(evals=1000, seconds=5.0, samples=10000)

julia> run(b)
BenchmarkTools.Trial:
  memory estimate:  0 bytes
  allocs estimate:  0
  --------------
  minimum time:     1.384 ns (0.00% GC)
  median time:      1.440 ns (0.00% GC)
  mean time:        1.549 ns (0.00% GC)
  maximum time:     16.191 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000

julia> b2 = @benchmarkable foo2()
Benchmark(evals=1, seconds=5.0, samples=10000)

julia> tune!(b2)
Benchmark(evals=1000, seconds=5.0, samples=10000)

julia> run(b2)
BenchmarkTools.Trial:
  memory estimate:  0 bytes
  allocs estimate:  0
  --------------
  minimum time:     1.377 ns (0.00% GC)
  median time:      1.797 ns (0.00% GC)
  mean time:        2.061 ns (0.00% GC)
  maximum time:     31.709 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000

@quinnj quinnj closed this as completed Sep 27, 2017
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

No branches or pull requests

3 participants