fonsp / Pluto.jl

🎈 Simple reactive notebooks for Julia
https://plutojl.org/
MIT License
4.91k stars 284 forks source link

Strange @allocated numbers for function calls to interpolation objects #2844

Open chunjiw opened 3 months ago

chunjiw commented 3 months ago

I'm trying to reduce allocations during function calls to Interpolation objects in Interpolations.jl package. But I get this strange result: image

But then I put the same code in a file, they both return zero:

using Interpolations
let
    t = interpolate((1:10,), rand(10), Gridded(Linear()))
    println(@allocated t(5))
end
let
    t = interpolate((1:10,), rand(10), Gridded(Linear()))
    fieldnames(typeof(t))
    println(@allocated t(5))
end

Output is

0
0

I'm truly perplexed. Greatly appreciate it if someone can shed some light on this.

Pluto.jl is v0.19.40; and

julia> versioninfo()
Julia Version 1.10.2
Commit bd47eca2c8a (2024-03-01 10:14 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 12 × Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, skylake)
Threads: 1 default, 0 interactive, 1 GC (on 12 virtual cores)
fonsp commented 3 months ago

I think the first cell is being optimized more heavily than the second, and Julia is able to optimize away the actual t(5) call because it is effect-free and the result is not used.

This reminds me of https://github.com/JuliaLang/julia/issues/38880#issuecomment-745058041

In the REPL, if you make sure that the call cannot be optimized away (by storing the result), you get 16 allocs in both cases:

julia> using Interpolations

julia> let
               t = interpolate((1:10,), rand(10), Gridded(Linear()))
               println(@allocated t(5))
       end
0

julia> let
               t = interpolate((1:10,), rand(10), Gridded(Linear()))
               fieldnames(typeof(t))
               println(@allocated t(5))
       end
0

julia> result = Ref(0.0);

julia> let
               t = interpolate((1:10,), rand(10), Gridded(Linear()))
               fieldnames(typeof(t))
               println(@allocated result[] = t(5))
       end
16

julia> let
               t = interpolate((1:10,), rand(10), Gridded(Linear()))
               println(@allocated result[] = t(5))
       end
16

The difference between the REPL and Pluto is in the way Pluto runs code: it will wrap your code in a try catch, a timer function, etc, and sometimes even rewrites your toplevel code into a function body and calls the function instead (#720). So the heuristics were not able to optimize as well in Pluto as in the REPL.