Skip to content

[Nonlinear] fix performance of evaluating univariate operators #2620

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 10, 2025
Merged

Conversation

odow
Copy link
Member

@odow odow commented Feb 10, 2025

With the energy modeling benchmarking that @joaquimg has been doing, we've been talking about how small things never show up in a flame graph until you look at their aggregate across multiple call sites.

One thing that shows up is getindex

image

With the only giveaway being the ht_keyindex(::Dict{Symbol,Int}, ::Symbol) method.

It's because we're calling operators.univariate_operators[node.index] in multiple places, which is a Dict lookup.

These calls don't show much because of inlining etc. Even in the code view, you're kinda like "call is expensive. Sure"

image

Before

julia> @benchmark(
           MOI.Nonlinear.ReverseAD._reverse_mode($(evaluator.backend), x),
           setup=(x=rand(num_variables(model))),
       )
BenchmarkTools.Trial: 44 samples with 1 evaluation per sample.
 Range (min  max):  112.457 ms  132.677 ms  ┊ GC (min  max): 0.00%  0.00%
 Time  (median):     113.303 ms               ┊ GC (median):    0.00%
 Time  (mean ± σ):   115.478 ms ±   4.641 ms  ┊ GC (mean ± σ):  0.00% ± 0.00%

   █▂                                                            
  ▇███▆▃▁▄▁▁▁▁▁▃▁▁▁▁▁▃▁▁▁▁▃▃▄▃▁▁▁▁▁▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▃▁▁▁▁▁▃ ▁
  112 ms           Histogram: frequency by time          133 ms <

 Memory estimate: 0 bytes, allocs estimate: 0.

After

julia> @benchmark(
           MOI.Nonlinear.ReverseAD._reverse_mode($(evaluator.backend), x),
           setup=(x=rand(num_variables(model))),
       )
BenchmarkTools.Trial: 48 samples with 1 evaluation per sample.
 Range (min  max):  102.579 ms  115.444 ms  ┊ GC (min  max): 0.00%  0.00%
 Time  (median):     104.459 ms               ┊ GC (median):    0.00%
 Time  (mean ± σ):   105.355 ms ±   2.961 ms  ┊ GC (mean ± σ):  0.00% ± 0.00%

       ███▆█ ▁                                                   
  ▄▁▁▄▄█████▇█▄▇▄▄▁▁▁▁▁▁▁▁▁▁▄▁▁▁▁▁▁▁▁▁▄▁▁▁▁▁▁▁▁▁▁▁▁▁▄▁▁▄▁▄▁▁▁▁▄ ▁
  103 ms           Histogram: frequency by time          115 ms <

 Memory estimate: 0 bytes, allocs estimate: 0.

Script

using JuMP, PowerModels, BenchmarkTools
case = "test/data/pglib_opf_case13659_pegase.m"
backend = MOI.Nonlinear.SparseReverseMode()
begin
    pm = PowerModels.instantiate_model(
        case,
        PowerModels.ACPPowerModel,
        PowerModels.build_opf,
    );
    model = pm.model
    nlp = MOI.Nonlinear.Model()
    for (F, S) in list_of_constraint_types(model)
        if F != NonlinearExpr
            continue
        end
        for ci in all_constraints(model, F, S)
            o = constraint_object(ci)
            MOI.Nonlinear.add_constraint(nlp, o.func, o.set)
        end
    end
    evaluator = MOI.Nonlinear.Evaluator(
        nlp,
        backend,
        index.(all_variables(model)),
    )
end;
MOI.initialize(evaluator, [:Grad, :Jac, :Hess])

@odow odow changed the title [Nonliear] fix performance of evaluating univariate operators [Nonlinear] fix performance of evaluating univariate operators Feb 10, 2025
Copy link
Member

@blegat blegat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to remove this back and forth index mapping

@odow odow merged commit 88c9776 into master Feb 10, 2025
16 checks passed
@odow odow deleted the od/nlp branch February 10, 2025 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants