Batched convergence logger#
gko::batch::log::BatchConvergence<ValueType> is the per-item observability hook for batched
solvers. It captures the iteration count and final residual norm for every item in the
batch and exposes them as arrays on the solver’s executor after the solve; copy them to the
host to read individual entries. Without this logger attached,
per-item convergence information is computed during the solve but discarded; the only
observable signal is the global success of solver->apply.
What it captures#
After a batched solver completes, the logger holds two arrays of length \(N\) (one entry per batch item):
Array |
Type |
Accessor |
|---|---|---|
Iteration counts |
|
|
Final residuals |
|
|
real_type is gko::remove_complex<ValueType>, i.e. float/double for real solvers and
the real part type for complex ones.
The “final residual” is the implicit residual computed inside the solver process, the same quantity the stopping criterion compares against the tolerance. Depending on the algorithm (CG, BiCGSTAB) the implicit residual can drift from the true \(\lVert b - A x \rVert\), so for strict accuracy claims compute the true residual yourself with an extra SpMV after the solve.
Usage#
namespace b = gko::batch;
// Construct the solver and an empty logger.
auto solver = b::solver::Cg<double>::build()
.with_max_iterations(500)
.with_tolerance(1e-8)
.on(exec)
->generate(batched_matrix);
auto logger = gko::share(b::log::BatchConvergence<double>::create());
solver->add_logger(logger);
solver->apply(batched_rhs, batched_x);
// Pull per-item results back to the host.
const auto& iters = logger->get_num_iterations(); // gko::array<int>
const auto& norms = logger->get_residual_norm(); // gko::array<double>
// Both arrays live on the executor of the solver that was logged.
auto host_iters = gko::array<int>{exec->get_master(), iters};
for (gko::size_type k = 0; k < host_iters.get_size(); ++k) {
std::cout << "item " << k
<< ": iters=" << host_iters.get_const_data()[k] << "\n";
}
A logger instance is a one-shot record of a single solve: each call to solver->apply resets
the internal arrays. If you want to compare runs, copy the arrays out before the next apply.
Where the logger fires#
BatchConvergence listens for the batch_solver_completed event; that is the only event in
its default mask. create(mask) accepts an event mask; the default mask enables this event.
The event itself is emitted from inside the fused solver kernel’s host-side completion path.
The arrays are populated after every item has converged or hit max_iterations; the
batched path logs once per solve, because per-iteration logging would force a host round-trip every
iteration (and defeat the kernel-fusion design).
Storage#
create takes only the event mask; the logger is not tied to an executor. Its arrays are
allocated on the first on_batch_solver_completed call, on the executor of the solver’s
result arrays, and are refreshed on every later completed solve. When the batch size changes,
the arrays are resized to match.
See also
Batched CG and Batched BiCGSTAB: the solvers this logger observes.
Logging and observability: the broader logger framework on the single-system side.
API reference:
gko::batch::log::BatchConvergence