Hi, while doning GARCH fitting I discovered strange performance drop:
Case 1 Returning two values instead of one is x10 times slower 1.5ms vs 23μs
. See place marked with CHANGE1
. Is that a known issue and should not be used?
Case 2 The missing
values slows down by x10 1.5ms vs 5μs
see place marked with CHANGE2
. It seems like a known issue, what’s the best workaround, using NaN
or special float values?
Case 3 The multi method is x1.5 slower than simple method. I assumed compiler would optimise it into same code, but it’s not.
The Benchmark for Case 1, 2
using Distributions, BenchmarkTools
struct SimpleVol end
@inline predict_explicit(Q, prev, r) = begin
d = r - Q.μ
y = sqrt(d*d + 1e-6)
v = Q.α*y + (1-Q.α)*prev.v
(; v), 0.0
# (; v) # CHANGE1
end
vol_llh_explicit(T, Q, rs) = begin
n = length(rs)
l = findfirst(!ismissing, rs)
state = (; v=abs(rs[l]))
for t in max(l, 2):n
rs[t] === missing && continue
state, _ = predict_explicit(Q, state, rs[l])
# state = predict_explicit(Q, state, rs[l]) # CHANGE1
end
end;
returns = rand(Normal(0, 0.015), 10_000);
isweekend(i) = (mod(i,7) == 6) || (mod(i,7) == 0);
returns2 = [isweekend(i) ? missing : returns[i] for i in 1:length(returns)];
# Warmup
vol_llh_explicit(SimpleVol, (α = 0.048, μ = 0.0004, ν = 4.203), returns2)
# Bench
println("Explicit Method")
@benchmark vol_llh_explicit(SimpleVol, (α = 0.048, μ = 0.0004, ν = 4.203), returns2)
# CHANGE2 use returns instead of returns2 in benchmark
Benchmark for Case 3
using Distributions, BenchmarkTools
struct SimpleVol end
@inline predict(::Type{SimpleVol}, Q, prev, r) = begin
d = r - Q.μ
y = sqrt(d*d + 1e-6)
v = Q.α*y + (1-Q.α)*prev.v
(; v), 0.0
# (; v) # CHANGE1
end
@inline predict_explicit(Q, prev, r) = begin
d = r - Q.μ
y = sqrt(d*d + 1e-6)
v = Q.α*y + (1-Q.α)*prev.v
(; v), 0.0
# (; v) # CHANGE1
end
vol_llh_multi(T, Q, rs) = begin
n = length(rs)
l = findfirst(!ismissing, rs)
state = (; v=abs(rs[l]))
for t in max(l, 2):n
rs[t] === missing && continue
state, _ = predict(T, Q, state, rs[t])
# state = predict(T, Q, state, rs[t]) # CHANGE1
end
end;
vol_llh_explicit(T, Q, rs) = begin
n = length(rs)
l = findfirst(!ismissing, rs)
state = (; v=abs(rs[l]))
for t in max(l, 2):n
rs[t] === missing && continue
state, _ = predict_explicit(Q, state, rs[l])
# state = predict_explicit(Q, state, rs[l]) # CHANGE1
end
end;
returns = rand(Normal(0, 0.015), 10_000);
isweekend(i) = (mod(i,7) == 6) || (mod(i,7) == 0);
returns2 = [isweekend(i) ? missing : returns[i] for i in 1:length(returns)];
# Warmup
vol_llh_explicit(SimpleVol, (α = 0.048, μ = 0.0004, ν = 4.203), returns2)
vol_llh_multi(SimpleVol, (α = 0.048, μ = 0.0004, ν = 4.203), returns2)
# Bench
println("Explicit Method")
@benchmark vol_llh_explicit(SimpleVol, (α = 0.048, μ = 0.0004, ν = 4.203), returns2)
println("Multi Method")
@benchmark vol_llh_multi(SimpleVol, (α = 0.048, μ = 0.0004, ν = 4.203), returns2)
# CHANGE2 use returns instead of returns2 in benchmark
P.S. The issue on stack overflow, but it’s a bit unrelated, it only about 3d case.