DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
Errors.hpp
Go to the documentation of this file.
1#pragma once
2/// @file Errors.hpp
3/// @brief Assertion / error-handling macros and supporting helper functions.
4///
5/// ## Overview
6/// Three distinct families of checks are provided; choose based on how the
7/// failure should surface:
8///
9/// | Macro | Release behaviour | Failure mode |
10/// |------------------------|-------------------------|---------------------------|
11/// | @ref DNDS_assert | Compiled out (NDEBUG) | `std::abort()` |
12/// | @ref DNDS_assert_info | Compiled out (NDEBUG) | `std::abort()` + message |
13/// | @ref DNDS_assert_infof | Compiled out (NDEBUG) | `std::abort()` + fmtprintf|
14/// | @ref DNDS_check_throw | Always active | `throw std::runtime_error`|
15/// | @ref DNDS_check_throw_info | Always active | `throw` + message |
16/// | @ref DNDS_HD_assert | Compiled out in NDEBUG | host: `abort`, device: `trap` |
17///
18/// Prefer @ref DNDS_assert for internal invariants that are expensive to check or
19/// cannot fail in correct code; use @ref DNDS_check_throw for user-input / runtime
20/// validation that must remain active in release builds.
21///
22/// The device variants (`DNDS_HD_*`) expand to host asserts on the host and to
23/// atomic-guarded PTX `trap` on CUDA devices so only one thread prints.
24
25#include "Macros.hpp"
26
27// assert macros
28
29#include <iostream>
30#include <cstdarg>
31#include <sstream>
32namespace DNDS
33{
34 /// @brief Return a symbolicated stack trace for the calling thread.
35 /// @details Host-only, implemented with `boost::stacktrace` (or similar).
36 /// Used by the `assert_false*` helpers below.
37 std::string getTraceString();
38
39 /// @brief Low-level: print a red "DNDS_assertion failed" line and abort.
40 inline void assert_false(const char *expr, const char *file, int line)
41 {
42 std::cerr << getTraceString() << "\n";
43 std::cerr << "\033[91m DNDS_assertion failed\033[39m: \"" << expr << "\" at [ " << file << ":" << line << " ]" << std::endl;
44 std::abort();
45 }
46
47 /// @brief Variant of #assert_false that prints an extra `info` string.
48 inline void assert_false_info(const char *expr, const char *file, int line, const std::string &info)
49 {
50 std::cerr << getTraceString() << "\n";
51 std::cerr << "\033[91m DNDS_assertion failed\033[39m: \"" << expr << "\" at [ " << file << ":" << line << " ]\n"
52 << info << std::endl;
53 std::abort();
54 }
55
56 /// @brief `printf`-style variant of #assert_false. Used by @ref DNDS_assert_infof.
57 inline void assert_false_infof(const char *expr, const char *file, int line,
58 const char *info, ...)
59 {
60 va_list args;
61 va_start(args, info);
62 std::cerr << getTraceString() << "\n";
63 std::cerr << "\033[91m DNDS_assertion failed\033[39m: \"" << expr << "\" at [ " << file << ":" << line << " ]\n";
64 char format_buf[1024 * 512];
65 std::vsnprintf(format_buf, sizeof(format_buf), info, args);
66 va_end(args);
67 std::cerr << format_buf << std::endl;
68 std::abort();
69 }
70
71 /// @brief Throwing variant of #assert_false_info. Used by @ref DNDS_check_throw.
72 /// @tparam TException Exception type to throw (defaults to `std::runtime_error`).
73 /// Currently the implementation ignores the template parameter and always
74 /// throws `std::runtime_error`; kept for future customisation.
75 template <class TException = std::runtime_error>
76 void assert_false_info_throw(const char *expr, const char *file, int line, const std::string &info)
77 {
78 std::stringstream ss;
79 ss << getTraceString() << "\n";
80 ss << "\033[91m DNDS_assertion failed\033[39m: \"" << expr << "\" at [ " << file << ":" << line << " ]\n"
81 << info << std::endl;
82 throw std::runtime_error(ss.str());
83 }
84}
85
86/// @brief Runtime check active in both debug and release builds.
87/// Throws `std::runtime_error` if `expr` evaluates to `false`.
88/// Prefer this over @ref DNDS_assert for user-input and API-contract checks.
89#define DNDS_check_throw(expr) \
90 ((static_cast<bool>(expr)) \
91 ? void(0) \
92 : ::DNDS::assert_false_info_throw(#expr, __FILE__, __LINE__, ""))
93
94/// @brief Same as @ref DNDS_check_throw but attaches a user-supplied `info` message
95/// to the thrown `std::runtime_error`.
96#define DNDS_check_throw_info(expr, info) \
97 ((static_cast<bool>(expr)) \
98 ? void(0) \
99 : ::DNDS::assert_false_info_throw(#expr, __FILE__, __LINE__, info))
100
101#ifdef DNDS_NDEBUG
102# define DNDS_assert(expr) (void(0))
103# define DNDS_assert_info(expr, info) (void(0))
104# define DNDS_assert_infof(expr, info, ...) (void(0))
105#else
106/// @brief Debug-only assertion (compiled out when @ref DNDS_NDEBUG is defined).
107/// Prints the expression + file/line + backtrace, then calls `std::abort()`.
108# define DNDS_assert(expr) \
109 ((static_cast<bool>(expr)) \
110 ? void(0) \
111 : ::DNDS::assert_false(#expr, __FILE__, __LINE__))
112/// @brief Debug-only assertion with an extra std::string `info` message.
113# define DNDS_assert_info(expr, info) \
114 ((static_cast<bool>(expr)) \
115 ? void(0) \
116 : ::DNDS::assert_false_info(#expr, __FILE__, __LINE__, info))
117/// @brief Debug-only assertion with a printf-style format message.
118# define DNDS_assert_infof(expr, info, ...) \
119 ((static_cast<bool>(expr)) \
120 ? void(0) \
121 : ::DNDS::assert_false_infof(#expr, __FILE__, __LINE__, info, ##__VA_ARGS__))
122#endif
123
124#ifdef __CUDA_ARCH__
125
126/// @brief Device-side assertion failure: print once (atomic-guarded) and trap.
127/// @details Uses `atomicCAS` on a managed flag so only the first failing thread
128/// prints; all other threads simply call `asm("trap;")`. Avoids flooding the
129/// console when a kernel has one bug hit by thousands of threads.
130__device__ inline void device_assert_fail(const char *expr, const char *file, int line)
131{
132 __device__ __managed__ static int g_assert_printed = 0;
133 if (atomicCAS(&g_assert_printed, 0, 1) == 0)
134 {
135 printf("Device assert failed: %s at %s:%d (block %d thread %d)\n",
136 expr, file, line, blockIdx.x, threadIdx.x);
137 asm("trap;"); // force termination
138 }
139}
140
141/// @brief Printf-formatted variant of #device_assert_fail.
142__device__ inline void device_assert_fail_infof(const char *expr, const char *file, int line,
143 char *info, ...)
144{
145 __device__ __managed__ static int g_assert_printed = 0;
146 if (atomicCAS(&g_assert_printed, 0, 1) == 0)
147 {
148 va_list args;
149 va_start(args, info);
150 printf("Device assert failed: %s at %s:%d (block %d thread %d)\n",
151 expr, file, line, blockIdx.x, threadIdx.x);
152 vprintf(info, args);
153 va_end(args);
154 asm("trap;"); // force termination
155 }
156}
157
158# if defined(DNDS_NDEBUG) || defined(DNDS_NDEBUG_DEVICE)
159# define DNDS_HD_assert(cond) (void(0))
160# define DNDS_HD_assert_infof(cond, info, ...) (void(0))
161# else
162/// @brief Host/device assertion: abort on host, PTX `trap` on CUDA device.
163/// @details Can be used inside `__host__ __device__` functions. Disabled when
164/// either @ref DNDS_NDEBUG (host+device) or @ref DNDS_NDEBUG_DEVICE (device-only) is set.
165# define DNDS_HD_assert(cond) \
166 do \
167 { \
168 if (!(cond)) \
169 { \
170 device_assert_fail(#cond, __FILE__, __LINE__); \
171 } \
172 } while (0)
173
174/// @brief Host/device assertion with a printf-format message.
175# define DNDS_HD_assert_infof(cond, info, ...) \
176 do \
177 { \
178 if (!(cond)) \
179 { \
180 device_assert_fail(#cond, __FILE__, __LINE__); \
181 } \
182 } while (0)
183
184# endif
185#else
186
187// HOST version
188/// @brief Host-only expansion of @ref DNDS_HD_assert (equivalent to @ref DNDS_assert).
189# define DNDS_HD_assert(cond) DNDS_assert(cond)
190/// @brief Host-only expansion of @ref DNDS_HD_assert_infof.
191# define DNDS_HD_assert_infof(cond, info, ...) DNDS_assert_infof(cond, info, ##__VA_ARGS__)
192#endif
193
194#ifdef __CUDA_ARCH__
195# ifdef DNDS_DEVICE_BAN_EIGEN_MALLOC_DYNAMIC
196# define EIGEN_RUNTIME_NO_MALLOC
197# else
198# define EIGEN_NO_MALLOC
199# endif
200# define eigen_assert(expr) DNDS_HD_assert(expr) //! we overwrite the eigen's assert
201# if defined(EIGEN_RUNTIME_NO_MALLOC) && !defined(EIGEN_NO_MALLOC)
202# define DNDS_DEVICE_CODE_GUARD_EIGEN_MALLOC (Eigen::internal::set_is_malloc_allowed(false))
203# endif
204
205#else
206
207# define DNDS_DEVICE_CODE_GUARD_EIGEN_MALLOC (void(0))
208
209#endif
210
211namespace DNDS
212{
213}
Project-wide preprocessor flags, branch-hint macros, and version/build metadata strings....
the host side operators are provided as implemented
void assert_false(const char *expr, const char *file, int line)
Low-level: print a red "DNDS_assertion failed" line and abort.
Definition Errors.hpp:40
void assert_false_infof(const char *expr, const char *file, int line, const char *info,...)
printf-style variant of assert_false. Used by DNDS_assert_infof.
Definition Errors.hpp:57
void assert_false_info_throw(const char *expr, const char *file, int line, const std::string &info)
Throwing variant of assert_false_info. Used by DNDS_check_throw.
Definition Errors.hpp:76
void assert_false_info(const char *expr, const char *file, int line, const std::string &info)
Variant of assert_false that prints an extra info string.
Definition Errors.hpp:48
std::string getTraceString()
Return a symbolicated stack trace for the calling thread.
Definition Defines.cpp:162