Add nospecialize to some very highly specialized methods#2830
Conversation
|
These cut 100k method instances. Still need to benchmark properly. |
src/Utilities/model.jl
Outdated
| ::Type{S}, | ||
| ) where {F<:MOI.AbstractFunction,S<:MOI.AbstractSet} | ||
| @nospecialize(model::AbstractModel), | ||
| @nospecialize(F::Type{<:MOI.AbstractFunction}), |
There was a problem hiding this comment.
Note that the inner method will be compiled. It's just this one that isn't.
There was a problem hiding this comment.
Maybe add a comment explaining this ?
src/constraints.jl
Outdated
| ::Type{<:AbstractFunction}, | ||
| ::Type{<:AbstractSet}, | ||
| @nospecialize(::ModelLike), | ||
| @nospecialize(F::Type{<:AbstractFunction}), |
There was a problem hiding this comment.
Since it's a fallback returning false, I don't believe it will affect the performance of bottleneck to looks good
There was a problem hiding this comment.
Maybe add a comment explaining this
With lots of bridgesSlower because GC runs. Beforejulia> using JuMP, Gurobi, BenchmarkTools
julia> const ENV = Gurobi.Env()
Set parameter WLSAccessID
Set parameter WLSSecret
Set parameter LicenseID to value 722777
WLS license 722777 - registered to JuMP Development
Gurobi.Env(Ptr{Nothing} @0x000000012a809400, false, 0)
julia> function main(n)
model = Model(() -> Gurobi.Optimizer(ENV))
set_silent(model)
@variable(model, x[1:n])
@constraint(model, c[i in 1:n], 0 <= i * x[i] <= i)
MOI.Utilities.attach_optimizer(model)
return model
end
main (generic function with 1 method)
julia> @benchmark(main(100_000); setup = GC.gc())
BenchmarkTools.Trial: 16 samples with 1 evaluation per sample.
Range (min … max): 174.960 ms … 216.162 ms ┊ GC (min … max): 0.00% … 18.86%
Time (median): 176.379 ms ┊ GC (median): 0.00%
Time (mean ± σ): 180.940 ms ± 12.739 ms ┊ GC (mean ± σ): 2.60% ± 6.04%
██
▄██▄▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▄▁▁▁▁▁▁▁▄ ▁
175 ms Histogram: frequency by time 216 ms <
Memory estimate: 344.67 MiB, allocs estimate: 6303323.Afterjulia> using JuMP, Gurobi, BenchmarkTools
julia> const ENV = Gurobi.Env()
Set parameter WLSAccessID
Set parameter WLSSecret
Set parameter LicenseID to value 722777
WLS license 722777 - registered to JuMP Development
Gurobi.Env(Ptr{Nothing} @0x0000000127ddd000, false, 0)
julia> function main(n)
model = Model(() -> Gurobi.Optimizer(ENV))
set_silent(model)
@variable(model, x[1:n])
@constraint(model, c[i in 1:n], 0 <= i * x[i] <= i)
MOI.Utilities.attach_optimizer(model)
return model
end
main (generic function with 1 method)
julia> @benchmark(main(100_000); setup = GC.gc())
BenchmarkTools.Trial: 14 samples with 1 evaluation per sample.
Range (min … max): 213.427 ms … 235.628 ms ┊ GC (min … max): 14.28% … 19.73%
Time (median): 229.635 ms ┊ GC (median): 19.44%
Time (mean ± σ): 228.419 ms ± 5.341 ms ┊ GC (mean ± σ): 18.89% ± 1.57%
▁ ▁ █▁ █ █ ██ ▁
█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁██▁█▁▁▁█▁██▁▁▁▁▁▁▁▁▁▁█ ▁
213 ms Histogram: frequency by time 236 ms <
Memory estimate: 349.26 MiB, allocs estimate: 6503956.Without bridgesNo change. Beforejulia> function main2(n)
model = Model(() -> Gurobi.Optimizer(ENV))
set_silent(model)
@variable(model, x[1:n])
@constraint(model, c[i in 1:n], i * x[i] >= i)
MOI.Utilities.attach_optimizer(model)
return model
end
main2 (generic function with 1 method)
julia> @benchmark(main2(100_000); setup = GC.gc())
BenchmarkTools.Trial: 20 samples with 1 evaluation per sample.
Range (min … max): 117.079 ms … 120.962 ms ┊ GC (min … max): 0.00% … 0.00%
Time (median): 119.386 ms ┊ GC (median): 0.00%
Time (mean ± σ): 119.362 ms ± 868.501 μs ┊ GC (mean ± σ): 0.00% ± 0.00%
▁ ▁ █▁ ▁▁█ ▁ █ ▁▁ ▁▁ ▁ ▁ ▁ ▁
█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█▁▁██▁▁▁▁███▁▁█▁█▁▁██▁██▁▁▁█▁█▁▁▁▁█▁▁▁▁█ ▁
117 ms Histogram: frequency by time 121 ms <
Memory estimate: 263.94 MiB, allocs estimate: 4802694.Afterjulia> function main2(n)
model = Model(() -> Gurobi.Optimizer(ENV))
set_silent(model)
@variable(model, x[1:n])
@constraint(model, c[i in 1:n], i * x[i] >= i)
MOI.Utilities.attach_optimizer(model)
return model
end
main2 (generic function with 1 method)
julia> @benchmark(main2(100_000); setup = GC.gc())
BenchmarkTools.Trial: 20 samples with 1 evaluation per sample.
Range (min … max): 117.935 ms … 124.710 ms ┊ GC (min … max): 0.00% … 0.00%
Time (median): 121.387 ms ┊ GC (median): 0.00%
Time (mean ± σ): 121.877 ms ± 1.833 ms ┊ GC (mean ± σ): 0.00% ± 0.00%
▃ ▃ █ ▃
▇▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▇▁▁▁▁▁▇█▁▁█▁▁█▁▁▇▇▁▇▁▁▁▁▁▁▁▁▇▁▁▁▁▁▇▁▇▇▁▁▁▁▁▇█ ▁
118 ms Histogram: frequency by time 125 ms <
Memory estimate: 263.94 MiB, allocs estimate: 4802694. |
|
There doesn't seem to be any difference in the test runtime of So maybe they're such tiny methods that it doesn't really matter. |
|
I guess I should try: https://timholy.github.io/SnoopCompile.jl/dev/tutorials/pgdsgui/. I remember looking at it a couple of years ago without much obvious success. |
|
Even without bridges this is much better. Beforejulia> using JuMP, Gurobi
julia> const ENV = Gurobi.Env()
Set parameter WLSAccessID
Set parameter WLSSecret
Set parameter LicenseID to value 722777
WLS license 722777 - registered to JuMP Development
Gurobi.Env(Ptr{Nothing} @0x0000000142a8ac00, false, 0)
julia> function main2(n)
model = Model(() -> Gurobi.Optimizer(ENV))
set_silent(model)
@variable(model, x[1:n])
@constraint(model, c[i in 1:n], i * x[i] >= i)
MOI.Utilities.attach_optimizer(model)
return model
end
main2 (generic function with 1 method)
julia> @time main2(100_000)
0.338462 seconds (4.99 M allocations: 273.114 MiB, 26.99% gc time, 38.53% compilation time)
A JuMP Model
├ solver: Gurobi
├ objective_sense: FEASIBILITY_SENSE
├ num_variables: 100000
├ num_constraints: 100000
│ └ AffExpr in MOI.GreaterThan{Float64}: 100000
└ Names registered in the model
└ :c, :xAfterjulia> using JuMP, Gurobi
julia> const ENV = Gurobi.Env()
Set parameter WLSAccessID
Set parameter WLSSecret
Set parameter LicenseID to value 722777
WLS license 722777 - registered to JuMP Development
Gurobi.Env(Ptr{Nothing} @0x0000000118251000, false, 0)
julia> function main2(n)
model = Model(() -> Gurobi.Optimizer(ENV))
set_silent(model)
@variable(model, x[1:n])
@constraint(model, c[i in 1:n], i * x[i] >= i)
MOI.Utilities.attach_optimizer(model)
return model
end
main2 (generic function with 1 method)
julia> @time main2(100_000)
0.228506 seconds (4.84 M allocations: 265.752 MiB, 42.85% gc time, 6.42% compilation time)
A JuMP Model
├ solver: Gurobi
├ objective_sense: FEASIBILITY_SENSE
├ num_variables: 100000
├ num_constraints: 100000
│ └ AffExpr in MOI.GreaterThan{Float64}: 100000
└ Names registered in the model
└ :c, :x |
|
Thoughts @blegat? |
|
Bump @blegat |
|
Perhaps a question for a separate PR, would it make sense to not-specialize most of the functions in MOI.Test? |
|
Looks good to me, just need to address https://github.com/jump-dev/MathOptInterface.jl/pull/2830/files#r2378993412 |
|
I reverted the |
Before(grb2) pkg> st
Status `/private/tmp/grb2/Project.toml`
[2e9cd046] Gurobi v1.7.6
[4076af6c] JuMP v1.29.1
julia> using JuMP, Gurobi
julia> const ENV = Gurobi.Env()
Set parameter WLSAccessID
Set parameter WLSSecret
Set parameter LicenseID to value 722777
WLS license 722777 - registered to JuMP Development
Gurobi.Env(Ptr{Nothing} @0x000000014db87200, false, 0)
julia> function main(n)
model = Model(() -> Gurobi.Optimizer(ENV))
set_silent(model)
@variable(model, x[1:n])
@constraint(model, c[i in 1:n], 0 <= i * x[i] <= i)
MOI.Utilities.attach_optimizer(model)
return model
end
main (generic function with 1 method)
julia> @time main(100_000)
1.099357 seconds (8.99 M allocations: 479.260 MiB, 12.73% gc time, 71.90% compilation time)
A JuMP Model
├ solver: Gurobi
├ objective_sense: FEASIBILITY_SENSE
├ num_variables: 100000
├ num_constraints: 100000
│ └ AffExpr in MOI.Interval{Float64}: 100000
└ Names registered in the model
└ :c, :xAfter(grb) pkg> st
Status `/private/tmp/grb/Project.toml`
[2e9cd046] Gurobi v1.7.6
[4076af6c] JuMP v1.29.1
[b8f27783] MathOptInterface v1.45.0 `~/git/jump-dev/MathOptInterface`
julia> using JuMP, Gurobi
julia> const ENV = Gurobi.Env()
Set parameter WLSAccessID
Set parameter WLSSecret
Set parameter LicenseID to value 722777
WLS license 722777 - registered to JuMP Development
Gurobi.Env(Ptr{Nothing} @0x000000014f1cb000, false, 0)
julia> function main(n)
model = Model(() -> Gurobi.Optimizer(ENV))
set_silent(model)
@variable(model, x[1:n])
@constraint(model, c[i in 1:n], 0 <= i * x[i] <= i)
MOI.Utilities.attach_optimizer(model)
return model
end
main (generic function with 1 method)
julia> @time main(100_000)
0.750228 seconds (7.83 M allocations: 413.546 MiB, 17.80% gc time, 57.17% compilation time)
A JuMP Model
├ solver: Gurobi
├ objective_sense: FEASIBILITY_SENSE
├ num_variables: 100000
├ num_constraints: 100000
│ └ AffExpr in MOI.Interval{Float64}: 100000
└ Names registered in the model
└ :c, :x |


x-ref #2829