xealits
xealits

Reputation: 4546

julia, why does memory allocation happen for a loop inside a function?

In the memory allocation report of julia --track-allocation=user the maximum of allocation is in this function:

        - function fuzzy_dot_square( v::Array{Int64, 1} )
        -     dot_prod = zero(Int64)
7063056168     for i::Int64 in 2:28
        0         dot_prod += v[i]*(v[i] + v[i-1] + v[i+1] + v[i+28])# / 4 # no "top" pixel
        -     end
        0     for i in 29:(28*27) # compiler should literate 28*27
        0         dot_prod += v[i]*(v[i] + v[i-1] + v[i+1] + v[i-28] + v[i+28])# / 5 # all pixels
        -     end
        0     for i in (28*27):(28*28 - 1)
        0         dot_prod += v[i]*(v[i] + v[i-1] + v[i+1] + v[i-28])# / 4 # no "bottom" pixel
        -     end
        -
        0     return dot_prod
        - end

-- it is a "fuzzy dot product" square of a vector, representing pixel image 28 by 28 (the known MNIST dataset of digit images).

Why does the allocation happen there? As far as I understand, the dot_prod is the only thing to be allocated. But the report points at the first for..

Also I tried reproducing it in repl with:

v = Array{Int64,1}(1:100)
dot_prod = zero(Int64)
@allocated for i in 2:28
    dot_prod += v[i]
end

-- and I get following error at @allocated for ...:

ERROR: UndefVarError: dot_prod not defined
 in macro expansion at ./REPL[3]:2 [inlined]
 in (::##1#f#1)() at ./util.jl:256

The @time macro works fine, so probably there is some bug in @allocated? I have julia 0.5.0.

Upvotes: 3

Views: 886

Answers (1)

Fengyang Wang
Fengyang Wang

Reputation: 12051

This is a limitation of --track-allocation=user. There's no type instability and there are no allocations.

julia> function fuzzy_dot_square(v)
           dot_prod = zero(eltype(v))
           for i in 2:28
               dot_prod += v[i]*(v[i] + v[i-1] + v[i+1] + v[i+28])# / 4 # no "top" pixel
           end
           for i in 29:(28*27) # compiler should literate 28*27
               dot_prod += v[i]*(v[i] + v[i-1] + v[i+1] + v[i-28] + v[i+28])# / 5 # all pixels
           end
           for i in (28*27):(28*28 - 1)
               dot_prod += v[i]*(v[i] + v[i-1] + v[i+1] + v[i-28])# / 4 # no "bottom" pixel
           end
           return dot_prod
       end
fuzzy_dot_square (generic function with 1 method)

julia> const xs = [1:28^2;];

julia> @allocated fuzzy_dot_square(xs)
0

See also this passage from the Julia documentation:

In interpreting the results, there are a few important details. Under the user setting, the first line of any function directly called from the REPL will exhibit allocation due to events that happen in the REPL code itself. More significantly, JIT-compilation also adds to allocation counts, because much of Julia’s compiler is written in Julia (and compilation usually requires memory allocation). The recommended procedure is to force compilation by executing all the commands you want to analyze, then call Profile.clear_malloc_data() to reset all allocation counters. Finally, execute the desired commands and quit Julia to trigger the generation of the .mem files.

And for further information, see this Julia issue.

Upvotes: 8

Related Questions