Skip to content

Commit

Permalink
Floating-point exceptions instrumentation
Browse files Browse the repository at this point in the history
  • Loading branch information
jngrad committed Dec 18, 2024
1 parent f87aa66 commit 36d3537
Show file tree
Hide file tree
Showing 15 changed files with 639 additions and 4 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/push_pull.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ jobs:
- name: Build and check
uses: ./.github/actions/build_and_check
env:
build_procs: 4
check_procs: 4
build_procs: 3
check_procs: 3
with_ccache: 'true'

debian:
Expand Down
8 changes: 6 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ style_doxygen:
- mkdir build
- cd build
- cp ../maintainer/configs/maxset.hpp myconfig.hpp
- cmake .. -D ESPRESSO_BUILD_WITH_CUDA=ON -D ESPRESSO_BUILD_WITH_GSL=ON -D ESPRESSO_BUILD_WITH_HDF5=ON -D ESPRESSO_BUILD_WITH_SCAFACOS=ON -D ESPRESSO_BUILD_WITH_WALBERLA=ON -D ESPRESSO_BUILD_WITH_WALBERLA_FFT=ON -D ESPRESSO_BUILD_WITH_STOKESIAN_DYNAMICS=ON -D ESPRESSO_BUILD_WITH_CALIPER=ON
- cmake .. -D ESPRESSO_BUILD_WITH_CUDA=ON -D ESPRESSO_BUILD_WITH_GSL=ON -D ESPRESSO_BUILD_WITH_HDF5=ON -D ESPRESSO_BUILD_WITH_SCAFACOS=ON -D ESPRESSO_BUILD_WITH_WALBERLA=ON -D ESPRESSO_BUILD_WITH_WALBERLA_FFT=ON -D ESPRESSO_BUILD_WITH_STOKESIAN_DYNAMICS=ON -D ESPRESSO_BUILD_WITH_CALIPER=ON -D ESPRESSO_BUILD_WITH_FPE=ON
- sh ../maintainer/CI/dox_warnings.sh
tags:
- espresso
Expand Down Expand Up @@ -132,7 +132,8 @@ no_rotation:
with_cuda: 'false'
myconfig: 'no_rotation'
with_coverage: 'true'
with_scafacos: 'true'
with_scafacos: 'false'
with_fpe: 'true'
check_skip_long: 'true'
script:
- bash maintainer/CI/build_cmake.sh
Expand All @@ -148,6 +149,8 @@ fedora:40:
variables:
with_cuda: 'false'
with_gsl: 'false'
with_scafacos: 'false'
with_fpe: 'true'
myconfig: 'maxset'
make_check_python: 'true'
with_stokesian_dynamics: 'true'
Expand Down Expand Up @@ -422,6 +425,7 @@ empty:
with_scafacos: 'false'
with_walberla: 'false'
with_stokesian_dynamics: 'false'
with_fpe: 'true'
with_coverage: 'false'
with_coverage_python: 'true'
script:
Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ option(ESPRESSO_BUILD_BENCHMARKS "Enable benchmarks" OFF)
option(ESPRESSO_BUILD_WITH_VALGRIND "Build with Valgrind instrumentation" OFF)
option(ESPRESSO_BUILD_WITH_CALIPER "Build with Caliper instrumentation" OFF)
option(ESPRESSO_BUILD_WITH_CPPCHECK "Run Cppcheck during compilation" OFF)
option(ESPRESSO_BUILD_WITH_FPE
"Build with floating-point exceptions instrumentation" OFF)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
option(ESPRESSO_BUILD_WITH_CLANG_TIDY "Run Clang-Tidy during compilation" OFF)
endif()
Expand Down
2 changes: 2 additions & 0 deletions cmake/espresso_cmake_config.cmakein
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

#cmakedefine ESPRESSO_BUILD_WITH_CALIPER

#cmakedefine ESPRESSO_BUILD_WITH_FPE

#define PACKAGE_NAME "${PROJECT_NAME}"

/**
Expand Down
38 changes: 38 additions & 0 deletions doc/bibliography.bib
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ @Article{andersen83a
doi = {10.1016/0021-9991(83)90014-1},
}

@TechReport{ARM-DDI-0487-2024,
author = {{Arm Limited}},
title = {Arm Architecture Reference Manual for {A}-profile architecture},
type = {Manual},
number = {ARM DDI 0487},
month = nov,
year = {2024},
address = {Cambridge, England},
institution = {Arm Limited},
url = {https://developer.arm.com/documentation/ddi0487/latest/},
}

@Article{arnold02a,
author = {Arnold, Axel and Holm, Christian},
title = {{MMM2D}: {A} fast and accurate summation method for electrostatic interactions in {2D} slab geometries},
Expand Down Expand Up @@ -598,6 +610,32 @@ @Article{humphrey96a
doi = {10.1016/0263-7855(96)00018-5},
}

@TechReport{ISO-EIC-60559-2020,
author = {{International Organization for Standardization} and {International Electrotechnical Commission} and {Institute of Electrical and Electronics Engineers}},
title = {International Standard -- Floating-point arithmetic},
type = {Standard},
number = {{ISO}/{IEC} 60559:2020({E}), {IEEE} Std 754-2019},
month = may,
year = {2020},
edition = {2nd},
institution = {Institute of Electrical and Electronics Engineers},
isbn = {978-1-5044-6641-7},
doi = {10.1109/IEEESTD.2020.9091348},
}

@TechReport{ISO-EIC-9899-1999,
author = {{International Organization for Standardization} and {International Electrotechnical Commission}},
title = {Information technology --- Programming languages --- {C}},
type = {Standard},
number = {{ISO}/{IEC} 9899:1999},
month = dec,
year = {1999},
edition = {2nd},
address = {Geneva, Switzerland},
institution = {International Organization for Standardization},
url = {https://www.iso.org/standard/29237.html},
}

@Article{jancigova16a,
author = {Jan\v{c}igov\'{a}, Iveta and Cimr\'{a}k, Ivan},
title = {Non-uniform force allocation for area preservation in spring network models},
Expand Down
58 changes: 58 additions & 0 deletions doc/sphinx/running.rst
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,11 @@ you can as a last resort activate sanitizers:
The resulting build will be around 5 times slower that a debug build,
but it will generate valuable reports when detecting fatal exceptions.

If you are dealing with non-finite math errors (infinity, NaN, etc.),
you can interrupt code execution at the first occurence of a non-finite
value using :ref:`floating-point exceptions <FPE>` and investigate
the failing mathematical operation in GDB.

It is possible to attach an external debugger to ``pypresso``, albeit with
a custom syntax. The ``pypresso`` executable file is actually not a program
but a script which sets the Python path appropriately and starts the Python
Expand Down Expand Up @@ -756,6 +761,59 @@ array accesses out of bounds, signed integer overflows, etc.

For more details, please consult the tool online documentation [6]_.

.. _FPE:

FPE
~~~

.. note::

Requires specific compiler and linker flags, enabled with the CMake option
``-D ESPRESSO_BUILD_WITH_FPE=ON -D CMAKE_BUILD_TYPE=Debug``.

When abnormal mathematical operations take place at runtime,
for example divisions by zero, multiplication of infinity with zero,
square roots and logarithms of negative numbers, overflows, underflows,
or conversion of NaN values to integers, CPU flags may be raised.
The flags are known as *CPU exceptions*, and can be queried to detect
if a past operation yielded an abnormal result. They can be unmasked
to automatically *trap*, i.e. leave the user space and enter kernel space,
where the operating system will run a callback function, which may send
a POSIX signal such as ``SIGFPE`` or ``SIGILL``. Those signals can be
captured by a user-defined *signal handler*, which takes the form of a
C++ function with strict restrictions on which operations it can execute,
and are typically assigning an integer into a global variable for debugging.
Execution then resumes in user space on the exact same instruction that
originally trapped, potentially entering an infinite loop.

C libraries like GNU libc provide support for floating-point exceptions
(FPE or FE). These can be unmasked to interrupt |es| on the first occurrence
of an abnormal floating-point operation. This is achieved by sending a signal
that can be caught in GDB to allow inspection of the failing code.

When FPE instrumentation is enabled, most script interface calls will be
monitored for abnormal mathematical operations. One can select which subset
of CPU exceptions will trap by explicitly providing a bitmask to the FPE
handler constructor, like so:

.. code-block:: c++

Variant ObjectHandle::call_method(const std::string &name,
const VariantMap &params) {
if (m_context)
m_context->notify_call_method(this, name, params);

#ifdef FPE
auto const trap = fe_trap::make_shared_scoped(FE_DIVBYZERO | FE_INVALID);
#endif
return this->do_call_method(name, params);
}

For more details, see annex F IEC 60559 "floating-point arithmetic"
in ISO/EIC 9899 :cite:`ISO-EIC-9899-1999` and chapter 7
"Exceptions and default exception handling" in
ISO/IEC 60559:2020(E) :cite:`ISO-EIC-60559-2020`.

.. _Caliper:

Caliper
Expand Down
2 changes: 2 additions & 0 deletions maintainer/CI/build_cmake.sh
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ set_default_value with_ubsan false
set_default_value with_asan false
set_default_value with_static_analysis false
set_default_value with_caliper false
set_default_value with_fpe false
set_default_value myconfig "default"
set_default_value build_procs ${ci_procs}
set_default_value check_procs ${build_procs}
Expand Down Expand Up @@ -147,6 +148,7 @@ cmake_params="${cmake_params} -D ESPRESSO_CTEST_ARGS:STRING=-j${check_procs} -D
cmake_params="${cmake_params} -D ESPRESSO_BUILD_BENCHMARKS=${make_check_benchmarks}"
cmake_params="${cmake_params} -D ESPRESSO_BUILD_WITH_CCACHE=${with_ccache}"
cmake_params="${cmake_params} -D ESPRESSO_BUILD_WITH_CALIPER=${with_caliper}"
cmake_params="${cmake_params} -D ESPRESSO_BUILD_WITH_FPE=${with_fpe}"
cmake_params="${cmake_params} -D ESPRESSO_BUILD_WITH_HDF5=${with_hdf5}"
cmake_params="${cmake_params} -D ESPRESSO_BUILD_WITH_FFTW=${with_fftw}"
cmake_params="${cmake_params} -D ESPRESSO_BUILD_WITH_GSL=${with_gsl}"
Expand Down
1 change: 1 addition & 0 deletions src/config/features.def
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,4 @@ WALBERLA external
WALBERLA_FFT external
VALGRIND external
CALIPER external
FPE external
5 changes: 5 additions & 0 deletions src/core/unit_tests/EspressoSystemStandAlone_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ namespace utf = boost::unit_test;
#include "particle_node.hpp"
#include "system/System.hpp"

#include <instrumentation/fe_trap.hpp>

#include <utils/Vector.hpp>
#include <utils/index.hpp>
#include <utils/math/int_pow.hpp>
Expand Down Expand Up @@ -95,6 +97,9 @@ BOOST_FIXTURE_TEST_CASE(espresso_system_stand_alone, ParticleFactory) {
auto const comm = boost::mpi::communicator();
auto const rank = comm.rank();
auto const n_nodes = comm.size();
#if defined(FPE)
auto const trap = fe_trap::make_unique_scoped();
#endif

auto const box_l = 12.;
auto const box_center = box_l / 2.;
Expand Down
19 changes: 19 additions & 0 deletions src/instrumentation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@

add_library(espresso_instrumentation INTERFACE)
add_library(espresso::instrumentation ALIAS espresso_instrumentation)
target_include_directories(
espresso_instrumentation
INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)

if(ESPRESSO_BUILD_WITH_VALGRIND)
target_include_directories(espresso_instrumentation
Expand All @@ -31,3 +35,18 @@ if(ESPRESSO_BUILD_WITH_CALIPER)
espresso_instrumentation INTERFACE "${caliper_SOURCE_DIR}/include"
"${caliper_BINARY_DIR}/include")
endif()

if(ESPRESSO_BUILD_WITH_FPE)
add_library(espresso_fpe SHARED src/fe_trap.cpp)
add_library(espresso::fpe ALIAS espresso_fpe)
target_link_libraries(espresso_fpe PRIVATE espresso::config
espresso::cpp_flags)
target_include_directories(
espresso_fpe PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_link_libraries(espresso_instrumentation INTERFACE espresso::fpe)
install(TARGETS espresso_fpe
LIBRARY DESTINATION ${ESPRESSO_INSTALL_PYTHON}/espressomd)
endif()

add_subdirectory(tests)
Loading

0 comments on commit 36d3537

Please sign in to comment.