diff --git a/CMakeLists.txt b/CMakeLists.txt index 171715e60..82b72b6f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,6 +105,8 @@ set(LUACLINGO_INSTALL_DIR "" CACHE STRING set(LUACLINGO_SUFFIX CACHE STRING "Advanced variable to manually configure the suffix of the Lua module.") +option(CLINGO_PROFILE "profile clingo" OFF) + mark_as_advanced(CLINGO_BUILD_WEB) mark_as_advanced(CLINGO_BUILD_STATIC) mark_as_advanced(CLINGO_BUILD_SHARED) @@ -115,6 +117,7 @@ mark_as_advanced(PYCLINGO_SUFFIX) mark_as_advanced(PYCLINGO_DYNAMIC_LOOKUP) mark_as_advanced(LUACLINGO_INSTALL_DIR) mark_as_advanced(LUACLINGO_SUFFIX) +mark_as_advanced(CLINGO_PROFILE) # workaround to set custom ar and ranlib if (CLINGO_CMAKE_AR) @@ -240,6 +243,10 @@ if (Python_Development_FOUND) find_package(Threads REQUIRED) endif() +if (CLINGO_PROFILE) + find_package(Gperftools REQUIRED) +endif() + if (POLICY CMP0063 AND (CLINGO_BUILD_SHARED OR Python_Development_FOUND OR LUA_FOUND)) set(CMAKE_CXX_VISIBILITY_PRESET hidden) diff --git a/cmake/FindGperftools.cmake b/cmake/FindGperftools.cmake new file mode 100644 index 000000000..0a27135f6 --- /dev/null +++ b/cmake/FindGperftools.cmake @@ -0,0 +1,76 @@ +# Try to find gperftools +# Once done, this will define +# +# Gperftools_FOUND - system has Profiler +# GPERFTOOLS_INCLUDE_DIR - the Profiler include directories +# Tcmalloc_INCLUDE_DIR - where to find Tcmalloc.h +# GPERFTOOLS_TCMALLOC_LIBRARY - link it to use tcmalloc +# GPERFTOOLS_TCMALLOC_MINIMAL_LIBRARY - link it to use tcmalloc_minimal +# GPERFTOOLS_PROFILER_LIBRARY - link it to use Profiler +# TCMALLOC_VERSION_STRING +# TCMALLOC_VERSION_MAJOR +# TCMALLOC_VERSION_MINOR +# TCMALLOC_VERSION_PATCH + +find_path(GPERFTOOLS_INCLUDE_DIR gperftools/profiler.h + HINTS $ENV{GPERF_ROOT}/include) +find_path(Tcmalloc_INCLUDE_DIR gperftools/tcmalloc.h + HINTS $ENV{GPERF_ROOT}/include) + +if(Tcmalloc_INCLUDE_DIR AND EXISTS "${Tcmalloc_INCLUDE_DIR}/gperftools/tcmalloc.h") + foreach(ver "MAJOR" "MINOR" "PATCH") + file(STRINGS "${Tcmalloc_INCLUDE_DIR}/gperftools/tcmalloc.h" TC_VER_${ver}_LINE + REGEX "^#define[ \t]+TC_VERSION_${ver}[ \t]+[^ \t]+$") + string(REGEX REPLACE "^#define[ \t]+TC_VERSION_${ver}[ \t]+(\".)?([0-9]*)\"?$" + "\\2" TCMALLOC_VERSION_${ver} "${TC_VER_${ver}_LINE}") + unset(TC_VER_${ver}_LINE) + endforeach() + set(TCMALLOC_VERSION_STRING "${TCMALLOC_VERSION_MAJOR}.${TCMALLOC_VERSION_MINOR}") + if(NOT TCMALLOC_VERSION_PATCH STREQUAL "") + set(TCMALLOC_VERSION_STRING "${TCMALLOC_VERSION_STRING}.${TCMALLOC_VERSION_PATCH}") + endif() +endif() + +foreach(component tcmalloc tcmalloc_minimal profiler) + string(TOUPPER ${component} COMPONENT) + find_library(GPERFTOOLS_${COMPONENT}_LIBRARY ${component} + HINTS $ENV{GPERF_ROOT}/lib) + list(APPEND GPERFTOOLS_LIBRARIES GPERFTOOLS_${COMPONENT}_LIBRARY) +endforeach() + +set(_Gperftools_FIND_REQUIRED_VARS "GPERFTOOLS_INCLUDE_DIR") +if(Gperftools_FIND_COMPONENTS) + foreach(component ${Gperftools_FIND_COMPONENTS}) + string(TOUPPER ${component} COMPONENT) + list(APPEND _Gperftools_FIND_REQUIRED_VARS "GPERFTOOLS_${COMPONENT}_LIBRARY") + endforeach() +else() + list(APPEND _Gperftools_FIND_REQUIRED_VARS "GPERFTOOLS_LIBRARIES") +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Gperftools + FOUND_VAR Gperftools_FOUND + REQUIRED_VARS ${_Gperftools_FIND_REQUIRED_VARS} + VERSION_VAR TCMALLOC_VERSION_STRING) + +mark_as_advanced(${GPERFTOOLS_LIBRARIES} GPERFTOOLS_INCLUDE_DIR) + +if(Gperftools_FOUND) + foreach(Component Tcmalloc Tcmalloc_minimal Profiler) + if(NOT (TARGET Gperftools::${Component})) + string(TOUPPER ${Component} COMPONENT) + add_library(Gperftools::${Component} UNKNOWN IMPORTED) + set_target_properties(Gperftools::${Component} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${GPERFTOOLS_INCLUDE_DIR}" + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${GPERFTOOLS_${COMPONENT}_LIBRARY}") + endif() + endforeach() + foreach(Component Tcmalloc Tcmalloc_minimal) + if(NOT (TARGET Gperftools::${Component})) + set_target_properties(Gperftools::${Component} PROPERTIES + INTERFACE_COMPILE_OPTIONS "-fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free") + endif() + endforeach() +endif() diff --git a/libclingo/CMakeLists.txt b/libclingo/CMakeLists.txt index 30d34a8bf..6586066c2 100644 --- a/libclingo/CMakeLists.txt +++ b/libclingo/CMakeLists.txt @@ -102,6 +102,11 @@ if ((CLINGO_BUILD_SHARED OR CLINGO_INSTALL_LIB) AND NOT CLINGO_BUILD_WITH_PYTHON DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Clingo) endif() +if (CLINGO_PROFILE) + target_compile_definitions(libclingo PUBLIC CLINGO_PROFILE) + target_link_libraries(libclingo PUBLIC Gperftools::Profiler) +endif() + if (MSVC) target_compile_definitions(libclingo ${clingo_private_scope_} _SCL_SECURE_NO_WARNINGS) endif() diff --git a/libclingo/src/clingo_app.cc b/libclingo/src/clingo_app.cc index 535aef5b7..ac3d8fc3e 100644 --- a/libclingo/src/clingo_app.cc +++ b/libclingo/src/clingo_app.cc @@ -26,6 +26,10 @@ #include #include +#ifdef CLINGO_PROFILE +#include +#endif + namespace Gringo { // {{{ declaration of ClingoApp @@ -177,6 +181,16 @@ void ClingoApp::onEvent(Clasp::Event const& ev) { BaseType::onEvent(ev); } void ClingoApp::run(Clasp::ClaspFacade& clasp) { +#ifdef CLINGO_PROFILE + struct P { + P() { + ProfilerStart("clingo.solve.prof"); + } + ~P() { + ProfilerStop(); + } + } profile; +#endif try { using namespace std::placeholders; if (mode_ != mode_clasp) { @@ -195,7 +209,9 @@ void ClingoApp::run(Clasp::ClaspFacade& clasp) { std::cerr << e.what() << std::endl; throw std::runtime_error("fatal error"); } - catch (...) { throw; } + catch (...) { + throw; + } } // }}}