Trying to make an MWE seems to remove the problems that I have, so there must be something wrong in the way I am doing it in the actual code. I am posting the function I am using below:
function state_control_to_poly_vector!(state, control, vec)
N = length(state.K)
M = 5 + 3 * N
vec[1] = state.MAT
vec[2] = state.MU
vec[3] = state.ML
vec[4] = state.TE
vec[5] = state.TL
for n=0:N-1
vec[6+n] = state.K[n+1]
end
for n=0:2N-1
vec[6+N+n] = control[n+1]
end
for m=1:M
vec[M+m] = vec[m]^2
vec[2*M+m] = vec[m]^3
end
end
function fast_optimize_control(
nt::Int,
state,
valfuncs,
params,
scalars,
ricedata,
simparams,
)
# Constraints and initial values
valfunc = valfuncs[nt]
lower = vcat(0.01 * ones(simparams.N), 0.7 * ones(simparams.N))
upper = vcat(0.3 * ones(simparams.N), 0.9 * ones(simparams.N))
initial_x = vcat(0.1 * ones(simparams.N), 0.8 * ones(simparams.N))
# Precompute terms needed for the very fast gross_output
D = @. (1.0 + ricedata.A1 / params.NN * (state.TE / 2.5)^ricedata.B2)
αKL = @. params.TFP[nt] * state.K^scalars.GAMMA * params.L[nt]^(1.0 - scalars.GAMMA) / D
αBBK = @. params.B3[nt] * ricedata.B1 * αKL
# Objective function
function f(x, vtmp)
r = zero(eltype(x))
for n = 1:simparams.N
r +=
params.DELTA[n] *
params.L[nt][n] *
log(
(αKL[n] - αBBK[n] * x[n]^ricedata.B2[n]) * x[simparams.N+n] /
params.L[nt][n],
)
end
r *= scalars.Q
v = get_tmp(vtmp, x)
state_control_to_poly_vector!(state, x, v)
v .-= valfunc.Amean
v ./= valfunc.Astd
ddot = dot(valfunc.val, v)
ddot = ddot*valfunc.ystd + valfunc.ymean
vhat = r + ddot
return -vhat
end
inner_optimizer = Optim.LBFGS()
v = zeros(3*41)
vtmp = DiffCache(v)
result = Optim.optimize(
x -> f(x, vtmp),
lower,
upper,
initial_x,
Fminbox(inner_optimizer),
Optim.Options(store_trace = false, show_trace = false);
autodiff = :forward,
)
x = Optim.minimizer(result)
MIU = x[1:simparams.N]
ALPHA = x[(simparams.N+1):end]
return Control(MIU, ALPHA)
end
As you can see I am capturing quite a few variables in a closure f, but this is not the issue (I have tried to add all the extra parameters as function arguments as well).
Running this function with Profile.Allocs.@profile, and then using PProf. Allocs.pprof(), I get the following:
Total: 0 6549 (flat, cum) 75.52%
220 . . (αKL[n] - αBBK[n] * x[n]^ricedata.B2[n]) * x[simparams.N+n] /
221 . . params.L[nt][n],
222 . . )
223 . . end
224 . . r *= scalars.Q
225 . 553 v = get_tmp(vtmp, x)
226 . 554 state_control_to_poly_vector!(state, x, v)
227 . 566 v .-= valfunc.Amean
228 . 510 v ./= valfunc.Astd
229 . 530 ddot = dot(valfunc.val, v)
230 . 2135 ddot = ddot*valfunc.ystd + valfunc.ymean
231 . .
232 . 1122 vhat = r + ddot
233 . 579 return -vhat
234 . . end
235 . .
From what I understand the only variables having other types than Float64 here should be x, r and v, and consequently ddot and vhat.
What stands out to me here are all the allocations where scalar operations are performed, eg. like line 230. Also, it seems that r and ddot has different types, as line 232 should not incur any allocations if the type was the same. The calculations involving just r does not incur any allocations it seems.