Skip to content

Commit

Permalink
Merge pull request #31 from kidder/feature/error_handling
Browse files Browse the repository at this point in the history
Add namespace Parallel and functions for enabling FPEs
  • Loading branch information
nilsdeppe committed Jun 1, 2017
2 parents b30669e + 6eb3c02 commit e393b0e
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 32 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Distributed under the MIT License.
# See LICENSE.txt for details.

add_subdirectory(ErrorHandling)
add_subdirectory(Executables)
10 changes: 10 additions & 0 deletions src/ErrorHandling/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Distributed under the MIT License.
# See LICENSE.txt for details.

set(library ErrorHandling)

set(library_sources
FloatingPointExceptions.cpp
)

add_library(${library} ${library_sources})
43 changes: 43 additions & 0 deletions src/ErrorHandling/FloatingPointExceptions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "ErrorHandling/FloatingPointExceptions.hpp"

#include "Parallel/Abort.hpp"

#include <csignal>

#ifdef __APPLE__
#include <xmmintrin.h>
#else
#include <fenv.h>
#endif

namespace {

#ifdef __APPLE__
auto old_mask = _mm_getcsr();
#endif

[[noreturn]] void fpe_signal_handler(int /*signal*/) {
Parallel::abort("Floating point exception!"); // LCOV_EXCL_LINE
}
} // namespace

void enable_floating_point_exceptions() {
#ifdef __APPLE__
_mm_setcsr(_MM_MASK_MASK &
~(_MM_MASK_OVERFLOW | _MM_MASK_INVALID | _MM_MASK_DIV_ZERO));
#else
feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
#endif
signal(SIGFPE, fpe_signal_handler);
}

void disable_floating_point_exceptions() {
#ifdef __APPLE__
_mm_setcsr(old_mask);
#else
fedisableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
#endif
}
17 changes: 17 additions & 0 deletions src/ErrorHandling/FloatingPointExceptions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

/// \file
/// Functions to enable/disable termination on floating point exceptions

#pragma once

/// \ingroup ErrorHandling
/// After a call to this function, the code will terminate with a floating
/// point exception on overflow, divide-by-zero, and invalid operations.
void enable_floating_point_exceptions();

/// \ingroup ErrorHandling
/// After a call to this function, the code will NOT terminate with a floating
/// point exception on overflow, divide-by-zero, and invalid operations.
void disable_floating_point_exceptions();
24 changes: 24 additions & 0 deletions src/Parallel/Abort.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

/// \file
/// Defines function Parallel::abort.

#pragma once

#include <charm++.h>
#include <exception>
#include <string>

namespace Parallel {

/// \ingroup Parallel
/// Abort the program with an error message.
[[noreturn]] inline void abort(const std::string& message) {
CkAbort(message.c_str());
// the following call is never reached, but suppresses the warning that
// a 'noreturn' functions does return
std::terminate(); // LCOV_EXCL_LINE
}

} // namespace Parallel
25 changes: 25 additions & 0 deletions src/Parallel/Exit.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

/// \file
/// Defines function Parallel::exit.

#pragma once

#include <charm++.h>
#include <exception>

/// Contains functions that forward to Charm++ parallel functions.
namespace Parallel {

/// \ingroup Parallel
/// \brief Exit the program normally.
/// This should only be called once over all processors.
[[noreturn]] inline void exit() {
CkExit();
// the following call is never reached, but suppresses the warning that
// a 'noreturn' function does return
std::terminate(); // LCOV_EXCL_LINE
}

} // namespace Parallel
14 changes: 8 additions & 6 deletions tests/Unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@ set(executable RunTests)

set(SPECTRE_TESTS "TestFramework.cpp")

add_subdirectory(ErrorHandling)
add_subdirectory(Utilities)

add_charm_mainmodule(${executable})

add_executable(
${executable}
${executable}.cpp
${executable}.decl.h
${executable}.def.h
${SPECTRE_TESTS}
${executable}
${executable}.cpp
${executable}.decl.h
${executable}.def.h
${SPECTRE_TESTS}
)

target_link_libraries(
${executable}
${executable}
ErrorHandling
)

spectre_add_catch_tests(${executable})
Expand Down
9 changes: 9 additions & 0 deletions tests/Unit/ErrorHandling/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Distributed under the MIT License.
# See LICENSE.txt for details.

list(APPEND ERROR_HANDLING_TESTS ErrorHandling/FloatingPointExceptions.cpp)

# CMake cannot append to a list in the parent scope
list(APPEND ERROR_HANDLING_TESTS ${SPECTRE_TESTS})
set(SPECTRE_TESTS "${ERROR_HANDLING_TESTS}" PARENT_SCOPE)

48 changes: 48 additions & 0 deletions tests/Unit/ErrorHandling/FloatingPointExceptions.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#include <catch.hpp>
#include <cmath>
#include <limits>

#include "ErrorHandling/FloatingPointExceptions.hpp"

// [[OutputRegex, Floating point exception!]]
TEST_CASE("Unit.ErrorHandling.FloatingPointExceptions.Invalid",
"[ErrorHandling][Unit]") {
enable_floating_point_exceptions();
double x = -1.0;
double invalid = sqrt(x);
CHECK(true);
}

// [[OutputRegex, Floating point exception!]]
TEST_CASE("Unit.ErrorHandling.FloatingPointExceptions.Overflow",
"[ErrorHandling][Unit]") {
enable_floating_point_exceptions();
volatile double overflow = std::numeric_limits<double>::max();
overflow *= 1.0e300;
CHECK(true);
}

// [[OutputRegex, Floating point exception!]]
TEST_CASE("Unit.ErrorHandling.FloatingPointExceptions.DivByZero",
"[ErrorHandling][Unit]") {
enable_floating_point_exceptions();
volatile double div_by_zero = 1.0;
div_by_zero /= 0.0;
CHECK(true);
}

TEST_CASE("Unit.ErrorHandling.FloatingPointExceptions.Disable",
"[ErrorHandling][Unit]") {
enable_floating_point_exceptions();
disable_floating_point_exceptions();
double x = -1.0;
double invalid = sqrt(x);
volatile double overflow = std::numeric_limits<double>::max();
overflow *= 1.0e300;
volatile double div_by_zero = 1.0;
div_by_zero /= 0.0;
CHECK(true);
}
11 changes: 9 additions & 2 deletions tests/Unit/RunTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@

#include <catch.hpp>

#include "ErrorHandling/FloatingPointExceptions.hpp"
#include "Informer/InfoFromBuild.hpp"
#include "Parallel/Abort.hpp"
#include "Parallel/Exit.hpp"

RunTests::RunTests(CkArgMsg* msg) {
printf("%s", info_from_build().c_str());
enable_floating_point_exceptions();
int result = Catch::Session().run(msg->argc, msg->argv);
if (0 == result) {
CkExit();
Parallel::exit();
}
CkAbort("A catch test has failed.");
Parallel::abort("A catch test has failed.");
}

#include "tests/Unit/RunTests.def.h"
5 changes: 4 additions & 1 deletion tests/Unit/RunTests.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@

#pragma once

#include <charm++.h>

#include "tests/Unit/RunTests.decl.h"

/// Main executable for running the unit tests.
class RunTests : public CBase_RunTests {
public:
explicit RunTests(CkArgMsg* msg);
[[noreturn]] explicit RunTests(CkArgMsg* msg);
};
41 changes: 18 additions & 23 deletions tests/Unit/Utilities/ConstantExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@

namespace {
template <typename T>
void TestT() {
const T zero = 0;
const T one = 1;
const T two = 2;
const T three = 3;
const T four = 4;
const T eight = 8;
const T sixteen = 16;

CHECK((one == two_to_the(zero)));
struct TestT {
static constexpr T zero = 0;
static constexpr T one = 1;
static constexpr T two = 2;
static constexpr T three = 3;
static constexpr T four = 4;
static constexpr T eight = 8;
static constexpr T sixteen = 16;

static_assert(one == two_to_the(zero),
"Failed test Unit.Utilities.ConstantExpressions");
Expand All @@ -28,17 +26,14 @@ void TestT() {
"Failed test Unit.Utilities.ConstantExpressions");
static_assert(sixteen == two_to_the(four),
"Failed test Unit.Utilities.ConstantExpressions");
}
} // namespace
};

TEST_CASE("Unit.Utilities.ConstantExpressions", "[Utilities][Unit]") {
TestT<int>();
TestT<short>();
TestT<long>();
TestT<long long>();
TestT<unsigned int>();
TestT<unsigned short>();
TestT<unsigned long>();
TestT<unsigned long long>();
TestT<std::size_t>();
}
template struct TestT<int>;
template struct TestT<short>;
template struct TestT<long>;
template struct TestT<long long>;
template struct TestT<unsigned int>;
template struct TestT<unsigned short>;
template struct TestT<unsigned long>;
template struct TestT<unsigned long long>;
} // namespace

0 comments on commit e393b0e

Please sign in to comment.