Hello, I recently discovered a very strange behavior which I cannot understand and I would like to ask you for help on this.
I have simplified the original code as much as possible to reproduce this behavior. Consider the following script:
using Statistics
using BenchmarkTools
f(X, av = (X,D) -> mean(X)) = av((a for a ∈ X.A), X)
g(X, av = (X,D) -> mean(X)) = av((a * b for (a, b) ∈ zip(X.A, X.B)), X)
N = 100_000
X = (A = rand(N), B = rand(N))
@inline function reweight(A, W, ω)
N = 0.0
D = 0.0
for (a,w) ∈ zip(A,W)
P = exp(ω * w)
N += a * P
D += P
end
return N / D
end
println("f")
@btime f($X) ## try to comment out this line, restart julia and run twice
@btime f($X, (X,D) -> reweight(X, D.B, 0.1))
@btime f($X, (X,D) -> reweight(X, D.B, 0.1))
println("g")
@btime g($X) ## try to comment out this line, restart julia and run twice
@btime g($X, (X,D) -> reweight(X, D.B, 0.1))
@btime g($X, (X,D) -> reweight(X, D.B, 0.1))
Running it in a freshly opened julia session give following results on my computer:
f
148.624 μs (1 allocation: 16 bytes)
4.417 ms (1 allocation: 16 bytes)
4.406 ms (1 allocation: 16 bytes)
g
322.668 μs (3 allocations: 64 bytes)
4.844 ms (3 allocations: 64 bytes)
4.839 ms (3 allocations: 64 bytes)
Basic things to note: both, f
and g
with reweight
run fast and allocate nearly no memory. Also, both runs for each of the functions are quite the same.
Now, comment out the marked lines in the code, restart julia and run the script again. The results from the first run are:
f
4.409 ms (1 allocation: 16 bytes)
4.405 ms (1 allocation: 16 bytes)
g
274.319 ms (1299496 allocations: 30.51 MiB)
270.832 ms (1299496 allocations: 30.51 MiB)
but from the second run I get:
f
4.407 ms (1 allocation: 16 bytes)
4.402 ms (1 allocation: 16 bytes)
g
4.839 ms (3 allocations: 64 bytes)
4.843 ms (3 allocations: 64 bytes)
Things to note: the first two runs for g
with reweight
are slow and consume a lot on memory. But both calls from the second run are fast again. However, for f
every run is fast.
So the question is: how the call g(X)
affects the speed of the call with the reweight
function and why does the same not happen when calling the function twice but only when rerun the code a second time?
As you see, the difference in f
and g
is the usage of zip
. Does this explain the behavior somehow?
You can also use @time
, the picture is the same, so it is not due to BenchmarkTools
.
Thanks.