Variables in @belapsed benchmark

Hey there! Maybe anybody can help me? I don’t understand how variables work in @belapsed.
My code:

function test_queue_deque(n)
    @belapsed begin
        for i in 1:n
            popfirst!(dq)
        end
    end setup = begin
        dq = Deque{Int}()
        for _ in 1:n
            push!(dq, 1)
        end
    end
end
ERROR: LoadError: UndefVarError: `j` not defined in `Main`
Suggestion: check for spelling errors or missing imports.

If I try to replace j with underscore, the code still doesn’t work. I get: ERROR: LoadError: syntax: all-underscore identifiers are write-only and their values cannot be used in expressions around

I use Julia 1.12.1
Thanks

Put code between triple backticks like this so things properly format:

```
code
```

You can see those backticks because I used \ to escape them instead of specifying Markdown formatting.

As for your provided code, there’s no visible j variable anywhere so it wouldn’t throw the associated error. You likely provided the underscore edit instead but it’s not clear where the j would have been; if the underscore is replaced with j, the error would actually be about n.

There are a couple issues going on here. First, BenchmarkTools macros are designed to run their code in the global scope, so to put your argument n into the code, you have to interpolate them $n. Chairmarks.jl is an independent alternative that runs code in the macro call scope, if you prefer not to deal with global scope motion and are willing to take a chance on a newer less-known package. Second, BenchmarkTools transformed the code in some way that j or _ end up on the right hand side of a globally scoped assignment at some point, which isn’t what we want and isn’t allowed in the latter case. Refactor the setup code in a simpler function call as designed; loop variables are a genuine limitation of the setup expression that the benchmark expression doesn’t have.

julia> @btime sin(x) setup=(x=0; for i in 1:5 x+=i end) # simpler example
ERROR: UndefVarError: `i` not defined in `Main`
...
julia> foo() = (x=0; for i in 1:5 x+=i end; x); @btime sin(x) setup=(x=foo())
  18.437 ns (0 allocations: 0 bytes)
0.6502878401571168

This is two working versions.

using DataStructures
function test_queue_deque(n)
    @benchmark begin
        for i = 1:$n
            popfirst!(dq)
        end
    end setup = begin
        dq = Deque{Int}()
        push_all!(dq, $n)
    end evals = 1
end

function push_all!(dq, n)
    for _ = 1:n
        push!(dq, 1)
    end
end

test_queue_deque(3)

or

using DataStructures
function test_queue_deque(n)
    @benchmark begin
        for i = 1:$n
            popfirst!(dq)
        end
    end setup = begin
        dq = Deque{Int}()
        j = 0
        while (j += 1; j <= $n)
            push!(dq, 1)
        end
    end evals = 1
end

test_queue_deque(3)

Key points are as follows:

  1. Specify your dependencies when providing MREs.

  2. All content within the entire begin code block is “wrapped” by the macro. To use the value of variable n, you must insert n using $.

  3. @benchmark executes your begin…end block multiple times within a single sample, sharing the same dq.
    Your code completely pops the dq in each execution, leading to an empty dq in later runs of the same sample and causing errors. I added evals = 1 at the end.