diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d015d3..5e8f806 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,271 +1,278 @@ #################################################### # # # SpecMiCP : CMakeLists.txt # # # #################################################### project(specmicp) cmake_minimum_required(VERSION 3.2) # CMake Options # ============= # For an explanation of the options see the INSTALL file option( SPECMICP_USE_OPENMP "Use OpenMP for parallelisation" ON ) option( SPECMICP_NO_DEBUG "Disable SpecMiCP assert" OFF ) option( SPECMICP_BUILD_STATIC "Build static libraries" OFF ) option( SPECMICP_BUILD_EXAMPLE "Build the examples" ON ) option( SPECMICP_BENCHMARK "Build benchmark" OFF ) option( SPECMICP_TEST "Enable testing" ON ) option( SPECMICP_BINARIES_USE_STATIC "Executables use static libraries" OFF ) # the following is only a debug options for developpers option( SPECMICP_DEBUG_EQUATION_FD_JACOBIAN "Use a finite difference jacobian" OFF ) # PGO sequence option( SPECMICP_PROFILE_GENERATE "Generate profile for PGO optimization" OFF ) option( SPECMICP_PROFILE_USE "Use profile for PGO optimization" OFF ) # LTO optimization option( SPECMICP_LTO "Use link time optimization" OFF ) option( SPECMICP_LD_GOLD "Use GNU gold linker" ON ) # global variables # ================ set(SPECMICP_VERSION 0.0.4) # External Package # ================ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) # OpenMP #------- # not required but recommended if(SPECMICP_USE_OPENMP) find_package(OpenMP) if (OPENMP_FOUND) set(SPECMICP_HAVE_OPENMP ON) endif(OPENMP_FOUND) endif() # Eigen # ----- find_package(Eigen3 REQUIRED) # This module comes from the Eigen3 Package include_directories(${EIGEN3_INCLUDE_DIR}) # Eigen unsuported # GMRES.h is really the file we are using/looking for # If it doesn't exist then the solver will not be included in the list of the parse solvers set( EIGEN_GMRES_PATH "${EIGEN3_INCLUDE_DIR}/unsupported/Eigen/src/IterativeSolvers/GMRES.h") if( EXISTS ${EIGEN_GMRES_PATH} ) add_definitions(-DEIGEN_UNSUPPORTED_FOUND) include_directories("${EIGEN3_INCLUDE_DIR}/unsupported/") endif() # Yaml-cpp # -------- include(FindPkgConfig) pkg_check_modules(YAML REQUIRED yaml-cpp>=0.5) include_directories(${YAML_INCLUDE_DIRS}) link_directories(${YAML_LIBRARY_DIRS}) # HDF5 # ---- find_package(HDF5 REQUIRED COMPONENTS C CXX) # HDF5 is optional, must be checked by files that used it # glibc functions # --------------- include(CheckIncludeFile) include(CheckFunctionExists) macro(check_required_include name var) CHECK_INCLUDE_FILE( ${name} ${var} ) if (NOT ${var}) message(SEND_ERROR "Missing required include ${name}") endif() endmacro(check_required_include) check_required_include( "string.h" HAVE_STRING_H ) check_required_include( "dirent.h" HAVE_DIRENT_H ) check_required_include( "unistd.h" HAVE_UNISTD_H ) check_required_include( "sys/stat.h" HAVE_SYS_STAT_H ) check_required_include( "limits.h" HAVE_LIMITS_H ) check_required_include( "stdlib.h" HAVE_STDLIB_H ) +CHECK_INCLUDE_FILE( "sys/time.h" HAVE_TIME_H ) +CHECK_INCLUDE_FILE( "sys/resource.h" HAVE_RESOURCE_H ) + +if (${HAVE_TIME_H} AND ${HAVE_RESOURCE_H}) + CHECK_FUNCTION_EXISTS("getrusage" SPECMICP_HAVE_GETRUSAGE) +endif() + CHECK_FUNCTION_EXISTS( "secure_getenv" SPECMICP_HAVE_SECURE_GETENV ) # sanitizer # --------- # to check memory, undefined behavior and all... include(SanitizerBuild) # compilation flags # ============================================================================ # check the availability of : # require C++11 standard by default set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # -fuse-ld=gold include(gold_linker) # pgo optimization include(pg_optimization) # -fvisibility-hidden include(visibility_flag) # just a friendly warning if(NOT UNIX) message(WARNING "Not tested on non linux platform ! Probably won't work") endif() include(lto) # set the flags # ------------- if (OPENMP_FOUND) SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() # let's be pedantic, it's always fun SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -pedantic") # always best to check what we do... message(STATUS "c++ flags : ${CMAKE_CXX_FLAGS}") # Directories ######################################################################### # use gnu coding standards include(GNUInstallDirs) # the libraries install dir set( LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_FULL_LIBDIR} CACHE PATH "Installation directory for libraries" ) # the static libraries install dir set( STATIC_LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_FULL_LIBDIR} CACHE PATH "Installation directory for static libraries" ) # Binaries # -------- set( BIN_INSTALL_DIR ${CMAKE_INSTALL_FULL_BINDIR} CACHE PATH "Installation directory for the programs" ) # include #-------- set( INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_FULL_INCLUDEDIR} CACHE PATH "Installation directory for the headers" ) # share #------ set( SHARE_INSTALL_DIR "${CMAKE_INSTALL_FULL_DATADIR}/specmicp/" CACHE PATH "Installation directory for the miscalleneous files..." ) mark_as_advanced( LIBRARY_INSTALL_DIR STATIC_LIBRARY_INSTALL_DIR BIN_INSTALL_DIR INCLUDE_INSTALL_DIR SHARE_INSTALL_DIR ) # CPP API : SpecMiCP / ReactMiCP ######################################################################### # the main source directory - the c++ api set(SPECMICP_CPP_API ${CMAKE_CURRENT_SOURCE_DIR}/src) include_directories( ${SPECMICP_CPP_API} ) add_subdirectory( ${SPECMICP_CPP_API} ) # the necessary libraries to link to set( SPECMICP_LIBS # just speciation solver specmicp specmicp_database specmicp_common ${YAML_LIBRARIES} ) set( REACTMICP_LIBS # reactive transport solver reactmicp dfpm ${SPECMICP_LIBS} ) # static versions set( SPECMICP_STATIC_LIBS specmicp_static specmicp_database_static specmicp_common_static ${YAML_LIBRARIES} ) set( REACTMICP_STATIC_LIBS reactmicp_static dfpm_static ${SPECMICP_STATIC_LIBS} ) # Databases ######################################################################### add_subdirectory( data ) # Documentation ######################################################################### # "common" documentation # ----------------------- set( DOCS_LIST ${CMAKE_CURRENT_SOURCE_DIR}/README.md ${CMAKE_CURRENT_SOURCE_DIR}/INSTALL ${CMAKE_CURRENT_SOURCE_DIR}/COPYING ) add_custom_target(docs SOURCES ${DOCS_LIST}) install(FILES ${DOCS_LIST} DESTINATION ${SHARE_INSTALL_DIR} ) # scripts # -------- add_subdirectory( scripts ) # Doxygen documentation # --------------------- add_subdirectory( doc ) # Tests ######################################################################### if( SPECMICP_TEST ) enable_testing(true) endif() add_subdirectory( tests ) # Examples ######################################################################### add_subdirectory( examples ) # Benchmark ######################################################################## if (SPECMICP_BENCHMARK) add_subdirectory( benchmark ) endif() # Docker ######################################################################## file(COPY docker/Dockerfile docker/run_tests.sh DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/docker ) diff --git a/src/specmicp_common/config.h.in b/src/specmicp_common/config.h.in index 9501bae..3c3dfae 100644 --- a/src/specmicp_common/config.h.in +++ b/src/specmicp_common/config.h.in @@ -1,47 +1,50 @@ /* ============================================================================= Copyright (c) 2014 - 2016 F. Georget Princeton University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ============================================================================= */ #ifndef SPECMICP_COMMON_CONFIG_H #define SPECMICP_COMMON_CONFIG_H //! \file config.h.in //! \brief Compilation configuration header // defined if has the secure_getenv #cmakedefine SPECMICP_HAVE_SECURE_GETENV +// defined if getrusage is found +#cmakedefine SPECMICP_HAVE_GETRUSAGE + // define if openmp is set #cmakedefine SPECMICP_HAVE_OPENMP #endif // SPECMICP_COMMON_CONFIG_H diff --git a/src/specmicp_common/filesystem.cpp b/src/specmicp_common/filesystem.cpp index d38fd38..82b7b80 100644 --- a/src/specmicp_common/filesystem.cpp +++ b/src/specmicp_common/filesystem.cpp @@ -1,235 +1,260 @@ /* ============================================================================= Copyright (c) 2014 - 2016 F. Georget Princeton University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ============================================================================= */ #include "filesystem.hpp" #include #include #include #include #include #include #include + #include "specmicp_common/config.h" +#ifdef SPECMICP_HAVE_GETRUSAGE +#include +#include +#endif + #include "log.hpp" static std::string test_name; namespace specmicp { namespace utils { bool is_directory(const std::string& path) { struct stat info; if (stat(path.c_str(), &info) == -1) { return false; } if (S_ISDIR(info.st_mode)) { return true; } return false; } bool is_file(const std::string& path) { struct stat info; if (stat(path.c_str(), &info) == -1) { return false; } if (S_ISREG(info.st_mode)) { return true; } return false; } std::string get_current_directory() { char buf[PATH_MAX]; char* test = getcwd(buf, PATH_MAX); if (test == NULL) { ERROR << "Unable to obtain current working directory"; throw std::runtime_error("Something is wrong," "unable to obtain the current directory."); } return std::string(buf); } std::string complete_path( const std::string& dir, const std::string& file ) { std::string complete = dir; if (dir.back() != '/') { complete += '/'; } complete += file; return complete; } std::string relative_to_absolute( const std::string& rel_path, std::string& error ) { std::string abs_path = ""; char buf[PATH_MAX]; // call posix function char* res = realpath(rel_path.c_str(), buf); if (res == NULL) { // parse error if (errno == ENOENT) { error = "No such file '" + rel_path +"'."; } else if (errno == EACCES) { error = "Read permission denied while searching for '" + rel_path +"'."; } else if (errno == EIO) { error = "I/O error while searching for '" + rel_path +"'."; } else { error = "Error while accessing '" + rel_path + "'."; } } else { // no error, copy buffer abs_path = buf; } return abs_path; } int name_filter(const struct dirent64* entry) { auto res = strncmp(entry->d_name, test_name.c_str(), 256); if (res == 0) { return 1; } return 0; } bool is_path_absolute(const std::string& path) { return (path[0] == '/'); } std::string find_path( std::string filename, const std::vector &directories ) { // check if filename is a path const auto has_sep = filename.find('/'); if (has_sep != std::string::npos) { // already a path => we convert it to absolute std::string error = ""; auto filepath = relative_to_absolute(filename, error); if (filepath == "") { ERROR << error; return ""; // empty string is signal for error } return filepath; } // if not a path we try to find it std::string complete_path_str = ""; test_name = filename.c_str(); for (auto dir: directories) { bool found = false; struct dirent64** entry_list; auto count = scandir64(dir.c_str(), &entry_list, name_filter, alphasort64); if (count < 0) { ERROR << "Problem while scanning directory : " << dir << "."; throw std::runtime_error("Problem while scanning directory " + dir + "."); } if (count == 0) { continue; } if (count > 1) { WARNING << "More that one match for file '" << filename << "in : " << dir << "."; } for (auto ind=0; indd_name); } free(entry); // need to free everything } free(entry_list); if (found) break; } return complete_path_str; } bool has_env( const std::string& env_var ) { #ifdef SPECMICP_HAVE_SECURE_GETENV char* env = secure_getenv(env_var.c_str()); #else char* env = getenv(env_var.c_str()); #endif if (env == NULL) { return false; } return true; } std::string get_env( const std::string& env_var ) { #ifdef SPECMICP_HAVE_SECURE_GETENV char* env = secure_getenv(env_var.c_str()); #else char* env = getenv(env_var.c_str()); #endif if (env == NULL) { return ""; } else return env; } + +resource_usage get_resource_usage() +{ + resource_usage resource; +#ifdef SPECMICP_HAVE_GETRUSAGE + struct rusage c_rusage; + auto retcode = getrusage(RUSAGE_SELF, &c_rusage); + if (retcode == -1) { + ERROR << "Error while using getrusage"; + return resource; + } + resource.system_cpu_time = c_rusage.ru_stime.tv_sec + 1e-6*c_rusage.ru_stime.tv_usec; + resource.user_cpu_time = c_rusage.ru_utime.tv_sec + 1e-6*c_rusage.ru_utime.tv_usec; + resource.max_resident_set_size = c_rusage.ru_maxrss; + +#endif + return resource; +} + } // end namespace utils } // end namespace specmicp diff --git a/src/specmicp_common/filesystem.hpp b/src/specmicp_common/filesystem.hpp index f05996a..1b2baaa 100644 --- a/src/specmicp_common/filesystem.hpp +++ b/src/specmicp_common/filesystem.hpp @@ -1,111 +1,124 @@ /* ============================================================================= Copyright (c) 2014 - 2016 F. Georget Princeton University All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ============================================================================= */ #ifndef SPECMICP_UTILS_FILESYSTEM #define SPECMICP_UTILS_FILESYSTEM //! \file filesystem.hpp //! \brief helper functions to deal with the filesystem #include "macros.hpp" #include #include namespace specmicp { namespace utils { //! \brief Check that the directory exist bool SPECMICP_DLL_PUBLIC is_directory(const std::string& path); //! \brief Check that the directory exist bool SPECMICP_DLL_PUBLIC is_file(const std::string& path); //! \brief Return the current directory std::string SPECMICP_DLL_PUBLIC get_current_directory(); //! \brief Complete a path from a given directory and a file //! //! \param dir the directory //! \param file the basename of the file std::string SPECMICP_DLL_PUBLIC complete_path( const std::string& dir, const std::string& file ); //! \brief Return true if the given path is absolute //! //! \param path the path to test bool SPECMICP_DLL_PUBLIC is_path_absolute(const std::string& path); //! \brief Return an absolute path from a relative one //! //! \param[in] rel_path a path //! \param[out] error a string to contain error message if needed //! \return An aboslute path, or an empty string if an error occured //! //! If an error is detected then the return string will be empty, //! and error will contain a message about the error std::string SPECMICP_DLL_PUBLIC relative_to_absolute( const std::string& rel_path, std::string& error ); //! \brief Return the complete path to a file from a set of directories //! //! \param filename basename of the file to seek //! \param directories list of directories where to search the file //! \return an absolute path, or an empty string if the file wasn't found std::string SPECMICP_DLL_PUBLIC find_path( std::string filename, const std::vector& directories ); //! \brief Return true if the environment variable is defined //! //! \param env_var the environment variable to check bool SPECMICP_DLL_PUBLIC has_env( const std::string& env_var ); //! \brief Return an environment variable //! //! \param env_var the environment variable //! \return the value stored in the environment variable, or an empty string std::string SPECMICP_DLL_PUBLIC get_env( const std::string& env_var ); + +//! \brief Struct containing resource usage +struct resource_usage +{ + double system_cpu_time {-1}; //!< The system CPU time + double user_cpu_time {-1}; //!< The user CPU time + long max_resident_set_size {-1}; //!< The maximum size in RAM +}; + +//! \brief Return resource usage information +resource_usage get_resource_usage(); + + } // end namespace utils } // end namespace specmicp #endif // SPECMICP_UTILS_FILESYSTEM