error.hh
Go to the documentation of this file.
1#pragma once
2
3/// @file
4/// @brief The BatchLAS exception hierarchy.
5///
6/// Every failure BatchLAS diagnoses is thrown as one of the classes below. Each derives from the
7/// `std::` exception the site threw historically (so existing handlers and the pybind11 type
8/// mapping are unchanged) and, virtually, from the empty tag batchlas::exception.
9///
10/// Three catches answer three questions: `catch (const batchlas::workspace_error&)` (a specific
11/// reason), `catch (const batchlas::exception&)` (anything BatchLAS diagnosed), and
12/// `catch (const std::exception&)` (that, plus `std::bad_alloc` and `sycl::exception`, which are
13/// deliberately not wrapped).
14/// @note Not yet covered: the kernel-selection layer throws plain `std::invalid_argument` for a
15/// bad `BATCHLAS_<OP>_ROUTE` pin and `std::runtime_error` when no kernel can run; neither
16/// matches `catch (const batchlas::exception&)`. batchlas::NoRouteError
17/// (`<batchlas/no_route.hh>`, nothing compiled in can serve the call) is a batchlas::unsupported.
18/// @see @ref design_error_model
19/// @ingroup api_errors
20// Every class here must carry BATCHLAS_API even with no out-of-line member, or catch-by-type
21// breaks under -fvisibility=hidden; a throw/catch test on x86-64 cannot detect it.
22// evidence: docs/design/symbol-visibility.md#symbol-visibility-exception-typeinfo-must-be-exported
23
24#include <stdexcept>
25#include <string>
26
27#include <batchlas/export.hh>
28
29namespace batchlas {
30
31/// @brief Empty tag base of every BatchLAS exception.
32///
33/// `catch (const batchlas::exception& e)` matches every class in this header and nothing else.
34/// Read the text with message(); the tag deliberately has no what().
35/// @ingroup api_errors
36// Tag rules, each fails SILENTLY if broken: (1) never derive from std::exception, (2) every leaf
37// inherits it virtually (only via detail::exception_bridge), (3) never declare what().
38// evidence: docs/design/error-model.md#error-model-the-three-tag-base-rules
39class BATCHLAS_API exception {
40public:
41 virtual ~exception() = default;
42
43 /// @brief The exception's message; the same string `what()` returns on the `std::` base.
44 virtual const char* message() const noexcept = 0;
45
46 // Public so no access check stands between a leaf's implicit copy ctor and this virtual base.
47 exception() = default;
48 exception(const exception&) = default;
49 exception& operator=(const exception&) = default;
50};
51
52namespace detail {
53
54/// @brief Derives from `StdBase` and, virtually, from batchlas::exception.
55///
56/// The single spelling of that inheritance, so rule 2 of the tag cannot be broken per class.
57/// @tparam StdBase the `std::` exception type the leaf extends
58/// @ingroup api_errors
59template <typename StdBase>
60class BATCHLAS_API exception_bridge : public StdBase, public virtual exception {
61public:
62 using StdBase::StdBase;
63 const char* message() const noexcept override { return StdBase::what(); }
64};
65
66} // namespace detail
67
68/// @brief The call violates the API contract.
69///
70/// Thrown for a non-square view where a square one is required, mismatched batch sizes, a span
71/// too short for the batch, a negative dimension, a null or non-USM pointer, an out-of-order
72/// Queue where an in-order one is required, or an enum value with no meaning here.
73///
74/// Not retryable: fix the call. Derives from `std::invalid_argument`, which pybind11 maps to
75/// Python's `ValueError`.
76/// @ingroup api_errors
77class BATCHLAS_API invalid_argument : public detail::exception_bridge<std::invalid_argument> {
78public:
79 explicit invalid_argument(const std::string& what_arg)
80 : detail::exception_bridge<std::invalid_argument>(what_arg) {}
81 explicit invalid_argument(const char* what_arg)
82 : detail::exception_bridge<std::invalid_argument>(what_arg) {}
83};
84
85/// @brief An index is outside its container.
86///
87/// Thrown only by `MatrixView::at(row, col, batch)` and `batch_item(i)`. Not retryable. Kept
88/// separate from invalid_argument because `std::out_of_range` is what pybind11 maps to Python's
89/// `IndexError`.
90/// @ingroup api_errors
91class BATCHLAS_API out_of_range : public detail::exception_bridge<std::out_of_range> {
92public:
93 explicit out_of_range(const std::string& what_arg)
94 : detail::exception_bridge<std::out_of_range>(what_arg) {}
95 explicit out_of_range(const char* what_arg)
96 : detail::exception_bridge<std::out_of_range>(what_arg) {}
97};
98
99/// @brief Base of the runtime arm: the call failed for a reason that is not a bad argument.
100///
101/// Catch a child to say which reason. Derives from `std::runtime_error` (Python `RuntimeError`),
102/// and every runtime class stays inside it. Nothing throws a bare `error` today.
103/// @ingroup api_errors
104class BATCHLAS_API error : public detail::exception_bridge<std::runtime_error> {
105public:
106 explicit error(const std::string& what_arg)
107 : detail::exception_bridge<std::runtime_error>(what_arg) {}
108 explicit error(const char* what_arg)
109 : detail::exception_bridge<std::runtime_error>(what_arg) {}
110};
111
112/// @brief No kernel, backend or vendor entry point in this build on this device serves the
113/// request.
114///
115/// Examples: a complex type on a real-only native path, `Uplo::Upper` where only `Lower` is
116/// implemented, a device with no sub-group size 32 under a CTA kernel, a backend that was not
117/// compiled in, an order above a kernel's register capacity.
118///
119/// Not retryable as asked, but a different kernel pin, backend, scalar type or shape may succeed:
120/// this is the class to catch to fall back to another algorithm.
121/// @ingroup api_errors
122class BATCHLAS_API unsupported : public error {
123public:
124 explicit unsupported(const std::string& what_arg) : error(what_arg) {}
125 explicit unsupported(const char* what_arg) : error(what_arg) {}
126};
127
128/// @brief The device or its vendor runtime failed.
129///
130/// A cuBLAS/cuSOLVER/cuSPARSE/rocBLAS/rocSPARSE status code, a CUDA launch failure, a handle that
131/// would not initialise, a `sycl::malloc_device`/`malloc_host` that returned null, no device of
132/// the requested type, or a host BLAS this machine ships broken.
133///
134/// Sometimes retryable, and the only class where a retry can be right: a transient launch failure
135/// or an allocation lost to another process may clear. A status code that repeats is a real
136/// fault; do not loop.
137/// @ingroup api_errors
138class BATCHLAS_API device_error : public error {
139public:
140 explicit device_error(const std::string& what_arg) : error(what_arg) {}
141 explicit device_error(const char* what_arg) : error(what_arg) {}
142};
143
144/// @brief The scratch the operation was handed is too small, or the allocator ran out of it.
145///
146/// Every routine's `*_buffer_size()` query is the contract; this is thrown when the buffer
147/// actually passed does not honour it.
148///
149/// Retry smaller: re-query `*_buffer_size()` and pass a buffer that size, or cut the batch,
150/// since a batched solve's workspace scales with the batch.
151/// @see @ref design_workspace
152/// @ingroup api_errors
153class BATCHLAS_API workspace_error : public error {
154public:
155 explicit workspace_error(const std::string& what_arg) : error(what_arg) {}
156 explicit workspace_error(const char* what_arg) : error(what_arg) {}
157};
158
159/// @brief An iterative kernel did not converge, or a factorisation broke down on the data.
160///
161/// An eigen/SVD sweep budget exhausted, a bidiagonal QR that never deflated, an ILU(k) pivot that
162/// was zero with no usable shift: the LAPACK `info > 0` case.
163///
164/// Retryable with different parameters (a looser tolerance, a higher sweep cap, a different
165/// algorithm, a rescaled input), not with the same ones.
166/// @note The exception is batch-wide: it says some item failed, not which. Pass the optional
167/// per-item `info` span (`syev`, `syevx`, `gesvd`, `steqr`, `stedc`) to learn which.
168/// @see @ref design_error_model
169/// @ingroup api_errors
170class BATCHLAS_API convergence_error : public error {
171public:
172 explicit convergence_error(const std::string& what_arg) : error(what_arg) {}
173 explicit convergence_error(const char* what_arg) : error(what_arg) {}
174};
175
176/// @brief BatchLAS is internally inconsistent.
177///
178/// A kernel was chosen that its own guard then refuses, an internal phase produced a structure
179/// the next one cannot use, an internal seam was not injected, a branch documented "unreachable"
180/// was reached. Never retryable and, with one exception, never the caller's fault: report it with
181/// the message, which names the op and the two things that disagreed.
182/// @note The exception: gesv and posv throw it for an empty or heterogeneous batch, which no
183/// kernel serves.
184/// @ingroup api_errors
185class BATCHLAS_API internal_error : public error {
186public:
187 explicit internal_error(const std::string& what_arg) : error(what_arg) {}
188 explicit internal_error(const char* what_arg) : error(what_arg) {}
189};
190
191/// @brief A well-formed call arrived in a state, order or thread where it is not valid.
192///
193/// A Queue used from a thread other than its owner, `attach_to_current_thread()` with a workspace
194/// lease outstanding, `configure()` after a Queue already exists, a BumpAllocator query asked of
195/// the wrong kind of pool (`required_bytes()` of a real pool, `remaining()` of a sizing one).
196///
197/// Not retryable as-is: reorder the calls or confine the object to one thread. Distinct from
198/// invalid_argument because no argument is wrong.
199/// @ingroup api_errors
200class BATCHLAS_API api_misuse : public error {
201public:
202 explicit api_misuse(const std::string& what_arg) : error(what_arg) {}
203 explicit api_misuse(const char* what_arg) : error(what_arg) {}
204};
205
206} // namespace batchlas
api_misuse(const std::string &what_arg)
Definition error.hh:202
api_misuse(const char *what_arg)
Definition error.hh:203
convergence_error(const char *what_arg)
Definition error.hh:173
convergence_error(const std::string &what_arg)
Definition error.hh:172
Derives from StdBase and, virtually, from batchlas::exception.
Definition error.hh:60
const char * message() const noexcept override
The exception's message; the same string what() returns on the std:: base.
Definition error.hh:63
device_error(const std::string &what_arg)
Definition error.hh:140
device_error(const char *what_arg)
Definition error.hh:141
error(const std::string &what_arg)
Definition error.hh:106
error(const char *what_arg)
Definition error.hh:108
virtual ~exception()=default
virtual const char * message() const noexcept=0
The exception's message; the same string what() returns on the std:: base.
internal_error(const std::string &what_arg)
Definition error.hh:187
internal_error(const char *what_arg)
Definition error.hh:188
invalid_argument(const std::string &what_arg)
Definition error.hh:79
invalid_argument(const char *what_arg)
Definition error.hh:81
out_of_range(const std::string &what_arg)
Definition error.hh:93
out_of_range(const char *what_arg)
Definition error.hh:95
unsupported(const std::string &what_arg)
Definition error.hh:124
unsupported(const char *what_arg)
Definition error.hh:125
workspace_error(const char *what_arg)
Definition error.hh:156
workspace_error(const std::string &what_arg)
Definition error.hh:155