Skip to content

Parallelize solve_problems - #195

Open
MaxenceGollier wants to merge 6 commits into
JuliaSmoothOptimizers:mainfrom
MaxenceGollier:parallel
Open

Parallelize solve_problems#195
MaxenceGollier wants to merge 6 commits into
JuliaSmoothOptimizers:mainfrom
MaxenceGollier:parallel

Conversation

@MaxenceGollier

@MaxenceGollier MaxenceGollier commented Feb 10, 2026

Copy link
Copy Markdown
Contributor

@dpo, @tmigot

#120

(hopefully) supersedes #127, #167, #176.
To parallelize over solvers instead of problems, CUTEst problems make it very very difficult, i have tried multiple times but failed. I think it is fine just to parallelize over problems.

To make things clear,

  • I added a private function _run_problem which just performs one iteration of the loop.
  • I first make a serial run where first_problem is set to false to avoid race conditions on this variable and other variables accessed when first_problem is true.
  • I then make the parallel run.
  • I added a lock when we modify and read from stats to prevent race conditions.

@MaxenceGollier

Copy link
Copy Markdown
Contributor Author

The race condition causes issue, for example, see MaxenceGollier/Penelopt.jl#57. I will fix the BSD tests as well.

@tmigot tmigot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@MaxenceGollier If I understand correctly you propose to do multi-threading over problems. This assumes that problems are thread-safe, which is the case for CUTEst and (in theory) OptimizationProblems.jl, however it also needs the solvers to be thread safe, which I don't think we really test.

If we are going for a multi-threaded version, I think it should be a different function than solve_problems also, because it will never be safe in general (for any set of problems, and any set of solvers).

Comment thread src/run_solver.jl
Comment on lines 89 to +90
stats = DataFrame(names .=> [T[] for T in types])
stats_lock = ReentrantLock()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would it be better to have one stats per thread and merge all of them in the end ?

@tmigot

tmigot commented Feb 11, 2026

Copy link
Copy Markdown
Member

The idea would be that your version is faster when it is possible, and #194 would be safer. So, both approaches might be complementary.

@MaxenceGollier

Copy link
Copy Markdown
Contributor Author

Hi @tmigot, i separated in two distinct functions. My issue is that there is a lot of repeated code which makes it harder to maintain...

@MaxenceGollier
MaxenceGollier marked this pull request as ready for review August 12, 2026 13:35
Copilot AI lite review requested due to automatic review settings August 12, 2026 13:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a threaded execution path for benchmarking by parallelizing solve_problems over problems, and wires it into bmark_solvers behind a new parallel keyword.

Changes:

  • Introduces solve_problems_parallel in src/run_solver.jl using Threads.@spawn and a lock to protect writes to the shared stats DataFrame.
  • Adds parallel::Bool=false to bmark_solvers to select solve_problems_parallel when multiple Julia threads are available.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/run_solver.jl Adds a new parallel solver runner and a locked per-problem execution helper.
src/bmark_solvers.jl Adds a parallel keyword to switch between serial and threaded benchmarking.
Suppressed comments (1)

src/run_solver.jl:330

  • _run_problem is called inside the spawned task, but there is no _run_problem definition in the codebase. This will throw a UndefVarError when the parallel section runs.
      _run_problem(

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/run_solver.jl Outdated
# Make a first serial run until first_problem is false
final_id = 0
for (id, problem) in enumerate(problems)
first_problem, nb_unsuccessful_since_start = _run_problem(
Comment thread src/run_solver.jl
problem,
stats::DataFrame,
solver,
solver_name::Symbol,
Comment thread src/run_solver.jl
Comment on lines +296 to +298
# Make a first serial run until first_problem is false
final_id = 0
for (id, problem) in enumerate(problems)
Comment thread src/bmark_solvers.jl
if parallel && Threads.nthreads() > 1
stats[name] = solve_problems_parallel(solver, name, args...; kwargs...)
else
parallel && @warn "SolverBenchmarks.jl: parallel is set to true but the number of threads is $(Threads.nthreads()). Running in serial mode."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants