I have asked about the related idea behind my problem over here, but since no conclusion could be drawn, I’ve constructed a little test. That’s where things got weird - I am unsure why the result looks the way they do, and now feel like I am doing something wrong.
Short explanation, the full code is posted below. Basically I am looking to integrate a “reference” to the current JuMP.Model
being built into every component (the “components” are some kind of building blocks of this model). That’s why I am comparing the performance of
- keeping that as field of the
struct
- not keeping it at all
- keeping it as field of the
struct
but only asRef
The initial test showed that 2.
resulted in two allocations less than 1.
(kind of expected?), while 3.
results in three allocations more (did not expect that?).
Now, I am adding all components to the .ext
dictionary, and I thought that would not influence the 3 different ways, but something strange happens: 1.
and 2.
result in the same amount of allocations if I do not save the components into .ext
. And now I am completely lost on why this happens…
Really glad for any insights (probably about me misunderstanding how Julia handles something…)!
Allocations:
- 209609
- 207609
- 212609
Allocations without .ext
:
- 202119
- 202119
MWE:
using JuMP
using BenchmarkTools
Base.@kwdef mutable struct Component1
model::JuMP.Model
var::Union{Vector{JuMP.VariableRef}, Nothing} = nothing
bound::Float64
end
Base.@kwdef mutable struct Component2
var::Union{Vector{JuMP.VariableRef}, Nothing} = nothing
bound::Float64
end
Base.@kwdef mutable struct Component3
model::Ref{JuMP.Model}
var::Union{Vector{JuMP.VariableRef}, Nothing} = nothing
bound::Float64
end
function foo1()
m = JuMP.Model()
set_string_names_on_creation(m, false)
m.ext[:components] = [Component1(model=m, bound=rand()) for _ in 1:1000]
for comp in m.ext[:components]
comp.var = @variable(comp.model, [t=1:100], upper_bound=comp.bound)
end
end
function foo2()
m = JuMP.Model()
set_string_names_on_creation(m, false)
m.ext[:components] = [Component2(bound=rand()) for _ in 1:1000]
for comp in m.ext[:components]
comp.var = @variable(m, [t=1:100], upper_bound=comp.bound)
end
end
function foo3()
m = JuMP.Model()
set_string_names_on_creation(m, false)
m.ext[:components] = [Component3(model=Ref(m), bound=rand()) for _ in 1:1000]
for comp in m.ext[:components]
comp.var = @variable(comp.model[], [t=1:100], upper_bound=comp.bound)
end
end
function foo1_alt()
m = JuMP.Model()
set_string_names_on_creation(m, false)
comps = [Component1(model=m, bound=rand()) for _ in 1:1000]
for comp in comps
comp.var = @variable(comp.model, [t=1:100], upper_bound=comp.bound)
end
end
function foo2_alt()
m = JuMP.Model()
set_string_names_on_creation(m, false)
comps = [Component2(bound=rand()) for _ in 1:1000]
for comp in comps
comp.var = @variable(m, [t=1:100], upper_bound=comp.bound)
end
end
@benchmark foo1()
@benchmark foo2()
@benchmark foo3()
@benchmark foo1_alt()
@benchmark foo2_alt()