Benchmarking

This notebook shows some @benchmark and @code_warntype output. Both outputs are shown via the with_terminal from PlutoUI.jl, see below.

We define some function double and a dictionary of numbers in order to show type inference problems via @code_warntype:

numbers = Dict(:one => 1f0, :two => 2.0)
Dict{Symbol, AbstractFloat} with 2 entries:
  :two => 2.0
  :one => 1.0
function double(mapping, key::Symbol)
    return 2 * mapping[key]
end;

Now, the code works.

double(numbers, :one)
2.0f0
double(numbers, :two)
4.0

But the @code_warntype shows some big red warnings:

using PlutoUI: with_terminal
with_terminal() do
    @code_warntype double(numbers, :one)
end
MethodInstance for Main.var\"workspace#4\".double(::Dict{Symbol, AbstractFloat}, ::Symbol)
  from double(�[90mmapping�[39m, �[90mkey�[39m::�[1mSymbol�[22m)�[90m @�[39m �[90mMain.var\"workspace#4\"�[39m �[90m~/Documents/UConn/ME5180/dynamics/tutorials/�[39m�[90m�[4mbenchmarking.jl#==#3f0e2049-8597-4dac-b499-4d7a8a35978e:1�[24m�[39m
Arguments
  #self#�[36m::Core.Const(Main.var\"workspace#4\".double)�[39m
  mapping�[36m::Dict{Symbol, AbstractFloat}�[39m
  key�[36m::Symbol�[39m
Body�[91m�[1m::Any�[22m�[39m
�[90m1 ─�[39m %1 = Main.var\"workspace#4\".:*�[36m::Core.Const(*)�[39m
�[90m│  �[39m %2 = Base.getindex(mapping, key)�[91m�[1m::AbstractFloat�[22m�[39m
�[90m│  �[39m %3 = (%1)(2, %2)�[91m�[1m::Any�[22m�[39m
�[90m└──�[39m      return %3

We can fix this by forcing all elements in the dictionary to have the same type. Specifically, to we force all elements to be of type Float64:

typednumbers = Dict{Symbol, Float64}(:one => 1f0, :two => 2.0)
Dict{Symbol, Float64} with 2 entries:
  :two => 2.0
  :one => 1.0

This gets rid of all the type warnings:

with_terminal() do
    @code_warntype double(typednumbers, :one)
end
MethodInstance for Main.var\"workspace#4\".double(::Dict{Symbol, Float64}, ::Symbol)
  from double(�[90mmapping�[39m, �[90mkey�[39m::�[1mSymbol�[22m)�[90m @�[39m �[90mMain.var\"workspace#4\"�[39m �[90m~/Documents/UConn/ME5180/dynamics/tutorials/�[39m�[90m�[4mbenchmarking.jl#==#3f0e2049-8597-4dac-b499-4d7a8a35978e:1�[24m�[39m
Arguments
  #self#�[36m::Core.Const(Main.var\"workspace#4\".double)�[39m
  mapping�[36m::Dict{Symbol, Float64}�[39m
  key�[36m::Symbol�[39m
Body�[36m::Float64�[39m
�[90m1 ─�[39m %1 = Main.var\"workspace#4\".:*�[36m::Core.Const(*)�[39m
�[90m│  �[39m %2 = Base.getindex(mapping, key)�[36m::Float64�[39m
�[90m│  �[39m %3 = (%1)(2, %2)�[36m::Float64�[39m
�[90m└──�[39m      return %3

And makes the method more quick:

using BenchmarkTools
with_benchmark_terminal() do
    @benchmark double(numbers, :one)
end
BenchmarkTools.Trial: 10000 samples with 995 evaluations.
 Range (min … max):  29.967 ns …  4.848 μs  ┊ GC (min … max): 0.00% … 98.05%
 Time  (median):     31.041 ns              ┊ GC (median):    0.00%
 Time  (mean ± σ):   35.762 ns ± 55.295 ns  ┊ GC (mean ± σ):  2.09% ±  1.67%

  █▃▆▅▂                                                       ▁
  ██████▇▇▆▆▇▇▆▆▆▆▅▅▄▆▅▃▆▁▄▅▅▅▁▄▃▄▅▅▁▄▄▃▃▃▄▅▁▅▄▄▅▁▄▁▄▁▅▁▁▃▃▅▅ █
  30 ns        Histogram: log(frequency) by time       146 ns <

 Memory estimate: 16 bytes, allocs estimate: 1.
with_benchmark_terminal() do
    @benchmark double(typednumbers, :one)
end
BenchmarkTools.Trial: 10000 samples with 996 evaluations.
 Range (min … max):  15.962 ns …  5.502 μs  ┊ GC (min … max): 0.00% … 98.75%
 Time  (median):     18.079 ns              ┊ GC (median):    0.00%
 Time  (mean ± σ):   19.896 ns ± 56.117 ns  ┊ GC (mean ± σ):  3.27% ±  1.38%

         ▁ █                                                   
  ▁▂▂▂▂▃▃███▇▄▂▂▂▁▂▂▂▂▂▃▄▄▄▃▃▂▂▂▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▂
  16 ns           Histogram: frequency by time        28.4 ns <

 Memory estimate: 16 bytes, allocs estimate: 1.

Appendix

function with_benchmark_terminal(f)
    out = sprint(show, "text/plain", f())
    with_terminal() do
        print(out)
    end
end;

Built with Julia 1.12.4 and

BenchmarkTools 1.3.2
PlutoUI 0.7.51