Skip to content
cpbenchy 0.1.0.dev0 is in alpha: until version 1.0, commands, options, the Python API and the result format may still change. Pin the version you use.

--terminate

Stops runs at their time limit the way competitions do, so they still give their best answer.

Updated View as Markdown
OptionBuilt incomes with cpbenchy
cpbenchy run instances/ -s ortools -t 60 --terminate --grace 1
Version
cpbenchy 0.1.0.dev0
Last updated
6 Oct 2026 · 1 commit
Authors
ThomSerg
Tags
limitssignalscompetition

What it does

By default, a solver is told how much time it has, and it is killed if it is still running a grace period after that; a killed run has no answer. Competitions stop solvers differently: at the time limit, the solver gets SIGTERM and must print the best solution it found, and a second later it gets SIGKILL. --terminate makes runs behave like that.

At its time limit (wall or CPU), or on SIGTERM, a run reports the last solution its solver found: competition output gets its s and v lines, CheckSolutions checks it, and the run ends as feasible with that objective, or as timeout without one.

Use it

Rules switch it on with terminate = true, and cpbenchy solve always has it.

What it records

What the run had status termination
a solution of an optimization problem feasible, with its objective walltime, cputime or signal
no solution timeout same

Notes

  • The solutions are those the solver reports through its solution callback; satisfaction problems and solvers without one have nothing to report until they finish.
  • Keeping each solution costs a little time per solution, as it does for competition solvers.
  • A watcher thread stops the run, so a solver that holds Python’s GIL while it searches can’t be stopped this way; native solvers release it. Others are killed after the grace period.

Measurement and limits has the details.

Implementation

The stop in src/cpbenchy/worker/terminate.py, lines 58–84 of 84, as of this version of the docs.

src/cpbenchy/worker/terminate.pypython
def stop(ctx: WorkerContext, reason: str) -> bool:
    """Report what the run has and exit. Returns (True: stop watching) only if the run is already finishing
    by itself."""
    ctx.lock.acquire()  # never released: the process ends here, and a solution callback must not change `best`
    if ctx.finishing:
        ctx.lock.release()
        return True  # the run reports by itself; the executor's kill is the backstop
    try:
        ctx.terminated = reason
        ctx.log(f"stopped at the {reason} limit" if reason != "signal" else "stopped by SIGTERM")
        if ctx.solve_started is not None:
            ctx.times["solve_s"] = time.perf_counter() - ctx.solve_started
        if ctx.restore_best():
            ctx.status, ctx.objective = "feasible", ctx.best[0] if ctx.best else None
        else:
            ctx.status = "unknown"
        ctx.finishing = True
        try:
            ctx.hook.cpbenchy_worker_finish(ctx=ctx)
        except Exception as e:
            ctx.status, ctx.error = "error", f"in finish: {type(e).__name__}: {e}"
            traceback.print_exc()
        ctx.emit("result", **ctx.report())
    finally:
        sys.stdout.flush()
        sys.stderr.flush()
        os._exit(1 if ctx.status == "error" else 0)
Navigation

Type to search…

↑↓ navigate↵ selectEsc close