Performance of value type construction

I noticed the following performance discrepancy between making a value type and making the instance of a value type using a runtime value:

julia> using BenchmarkTools

julia> x = "x"
"x"

julia> f(x::String) = Val{Symbol(x)}
f (generic function with 1 method)

julia> @btime f($x)
  138.326 ns (0 allocations: 0 bytes)
Val{:x}

julia> g(x::String) = Val{Symbol(x)}()
g (generic function with 1 method)

julia> @btime g($x)
  4.037 μs (0 allocations: 0 bytes)
Val{:x}()

This is with Julia v1.4.2:

julia> versioninfo()
Julia Version 1.4.2
Commit 44fa15b150* (2020-05-23 18:35 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Xeon(R) E-2176M  CPU @ 2.70GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-8.0.1 (ORCJIT, skylake)

but I see a similar discrepancy with Julia v1.5.

Is there a fundamental reason for this discrepancy? We are using a custom value type to do “runtime dispatch” (take a runtime value like a string, turn it into a value type, and then dispatch on that type). Originally we wanted to dispatch on the instances of the type. However, the 4 microsecond constructor overhead creates a bottleneck in the function (once the type is created, the dispatch and function that are being overloaded are very fast, and we are dispatching on multiple value types so the overhead adds up). We can dispatch on the type instead of the instance, but we were wondering if the constructor can (in principle) be made fast.

Sorry if this topic came up before, I tried searching for it but didn’t find anything addressing this particular question.

1 Like

Please refer to this Github issue for more information on this performance problem.