Celeritas 0.6.0-rc.2.13+develop.285b9112
Loading...
Searching...
No Matches
Classes | Macros | Enumerations | Functions
Assert.hh File Reference

Macros, exceptions, and helpers for assertions and error handling. More...

#include <stdexcept>
#include <string>
#include <ostream>
#include <sstream>
#include "corecel/Config.hh"
#include "Macros.hh"

Classes

struct  celeritas::DebugErrorDetails
 Detailed properties of a debug assertion failure. More...
 
struct  celeritas::RuntimeErrorDetails
 Detailed properties of a runtime error. More...
 
class  celeritas::DebugError
 Error thrown by Celeritas assertions. More...
 
class  celeritas::RuntimeError
 Error thrown by working code from unexpected runtime conditions. More...
 
class  celeritas::RichContextException
 Base class for writing arbitrary exception context to JSON. More...
 

Macros

#define CELER_DEBUG_FAIL(MSG, WHICH)
 Throw a debug assertion regardless of the CELERITAS_DEBUG setting.
 
#define CELER_RUNTIME_THROW(WHICH, WHAT, COND)
 
#define CELER_EXPECT(COND)   CELER_NOASSERT_(COND)
 Precondition debug assertion macro.
 
#define CELER_ASSERT(COND)   CELER_NOASSERT_(COND)
 Internal debug assertion macro.
 
#define CELER_ENSURE(COND)   CELER_NOASSERT_(COND)
 Postcondition debug assertion macro.
 
#define CELER_ASSUME(COND)   CELER_NDEBUG_ASSUME_(COND)
 Always-on compiler assumption.
 
#define CELER_ASSERT_UNREACHABLE()   ::celeritas::unreachable()
 Throw an assertion if the code point is reached.
 
#define CELER_VALIDATE(COND, MSG)
 Always-on runtime assertion macro.
 
#define CELER_NOT_CONFIGURED(WHAT)
 Assert if the code point is reached because an optional feature is disabled.
 
#define CELER_NOT_IMPLEMENTED(WHAT)    CELER_RUNTIME_THROW(::celeritas::RuntimeError::not_impl_err_str, WHAT, {})
 Assert if the code point is reached because a feature has yet to be fully implemented.
 
#define CELER_DEVICE_API_CALL(STMT)
 Safely and portably dispatch a CUDA/HIP API call.
 
#define CELER_DEVICE_PREFIX(STMT)   CELER_DEVICE_API_SYMBOL(STMT)
 
#define CELER_DEVICE_CALL_PREFIX(STMT)   CELER_DEVICE_API_CALL(STMT)
 
#define CELER_DEVICE_CHECK_ERROR()   CELER_DEVICE_API_CALL(PeekAtLastError())
 
#define CELER_MPI_CALL(STATEMENT)
 When MPI support is enabled, execute the wrapped statement and throw a RuntimeError if it fails.
 

Enumerations

enum class  celeritas::DebugErrorType {
  precondition , internal , unreachable , postcondition ,
  assumption
}
 

Functions

void celeritas::unreachable ()
 Invoke undefined behavior.
 
char constceleritas::to_cstring (DebugErrorType which)
 Get a human-readable string describing a debug error.
 
std::string celeritas::mpi_error_to_string (int errorcode)
 Get an MPI error string.
 

Detailed Description

Macros, exceptions, and helpers for assertions and error handling.

This defines host- and device-compatible assertion macros that are toggled on the CELERITAS_DEBUG and CELERITAS_DEVICE_DEBUG configure macros.

Macro Definition Documentation

◆ CELER_ASSERT

#define CELER_ASSERT (   COND)    CELER_NOASSERT_(COND)

Internal debug assertion macro.

This replaces standard assert usage.

◆ CELER_ASSERT_UNREACHABLE

#define CELER_ASSERT_UNREACHABLE ( )    ::celeritas::unreachable()

Throw an assertion if the code point is reached.

When debug assertions are turned off, this changes to a compiler hint that improves optimization (and may force the code to exit uncermoniously if the point is encountered, rather than continuing on with undefined behavior).

◆ CELER_ASSUME

#define CELER_ASSUME (   COND)    CELER_NDEBUG_ASSUME_(COND)

Always-on compiler assumption.

This should be used very rarely: you should make sure the resulting assembly is simplified in optimize mode from using the assumption. For example, sometimes informing the compiler of an assumption can reduce code bloat by skipping standard library exception handling code (e.g. in std::visit by assuming

!var_obj.valueless_by_exception()

).

◆ CELER_DEBUG_FAIL

#define CELER_DEBUG_FAIL (   MSG,
  WHICH 
)
Value:
do \
{ \
CELER_DEBUG_THROW_(MSG, WHICH); \
::celeritas::unreachable(); \
} while (0)

Throw a debug assertion regardless of the CELERITAS_DEBUG setting.

This is used internally but is also useful for catching subtle programming errors in downstream code.

◆ CELER_DEVICE_API_CALL

#define CELER_DEVICE_API_CALL (   STMT)
Value:
do \
{ \
CELER_NOT_CONFIGURED("CUDA or HIP"); \
CELER_DISCARD(CorecelDeviceRuntimeApiHh) \
} while (0)
int const CorecelDeviceRuntimeApiHh
Declare a dummy variable for disabled CELER_DEVICE_API_CALL calls.

Safely and portably dispatch a CUDA/HIP API call.

When CUDA or HIP support is enabled, execute the wrapped statement prepend the argument with "cuda" or "hip" and throw a RuntimeError if it fails. If no device platform is enabled, throw an unconfigured assertion.

Example:

CELER_DEVICE_API_CALL(Malloc(&ptr_gpu, 100 * sizeof(float)));
CELER_DEVICE_API_CALL(DeviceSynchronize());
#define CELER_DEVICE_API_CALL(STMT)
Safely and portably dispatch a CUDA/HIP API call.
Definition Assert.hh:286
Note
A file that uses this macro must include corecel/DeviceRuntimeApi.hh . The CorecelDeviceRuntimeApiHh declaration enforces this when CUDA/HIP are disabled, and the absence of CELER_DEVICE_API_SYMBOL enforces when enabled.

◆ CELER_ENSURE

#define CELER_ENSURE (   COND)    CELER_NOASSERT_(COND)

Postcondition debug assertion macro.

Use to "ensure" that return values or side effects are as expected when leaving a function.

◆ CELER_EXPECT

#define CELER_EXPECT (   COND)    CELER_NOASSERT_(COND)

Precondition debug assertion macro.

We "expect" that the input values or initial state satisfy a precondition, and we throw exception in debug mode if they do not.

◆ CELER_MPI_CALL

#define CELER_MPI_CALL (   STATEMENT)
Value:
do \
{ \
CELER_NOT_CONFIGURED("MPI"); \
} while (0)

When MPI support is enabled, execute the wrapped statement and throw a RuntimeError if it fails.

If MPI is disabled, throw an unconfigured assertion.

Note
A file that uses this macro must include mpi.h.

◆ CELER_NOT_CONFIGURED

#define CELER_NOT_CONFIGURED (   WHAT)
Value:
CELER_RUNTIME_THROW( \
static char const not_config_err_str[]
Definition Assert.hh:427

Assert if the code point is reached because an optional feature is disabled.

This generally should be used for the constructors of dummy class definitions in, e.g., Foo.nocuda.cc:

Foo::Foo()
{
}
#define CELER_NOT_CONFIGURED(WHAT)
Assert if the code point is reached because an optional feature is disabled.
Definition Assert.hh:242

◆ CELER_NOT_IMPLEMENTED

#define CELER_NOT_IMPLEMENTED (   WHAT)     CELER_RUNTIME_THROW(::celeritas::RuntimeError::not_impl_err_str, WHAT, {})

Assert if the code point is reached because a feature has yet to be fully implemented.

This placeholder is so that code paths can be "declared but not defined" and implementations safely postponed in a greppable manner. This should not be used to define "unused" overrides for virtual classes. A correct use case would be:

if (z > AtomicNumber{26})
{
CELER_NOT_IMPLEMENTED("physics for heavy nuclides");
}
#define CELER_NOT_IMPLEMENTED(WHAT)
Assert if the code point is reached because a feature has yet to be fully implemented.
Definition Assert.hh:245

◆ CELER_RUNTIME_THROW

#define CELER_RUNTIME_THROW (   WHICH,
  WHAT,
  COND 
)
Value:
throw ::celeritas::RuntimeError({ \
WHICH, \
WHAT, \
COND, \
__FILE__, \
__LINE__, \
})

◆ CELER_VALIDATE

#define CELER_VALIDATE (   COND,
  MSG 
)
Value:
do \
{ \
if (CELER_UNLIKELY(!(COND))) \
{ \
std::ostringstream celer_runtime_msg_; \
celer_runtime_msg_ MSG; \
CELER_RUNTIME_THROW( \
celer_runtime_msg_.str(), \
#COND); \
} \
} while (0)
#define CELER_UNLIKELY(COND)
Mark the result of this condition to be "unlikely".
Definition Macros.hh:95
static char const validate_err_str[]
Definition Assert.hh:426

Always-on runtime assertion macro.

This can check user input and input data consistency, and will raise RuntimeError on failure with a descriptive error message that is streamed as the second argument. This macro cannot be used in __device__ -annotated code.

The error message should read:

 "<PROBLEM> (<WHY IT'S A PROBLEM>) <SUGGESTION>?"

Examples with correct casing and punctuation:

  • "failed to open '{filename}' (should contain relaxation data)"
  • "unexpected end of file '{filename}' (data is inconsistent with boundaries)"
  • "MPI was not initialized (needed to construct a communicator). Maybe set the environment variable CELER_DISABLE_PARALLEL=1 to disable externally?"
  • "invalid min_range={opts.min_range} (must be positive)"

This looks in practice like:

CELER_VALIDATE(file_stream,
<< "failed to open '" << filename
<< "' (should contain relaxation data)");
#define CELER_VALIDATE(COND, MSG)
Always-on runtime assertion macro.
Definition Assert.hh:225

An always-on debug-type assertion without a detailed message can be constructed by omitting the stream (but leaving the comma):

CELER_VALIDATE(file_stream,);

Enumeration Type Documentation

◆ DebugErrorType

enum class celeritas::DebugErrorType
strong
Enumerator
precondition 

Precondition contract violation.

internal 

Internal assertion check failure.

unreachable 

Internal assertion: unreachable code path.

postcondition 

Postcondition contract violation.

assumption 

"Assume" violation