Precompile all the functions within a function

Hello everyone,
I was playing around with the precompile function, and I noticed that it does not precompile all the functions that are called within the precompiled function. For example, consider:

@time a = 100 #make sure the @time macro is compiled

struct myStruct
a::Float64
b::Int64
c::Bool
end

function test_calc(input::myStruct)
    if(input.c)
        sine_val = sin(input.a * 2pi)
        sine_val2 = cos(input.b * 2pi)
        final_val = mod(sine_val, sine_val2)
        println(final_val)
        return final_val
    end
    return 0
end

function actual_calc(input::myStruct)
    final_val = test_calc(input)
    return final_val
end

#precompile the upper most function
precompile(actual_calc, (myStruct,))

input = myStruct(0.1, 1, true)

@time actual_calc(input)

The result of the @time actual_calc(input) calculation is:

0.054569 seconds (101.86 k allocations: 4.889 MiB)

As the allocation size hints, the actual_calc function was not compiled in all its inner calls with the precompile statement. I assume that the functions called test_calc function were not precompiled when precompiling actual_calc, even though I was expecting they would. Running @time actual_calc(input) again gives the expected result of no allocations for the compilation, and fast runtime, since it has been called once before. The compilation of all the inner functions happened in the previous call, and not in the precompile call:

0.000054 seconds (11 allocations: 288 bytes)

If I precompile test_calc aswell, the results remain the same, hinting me that the precompilation for the sin, mod and println functions that are called within it did not go through. Am I correct in making these assumptions? Is there a way to make sure to precompile the whole function graph for a specified set of arguments without having to call the function explicitly?

Thank you and have a great day!

2 Likes

The problem is that the precompile mechanism doesn’t know where to “store” the precompiled method instances. For example, sin belongs to Base.Math but that module doesn’t store the precompiled instance. Consequently any inference performed for the types you passed into sin basically get dropped. Documented (and steps on the road towards a fix) at https://github.com/JuliaLang/julia/pull/31466.

3 Likes

Thanks! That looks like the problem here. I will look in the PR you linked for further developments