Skip to content

Commit

Permalink
Merge pull request #35 from nilsdeppe/feature/add_utilities
Browse files Browse the repository at this point in the history
Start adding Utilities
  • Loading branch information
kidder committed Jun 3, 2017
2 parents 705be89 + ba3bb85 commit d66b948
Show file tree
Hide file tree
Showing 22 changed files with 673 additions and 11 deletions.
2 changes: 2 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Language: Cpp
BasedOnStyle: Google
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
PointerAlignment: Left
DerivePointerAlignment: false
IncludeCategories:
- Regex: '^<.*'
Priority: 1
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ include(SetupLibCXX)
include(SetupClangFormat)
include(SetupClangTidy)
include(SetupCppCheck)
include(SetupCxxFlags)
include(SetupSanitizers)
include(SetupListTargets)
include(SetupDoxygen)
Expand Down
8 changes: 4 additions & 4 deletions cmake/CodeCoverage.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -97,23 +97,23 @@ function(SETUP_TARGET_FOR_COVERAGE
COMMAND ${TEST_RUNNER} ${ARG_TESTRUNNER_ARGS}
# Capture lcov counters
COMMAND ${LCOV} --gcov-tool ${GCOV} --capture
--rc lcov_branch_coverage=1 --directory .
--rc lcov_branch_coverage=0 --directory .
--output-file ${OUTPUT}.test.info
# Combine trace files
COMMAND ${LCOV} --gcov-tool ${GCOV} --rc lcov_branch_coverage=1
COMMAND ${LCOV} --gcov-tool ${GCOV} --rc lcov_branch_coverage=0
--add-tracefile ${OUTPUT}.base.info
--add-tracefile ${OUTPUT}.test.info
--output-file ${OUTPUT}.total.info
# Filter out unwanted files
COMMAND ${LCOV} --gcov-tool ${GCOV} --rc lcov_branch_coverage=1
COMMAND ${LCOV} --gcov-tool ${GCOV} --rc lcov_branch_coverage=0
--remove ${OUTPUT}.total.info '*/c++/*' '*/include/*'
'*/boost/*' '*/charm/*' '*.decl.h' '*.def.h'
'*/STDIN' '*/tut/*' '*/moduleinit*'
'${CMAKE_SOURCE_DIR}/src/Executables/*'
${ARG_IGNORE_COV}
--output-file ${OUTPUT}.filtered.info
# Generate HTML report
COMMAND ${GENHTML} --legend --branch-coverage --demangle-cpp
COMMAND ${GENHTML} --legend --demangle-cpp
--title `cd ${CMAKE_SOURCE_DIR} && git rev-parse HEAD`
-o ${OUTPUT} ${OUTPUT}.filtered.info
# Customize page headers in generated html to own
Expand Down
15 changes: 15 additions & 0 deletions cmake/SetupCxxFlags.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Distributed under the MIT License.
# See LICENSE.txt for details.

set(
CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} -DSPECTRE_DEBUG -D_GLIBCXX_DEBUG"
)

# Always build with -g so we can view backtraces, etc. when production code
# fails. This can be overridden by passing `-D CMAKE_CXX_FLAGS="-g0"` to CMake
set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}")

# Always compile only for the current architecture. This can be overridden
# by passing `-D CMAKE_CXX_FLAGS="-march=THE_ARCHITECTURE"` to CMake
set(CMAKE_CXX_FLAGS "-march=native ${CMAKE_CXX_FLAGS}")
9 changes: 9 additions & 0 deletions cmake/SetupLibCXX.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,13 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "-stdlib=libc++ ${CMAKE_CXX_FLAGS}")
message(STATUS "libc++ include: ${LIBCXX_INCLUDE_DIRS}")
message(STATUS "libc++ libraries: ${LIBCXX_LIBRARIES}")

option(
LIBCXX_DEBUG
"Enable debug mode for libc++ in Debug builds"
OFF
)
if(LIBCXX_DEBUG)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_LIBCPP_DEBUG=0")
endif()
endif()
38 changes: 38 additions & 0 deletions src/ErrorHandling/AbortWithErrorMessage.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "ErrorHandling/AbortWithErrorMessage.hpp"

#include <sstream>

#include "Parallel/Abort.hpp"
#include "Parallel/Info.hpp"

void abort_with_error_message(const char* expression, const char* file,
const int line, const std::string& message) {
std::ostringstream os;
os << "\n"
<< "############ ASSERT FAILED ############\n"
<< "Node: " << Parallel::my_node() << " Proc: " << Parallel::my_proc()
<< "\n"
<< "Line: " << line << " of " << file << "\n"
<< "'" << expression << "' violated!\n"
<< message << "\n"
<< "############ ASSERT FAILED ############\n"
<< "\n";
Parallel::abort(os.str());
}

void abort_with_error_message(const char* file, const int line,
const std::string& message) {
std::ostringstream os;
os << "\n"
<< "############ ERROR ############\n"
<< "Node: " << Parallel::my_node() << " Proc: " << Parallel::my_proc()
<< "\n"
<< "Line: " << line << " of " << file << "\n"
<< message << "\n"
<< "############ ERROR ############\n"
<< "\n";
Parallel::abort(os.str());
}
20 changes: 20 additions & 0 deletions src/ErrorHandling/AbortWithErrorMessage.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

/// \file
/// Declares function abort_with_error_message

#pragma once

#include <string>

/// \ingroup ErrorHandling
/// Compose an error message with an expression and abort the program.
[[noreturn]] void abort_with_error_message(const char* expression,
const char* file, int line,
const std::string& message);

/// \ingroup ErrorHandling
/// Compose an error message and abort the program.
[[noreturn]] void abort_with_error_message(const char* file, int line,
const std::string& message);
85 changes: 85 additions & 0 deletions src/ErrorHandling/Assert.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

/// \file
/// Defines macro ASSERT.

#pragma once

#include <sstream>
#include <string>

#include "ErrorHandling/AbortWithErrorMessage.hpp"
#include "Parallel/Abort.hpp"
#include "Utilities/Literals.hpp"

/*!
* \ingroup ErrorHandling
* \brief Assert that an expression should be true.
*
* If the preprocessor macro SPECTRE_DEBUG is defined and the expression is
* false, an error message is printed to the standard error stream, and the
* program aborts. ASSERT should be used to catch coding errors as it does
* nothing in production code.
* \param a the expression that must be true
* \param m the error message as an ostream
*/
#ifdef SPECTRE_DEBUG
// isocpp.org recommends using an `if (true)` instead of a `do
// while(false)` for macros because the latter can mess with inlining
// in some (old?) compilers:
// https://isocpp.org/wiki/faq/misc-technical-issues#macros-with-multi-stmts
// https://isocpp.org/wiki/faq/misc-technical-issues#macros-with-if
// However, Intel's reachability analyzer (as of version 16.0.3
// 20160415) can't figure out that the else branch and everything
// after it is unreachable, causing warnings (and possibly suboptimal
// code generation).
#define ASSERT(a, m) \
do { \
if (!(a)) { \
std::ostringstream avoid_name_collisions_ASSERT; \
avoid_name_collisions_ASSERT << m; /* NOLINT */ \
abort_with_error_message(#a, __FILE__, __LINE__, \
avoid_name_collisions_ASSERT.str()); \
} \
} while (false)
#else
#define ASSERT(a, m) \
do { \
if (false) { \
static_cast<void>(a); \
std::ostringstream avoid_name_collisions_ASSERT; \
avoid_name_collisions_ASSERT << m; \
static_cast<void>(avoid_name_collisions_ASSERT); \
} \
} while (false)
#endif

// If SPECTRE_DEBUG is not defined, a void cast is used to avoid an unused
// variable compiler warning when a passed parameter is only used in an ASSERT.
// This is inside an if(false) statement so that the code never actually gets
// executed and only placates the compiler.

/*!
* \ingroup ErrorHandling
* \brief Assert that an expression should be true.
*
* Just like ASSERT and so the same guidelines apply. However, because
* it does not use std::stringstream it can be used in some constexpr
* functions where ASSERT cannot be.
* \param a the expression that must be satisfied
* \param m a std::string holding the error message
*/
#ifdef SPECTRE_DEBUG
#define CASSERT(a, m) \
do { \
if (!(a)) { \
Parallel::abort("\n############ ASSERT FAILED ############\nLine: "s + \
std::to_string(__LINE__) + " of file '"s + __FILE__ + \
"'\n"s + "Condition: "s + #a + "\n"s + m + /* NOLINT */ \
"\n#######################################\n"s); \
} \
} while (false)
#else
#define CASSERT(a, m)
#endif
4 changes: 2 additions & 2 deletions src/ErrorHandling/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
set(library ErrorHandling)

set(library_sources
FloatingPointExceptions.cpp
)
AbortWithErrorMessage.cpp
FloatingPointExceptions.cpp)

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

/// \file
/// Defines macro ERROR.

#pragma once

#include <sstream>
#include <string>

#include "ErrorHandling/AbortWithErrorMessage.hpp"
#include "Parallel/Abort.hpp"
#include "Utilities/Literals.hpp"

/*!
* \ingroup ErrorHandling
* \brief prints an error message to the standard error stream and aborts the
* program.
*
* ERROR should not be used for coding errors, but instead for user errors
* or failure modes of numerical algorithms. An acceptable use for error is also
* in the default case of a switch statement.
* \param m an arbitrary output stream.
*/
// isocpp.org recommends using an `if (true)` instead of a `do
// while(false)` for macros because the latter can mess with inlining
// in some (old?) compilers:
// https://isocpp.org/wiki/faq/misc-technical-issues#macros-with-multi-stmts
// https://isocpp.org/wiki/faq/misc-technical-issues#macros-with-if
// However, Intel's reachability analyzer (as of version 16.0.3
// 20160415) can't figure out that the else branch and everything
// after it is unreachable, causing warnings (and possibly suboptimal
// code generation).
#define ERROR(m) \
do { \
std::ostringstream avoid_name_collisions_ERROR; \
avoid_name_collisions_ERROR << m; /* NOLINT */ \
abort_with_error_message(__FILE__, __LINE__, \
avoid_name_collisions_ERROR.str()); \
} while (false)

/*!
* \ingroup ErrorHandling
* \brief prints an error message to the standard error and aborts the
* program.
*
* CERROR is just like ERROR and so the same guidelines apply. However, because
* it does not use std::stringstream it can be used in some constexpr
* functions where ERROR cannot be.
* \param m error message as a string, may need to use string literals
*/
#define CERROR(m) \
do { \
Parallel::abort("\n################ ERROR ################\nLine: "s + \
std::to_string(__LINE__) + " of file '"s + __FILE__ + \
"'\n"s + m + /* NOLINT */ \
"\n#######################################\n"s); \
} while (false)
92 changes: 92 additions & 0 deletions src/Parallel/Info.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

/// \file
/// Defines functions for interfacing with the parallelization framework

#pragma once

#include <charm++.h>

namespace Parallel {
/*!
* \ingroup Parallel
* \brief Number of processing elements.
*/
inline int number_of_procs() { return CkNumPes(); }

/*!
* \ingroup Parallel
* \brief %Index of my processing element.
*/
inline int my_proc() { return CkMyPe(); }

/*!
* \ingroup Parallel
* \brief Number of nodes.
*/
inline int number_of_nodes() { return CkNumNodes(); }

/*!
* \ingroup Parallel
* \brief %Index of my node.
*/
inline int my_node() { return CkMyNode(); }

/*!
* \ingroup Parallel
* \brief Number of processing elements on the given node.
*/
inline int procs_on_node(const int node_index) {
// When using the verbs-linux-x86_64 non-SMP build of Charm++ these
// functions have unused-parameter warnings. This is remedied by
// casting the integer to a void which results in no extra assembly
// code being generated. We use this instead of pragmas because we
// would require one pragma for GCC and one for clang, which would
// result in code duplication. Commenting out the variable
// nodeIndex gives compilation failures on most Charm++ builds since
// they actually use the variable. Charm++ plz...
static_cast<void>(node_index);
return CkNodeSize(node_index);
}

/*!
* \ingroup Parallel
* \brief The local index of my processing element on my node.
* This is in the interval 0, ..., procs_on_node(my_node()) - 1.
*/
inline int my_local_rank() { return CkMyRank(); }

/*!
* \ingroup Parallel
* \brief %Index of first processing element on the given node.
*/
inline int first_proc_on_node(const int node_index) {
static_cast<void>(node_index);
return CkNodeFirst(node_index);
}

/*!
* \ingroup Parallel
* \brief %Index of the node for the given processing element.
*/
inline int node_of(const int proc_index) {
static_cast<void>(proc_index);
return CkNodeOf(proc_index);
}

/*!
* \ingroup Parallel
* \brief The local index for the given processing element on its node.
*/
inline int local_rank_of(const int proc_index) {
static_cast<void>(proc_index);
return CkRankOf(proc_index);
}

/*!
* \ingroup Parallel
* \brief The current wall time in seconds
*/
inline double wall_time() { return CmiWallTimer(); }
} // namespace Parallel

0 comments on commit d66b948

Please sign in to comment.