The benchmark code presented in JuMP-dev 2019(https://www.youtube.com/watch?v=MLunP5cdRBI):
https://gist.github.com/Thuener/5fd30bda29a84afb126cb5b723574eba
Memory consumption 1111 Mb and Time 20.904308405
Time to solve model 5.079105861
Memory consumption 1118 Mb and Time 20.27646884
Time to solve model 5.080772802
Memory consumption 997 Mb and Time 12.158498048
Time to solve model 5.005659555
Memory consumption 992 Mb and Time 12.178707011
Time to solve model 5.056525515
Memory consumption 854 Mb and Time 13.162695245
Time to solve model 5.002032299
Memory consumption 1065 Mb and Time 12.788777522
Time to solve model 4.613660219
Memory consumption 304 Mb and Time 2.538083196
Time to solve model 4.572178837
Memory consumption 367 Mb and Time 2.641781411
Time to solve model 4.766848752
Memory consumption 587 Mb and Time 12.18446959
Time to solve model 5.053543398
Memory consumption 482 Mb and Time 12.490777377
Time to solve model 5.095189864
Memory consumption 405 Mb and Time 5.850087326
Time to solve model 4.78109017
Memory consumption 456 Mb and Time 5.842091906
Time to solve model 5.22244529
Memory consumption 440 Mb and Time 6.361990639
Time to solve model 5.057280697
Memory consumption 440 Mb and Time 6.51641373
Time to solve model 4.437310264
One of the problems is the ordered dictionary. There is an issue open in Julia requesting a function to update values in-place https://github.com/JuliaLang/julia/issues/31199
@joaquimg
Another bottleneck is canonicalize on MOI.
We might want to implement a special canonicalize in LQOI as suggested by @mlubin in JuMPdev 2019.
We use ProfileView to understand the bottlenecks in the Direct Mode. I couldn't share the data but I did some nice graphs in paint :wink:
I just include the code in the gist and did:
using Profile
Profile.clear()
@profile test_const(3; direct = true)
using ProfileView
ProfileView.view()

@Thuener Could you re-run your benchmark making sure that the following PR is applied to the version MOI you are using. https://github.com/JuliaOpt/MathOptInterface.jl/pull/696, which ensures that when copying the caching optimizer to the solver it uses add_constraints rather than the singular version. Best to use the caching optimizer, because I know that with Clp I have seen 30x improvements in copy time.
A few notes julia v1.2 will have the method map!(f,values(dict)) which was added in JuliaLang/julia#31223. I have opened a PR to add that functionality to OrderedDict and LittleDict JuliaCollections/OrderedCollections.jl#22. So we could make use of it and it should improve the perf.
That being said the code says that for Dicts smaller that 30 elements LittleDIct should out perform OrderedDict.
I know we want to avoid dependencies, but we should keep these fast dictionaries in mind:
https://github.com/andyferris/Dictionaries.jl
I have opened a PR to add that functionality to OrderedDict and LittleDict JuliaCollections/OrderedCollections.jl#22. So we could make use of it and it should improve the perf.
https://github.com/JuliaCollections/OrderedCollections.jl/pull/22 was replaced by https://github.com/JuliaCollections/OrderedCollections.jl/pull/41
and merged
Most helpful comment
A few notes julia v1.2 will have the method
map!(f,values(dict))which was added in JuliaLang/julia#31223. I have opened a PR to add that functionality to OrderedDict and LittleDict JuliaCollections/OrderedCollections.jl#22. So we could make use of it and it should improve the perf.That being said the code says that for Dicts smaller that 30 elements LittleDIct should out perform OrderedDict.