-
Notifications
You must be signed in to change notification settings - Fork 580
Fix memory leak in appsi LegacySolverInterface wrapper #3915
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
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
e3ed5b0
committing test script first so that memory leak can be observed befo…
65402fa
improvements to test script, now compared using percentage growth in …
f291855
added delete_symbol_map calls to prevent memory leaks on repeat solves
b2f7f90
reduce memory leak allowance to 1% in test
2a9d434
run black formatter
8e78aba
removed unnecessary doc string
e4215b2
increased memory increase threshold for test passing & added skip if …
c82487f
add copyright text to test + duplicate proposed fix to legacy wrapper…
090fc81
Merge branch 'main' into fix-appsi-memory-leak
Marl0nL d522629
updated style for dependency optionality in test_legacy_leak.py
3e80240
removed delete_legacy_soln logic and moved symbol map attribute assig…
97443e7
Merge branch 'main' into fix-appsi-memory-leak
blnicho File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| # ____________________________________________________________________________________ | ||
| # | ||
| # Pyomo: Python Optimization Modeling Objects | ||
| # Copyright (c) 2008-2026 National Technology and Engineering Solutions of Sandia, LLC | ||
| # Under the terms of Contract DE-NA0003525 with National Technology and Engineering | ||
| # Solutions of Sandia, LLC, the U.S. Government retains certain rights in this | ||
| # software. This software is distributed under the 3-clause BSD License. | ||
| # ____________________________________________________________________________________ | ||
|
|
||
| import pyomo.environ as pyo | ||
| import pyomo.common.unittest as unittest | ||
| import gc | ||
| from pyomo.contrib.appsi.cmodel import cmodel_available | ||
|
|
||
| from pyomo.common.dependencies import attempt_import | ||
|
|
||
| # Note: tracemalloc is not always available, e.g., under PyPy | ||
| tracemalloc, tracemalloc_available = attempt_import('tracemalloc') | ||
|
|
||
|
|
||
| class TestAppsiLegacyLeak(unittest.TestCase): | ||
| @unittest.skipIf(not tracemalloc_available, "tracemalloc not available") | ||
| @unittest.skipIf(not cmodel_available, "APPSI C-extension not available") | ||
| def test_legacy_solver_wrapper_memory_leak(self): | ||
| tracemalloc.start() | ||
| # 1. Create a minimal structure | ||
| model = pyo.ConcreteModel() | ||
| model.I = pyo.RangeSet(100) | ||
| model.x = pyo.Var(model.I) | ||
| model.obj = pyo.Objective(expr=sum(model.x[i] for i in model.I)) | ||
| model.c = pyo.ConstraintList() | ||
| for i in model.I: | ||
| model.c.add(model.x[i] >= 0) | ||
|
|
||
| # 2. Instantiate Legacy Wrapper | ||
| solver = pyo.SolverFactory('appsi_cbc') | ||
| if not solver.available(): | ||
| raise unittest.SkipTest("appsi_cbc solver is not available") | ||
|
|
||
| solver.set_instance(model) | ||
|
|
||
| # Warm-up solve | ||
| solver.solve(model) | ||
| gc.collect() | ||
|
|
||
| # 3. Take initial memory snapshot | ||
|
|
||
| s1 = tracemalloc.take_snapshot() | ||
|
|
||
| # 4. Perform iterative solves | ||
| iterations = 10 | ||
| for _ in range(iterations): | ||
| solver.solve(model) | ||
|
|
||
| gc.collect() | ||
| s2 = tracemalloc.take_snapshot() | ||
| tracemalloc.stop() | ||
|
|
||
| # 5. Measure memory delta | ||
| stats = s2.compare_to(s1, 'lineno') | ||
| total_leak = sum(stat.size_diff for stat in stats) | ||
|
|
||
| initial_size = sum(stat.size for stat in s1.statistics('lineno')) | ||
| final_size = sum(stat.size for stat in s2.statistics('lineno')) | ||
| percentage_increase_per_solve = (total_leak / iterations) / initial_size * 100 | ||
|
|
||
| # We allow a small tolerance for memory use growth, set here | ||
| threshold_pct = 3 | ||
| print(f"Percentage increase per solve: {percentage_increase_per_solve}%") | ||
| # Check if the leak is substantial | ||
| self.assertLess( | ||
| percentage_increase_per_solve, | ||
| threshold_pct, | ||
| f"More than {threshold_pct}% memory leak detected across iterations", | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| unittest.main() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.