Generated (staged) function to avoid initializing an array multiple times for Monte Carlo simulations

Usually. But this is not something you can easily guarantee or reason about because of this bug:

I didn’t check your exact case, but if @musm says there’s an inference issue and you’re thing “but that should infer?”, you’re probably hitting this.

@vmh @ChrisRackauckas @musm

At first I did not see any difference in benchmark (for n=1000) between using draw_samples! with a globally pre-allocated vector
and between a generated draw_samples using

But then I benchmarked it with n=1 and I saw some overhead(~300 ns).After some investigation it turns out that
it is mostly due to ellipsis operator.
It also turns out that the Ref trick is unnecessary, I guess because a Vector is already an indirection.
I used the Ref trick to bypass the built-in boxing operation that produced less optimal code in the past.

After this fix, the code_native for the closure and for the original method is almost identical.

however I do see in code_warntype that the return value is ANY , which would suggest type instability, but
all benchmarks I made show that the generated function is so very slightly faster than the original…

my code:


using Distributions
G = Gamma(1,1)
n=1

samples2 = Array{Float64, 1}(n)

function draw_samples!(samples,dist)
    rand!(dist, samples)
    samples
end

function fsamples_prealoc(g,n)
    samples = Array{Float64, 1}(n)
    (x) -> g(samples,x)
end

draw_samples = fsamples_prealoc(draw_samples!,n)

@code_native draw_samples(G)

@code_native draw_samples!(samples2,G)

function foo2(d,samples)
    x = draw_samples!(samples,d)
    2x
end

function foo(d)
    x = draw_samples(d)
    2x
end

@benchmark foo2(G,samples2)

@benchmark foo(G)

@code_warntype foo2(G,samples2)

@code_warntype foo(G)

@ChrisRackauckas @musm maybe you can explain whats going on here and whether it is type stable or not
and whether it has any implications on performance

Thanks
Tsur

@musm
After a too long investigation it turns out that it is not type stable
because draw_samples2 which I presume is the name you gave the generated function, is not const.

if you declare it using:

const draw_samples2 = fsamples_prealoc(draw_samples!,n)

then foo2 becomes type_stable.

1 Like