Interpolation in macro calls

Yes, that is more or less what happens. Below is an expansion of @btime cos($(x+1)), with comments explaining the parameters of generate_benchmark:

julia> using BenchmarkTools
julia> using MacroTools
julia> (@macroexpand @btime cos($(x+1))) |> rmlines |> MacroTools.alias_gensyms
quote
    local manatee = begin
      (BenchmarkTools).generate_benchmark_definition(
         Main, # eval_module
         Symbol[], # out_vars
         Symbol[Symbol("cheetah")], # setup_vars
         $(Expr(:copyast, :($(QuoteNode(:(cos(cheetah))))))), (Core._expr)(:block, $(Expr(:copyast, :($(QuoteNode(nothing))))), # code
         (Core._expr)(:(=), Symbol("cheetah"), x + 1)), # setup
         $(Expr(:copyast, :($(QuoteNode(nothing))))), # teardown
         (BenchmarkTools.Parameters)() # params
      )                                                                                                                                                                        
    end
    (BenchmarkTools).warmup(manatee)
    (BenchmarkTools).tune!(manatee)
    local (sanddollar, bison) = (BenchmarkTools).run_result(manatee)
    local crow = (BenchmarkTools).minimum(sanddollar)
    local donkey = (BenchmarkTools).allocs(crow)
    println("  ", (BenchmarkTools).prettytime((BenchmarkTools).time(crow)), " (", donkey, " allocation", if donkey == 1
            ""
        else
            "s"
        end, ": ", (BenchmarkTools).prettymemory((BenchmarkTools).memory(crow)), ")")
    bison
end

In particular, you see that the “code” has been transformed into basically cos(cheetah), with a “setup” which says: cheetah = x+1.


You’ll probably be able to find the part of the BenchmarkTools which does this if you search for it. In the GFlops.jl package, I try to implement the same kind of feature (separation between code and preliminary setup) here, in order to use it there.

Hopefully you’ll find this example useful.

2 Likes