diff --git a/.cmake-format.yaml b/.cmake-format.yaml index da61c0e947..6ee48f754e 100644 --- a/.cmake-format.yaml +++ b/.cmake-format.yaml @@ -51,6 +51,7 @@ parse: omnitrace_add_bin_test: flags: - WILL_FAIL + - ADD_INVERSE kwargs: NAME: '*' ARGS: '*' diff --git a/.github/workflows/opensuse.yml b/.github/workflows/opensuse.yml index c4dfd33160..a74390d2aa 100644 --- a/.github/workflows/opensuse.yml +++ b/.github/workflows/opensuse.yml @@ -73,8 +73,8 @@ jobs: timeout-minutes: 45 run: cd build && - ldd ./omnitrace && - ./omnitrace --help && + ldd ./bin/omnitrace && + ./bin/omnitrace --help && ctest -V -N -O omnitrace-ctest-${{ github.job }}-commands.log && ctest -V --output-log omnitrace-ctest-${{ github.job }}.log --stop-on-failure diff --git a/.github/workflows/ubuntu-bionic.yml b/.github/workflows/ubuntu-bionic.yml index 4c69f62f9d..13f8846f31 100644 --- a/.github/workflows/ubuntu-bionic.yml +++ b/.github/workflows/ubuntu-bionic.yml @@ -102,8 +102,8 @@ jobs: timeout-minutes: 45 run: cd build && - ldd ./omnitrace && - ./omnitrace --help && + ldd ./bin/omnitrace && + ./bin/omnitrace --help && ctest -V -N -O omnitrace-ctest-${{ github.job }}-commands.log && ctest -V --output-log omnitrace-ctest-${{ github.job }}.log --stop-on-failure diff --git a/.github/workflows/ubuntu-focal.yml b/.github/workflows/ubuntu-focal.yml index c1500380e5..c0c6a723df 100644 --- a/.github/workflows/ubuntu-focal.yml +++ b/.github/workflows/ubuntu-focal.yml @@ -118,8 +118,8 @@ jobs: timeout-minutes: 45 run: cd build && - ldd ./omnitrace && - ./omnitrace --help && + ldd ./bin/omnitrace && + ./bin/omnitrace --help && ctest -V -N -O omnitrace-ctest-${{ github.job }}-commands.log && ctest -V --output-log omnitrace-ctest-${{ github.job }}.log --stop-on-failure @@ -241,8 +241,8 @@ jobs: timeout-minutes: 45 run: cd build && - ldd ./omnitrace && - ./omnitrace --help && + ldd ./bin/omnitrace && + ./bin/omnitrace --help && ctest -V -N -O omnitrace-ctest-${{ github.job }}-commands.log && ctest -V --output-log omnitrace-ctest-${{ github.job }}.log --stop-on-failure diff --git a/cmake/MacroUtilities.cmake b/cmake/MacroUtilities.cmake index 7596baf6a5..c5aac7c91f 100644 --- a/cmake/MacroUtilities.cmake +++ b/cmake/MacroUtilities.cmake @@ -781,6 +781,39 @@ function(OMNITRACE_FIND_SHARED_LIBRARY) find_library(${ARGN}) endfunction() +function(OMNITRACE_BUILDTREE_TPL _TPL_TARGET _NEW_NAME _BUILD_TREE_DIR) + get_target_property(_TPL_VERSION ${_TPL_TARGET} VERSION) + get_target_property(_TPL_SOVERSION ${_TPL_TARGET} SOVERSION) + get_target_property(_TPL_NAME ${_TPL_TARGET} OUTPUT_NAME) + set(_TPL_PREFIX ${CMAKE_SHARED_LIBRARY_PREFIX}) + set(_TPL_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) + + foreach(_TAIL ${_TPL_SUFFIX} ${_TPL_SUFFIX}.${_TPL_SOVERSION} + ${_TPL_SUFFIX}.${_TPL_VERSION}) + set(_INP ${_TPL_PREFIX}${_TPL_NAME}${_TAIL}) + set(_OUT ${_TPL_PREFIX}${_NEW_NAME}${_TAIL}) + endforeach() + + string(REPLACE " " "-" _TAIL "${ARGN}") + + # build tree symbolic links + add_custom_target( + ${_NEW_NAME}-build-tree-library${_TAIL} ALL + ${CMAKE_COMMAND} -E copy_if_different $ + ${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_VERSION} + COMMAND + ${CMAKE_COMMAND} -E create_symlink + ${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_VERSION} + ${_BUILD_TREE_DIR}/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_SOVERSION} + COMMAND + ${CMAKE_COMMAND} -E create_symlink + ${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_SOVERSION} + ${_BUILD_TREE_DIR}/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX} + WORKING_DIRECTORY ${_BUILD_TREE_DIR} + DEPENDS ${_TPL_TARGET} + COMMENT "Creating ${_NEW_NAME} from ${_TPL_TARGET}...") +endfunction() + function(OMNITRACE_INSTALL_TPL _TPL_TARGET _NEW_NAME _BUILD_TREE_DIR) get_target_property(_TPL_VERSION ${_TPL_TARGET} VERSION) get_target_property(_TPL_SOVERSION ${_TPL_TARGET} SOVERSION) @@ -795,41 +828,17 @@ function(OMNITRACE_INSTALL_TPL _TPL_TARGET _NEW_NAME _BUILD_TREE_DIR) endforeach() # build tree symbolic links - add_custom_target( - ${_NEW_NAME}-library ALL - ${CMAKE_COMMAND} -E copy_if_different $ - ${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_VERSION} - COMMAND - ${CMAKE_COMMAND} -E create_symlink - ${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_VERSION} - ${_BUILD_TREE_DIR}/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_SOVERSION} - COMMAND - ${CMAKE_COMMAND} -E create_symlink - ${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_SOVERSION} - ${_BUILD_TREE_DIR}/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX} - WORKING_DIRECTORY ${_BUILD_TREE_DIR} - DEPENDS ${_TPL_TARGET} - COMMENT "Creating ${_NEW_NAME} from ${_TPL_TARGET}...") + omnitrace_buildtree_tpl("${_TPL_TARGET}" "${_NEW_NAME}" "${_BUILD_TREE_DIR}" ${ARGN}) install( FILES $ DESTINATION ${CMAKE_INSTALL_LIBDIR} RENAME ${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_VERSION}) - execute_process( - COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/install-tree - COMMAND - ${CMAKE_COMMAND} -E create_symlink - ${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_VERSION} - ${PROJECT_BINARY_DIR}/install-tree/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_SOVERSION} - COMMAND - ${CMAKE_COMMAND} -E create_symlink - ${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_SOVERSION} - ${PROJECT_BINARY_DIR}/install-tree/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}) install( FILES - ${PROJECT_BINARY_DIR}/install-tree/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_SOVERSION} - ${PROJECT_BINARY_DIR}/install-tree/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX} + ${_BUILD_TREE_DIR}/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX}.${_TPL_SOVERSION} + ${_BUILD_TREE_DIR}/${_TPL_PREFIX}${_NEW_NAME}${_TPL_SUFFIX} DESTINATION ${CMAKE_INSTALL_LIBDIR}) endfunction() diff --git a/cmake/Modules/FindROCmVersion.cmake b/cmake/Modules/FindROCmVersion.cmake index 76bff6b091..85a46d3a5d 100644 --- a/cmake/Modules/FindROCmVersion.cmake +++ b/cmake/Modules/FindROCmVersion.cmake @@ -217,10 +217,13 @@ function(ROCM_VERSION_PARSE_VERSION_FILES) endif() # convert env to cache if not defined - foreach(_PATH ROCmVersion_DIR ROCmVersion_ROOT ROCmVersion_ROOT_DIR ROCM_PATH) + foreach(_PATH ROCmVersion_DIR ROCmVersion_ROOT ROCmVersion_ROOT_DIR + OMNITRACE_DEFAULT_ROCM_PATH ROCM_PATH) if(NOT DEFINED ${_PATH} AND DEFINED ENV{${_PATH}}) + set(_VAL "$ENV{${_PATH}}") + get_filename_component(_VAL "${_VAL}" REALPATH) set(${_PATH} - "$ENV{${_PATH}}" + "${_VAL}" CACHE PATH "Search path for ROCm version for ROCmVersion") endif() endforeach() @@ -229,8 +232,11 @@ function(ROCM_VERSION_PARSE_VERSION_FILES) set(_PATHS ${ROCmVersion_DIR}) else() set(_PATHS) - foreach(_DIR ${ROCmVersion_DIR} ${ROCmVersion_ROOT} ${ROCmVersion_ROOT_DIR} - $ENV{CMAKE_PREFIX_PATH} ${CMAKE_PREFIX_PATH} ${ROCM_PATH} /opt/rocm) + foreach( + _DIR + ${ROCmVersion_DIR} ${ROCmVersion_ROOT} ${ROCmVersion_ROOT_DIR} + $ENV{CMAKE_PREFIX_PATH} ${CMAKE_PREFIX_PATH} ${OMNITRACE_DEFAULT_ROCM_PATH} + ${ROCM_PATH} /opt/rocm) if(EXISTS ${_DIR}) get_filename_component(_ABS_DIR "${_DIR}" REALPATH) list(APPEND _PATHS ${_ABS_DIR}) diff --git a/cmake/Modules/Findrocm-smi.cmake b/cmake/Modules/Findrocm-smi.cmake index 1136f6f9d5..65076f5cb7 100644 --- a/cmake/Modules/Findrocm-smi.cmake +++ b/cmake/Modules/Findrocm-smi.cmake @@ -9,7 +9,7 @@ if(NOT ROCM_PATH AND NOT "$ENV{ROCM_PATH}" STREQUAL "") set(ROCM_PATH "$ENV{ROCM_PATH}") endif() -foreach(_DIR ${ROCM_PATH} /opt/rocm /opt/rocm/rocm_smi) +foreach(_DIR ${ROCmVersion_DIR} ${ROCM_PATH} /opt/rocm /opt/rocm/rocm_smi) if(EXISTS ${_DIR}) get_filename_component(_ABS_DIR "${_DIR}" REALPATH) list(APPEND _ROCM_SMI_PATHS ${_ABS_DIR}) diff --git a/cmake/Modules/Findrocprofiler.cmake b/cmake/Modules/Findrocprofiler.cmake index c24079f6f7..f62ffafcaa 100644 --- a/cmake/Modules/Findrocprofiler.cmake +++ b/cmake/Modules/Findrocprofiler.cmake @@ -9,7 +9,7 @@ if(NOT ROCM_PATH AND NOT "$ENV{ROCM_PATH}" STREQUAL "") set(ROCM_PATH "$ENV{ROCM_PATH}") endif() -foreach(_DIR ${ROCM_PATH} /opt/rocm /opt/rocm/rocprofiler) +foreach(_DIR ${ROCmVersion_DIR} ${ROCM_PATH} /opt/rocm /opt/rocm/rocprofiler) if(EXISTS ${_DIR}) get_filename_component(_ABS_DIR "${_DIR}" REALPATH) list(APPEND _ROCM_ROCPROFILER_PATHS ${_ABS_DIR}) @@ -48,7 +48,6 @@ find_path( mark_as_advanced(rocprofiler_hsa_INCLUDE_DIR) # ----------------------------------------------------------------------------------------# - find_library( rocprofiler_LIBRARY NAMES rocprofiler64 rocprofiler diff --git a/cmake/Modules/Findroctracer.cmake b/cmake/Modules/Findroctracer.cmake index 8dbebf5682..61cfed55f0 100644 --- a/cmake/Modules/Findroctracer.cmake +++ b/cmake/Modules/Findroctracer.cmake @@ -9,7 +9,7 @@ if(NOT ROCM_PATH AND NOT "$ENV{ROCM_PATH}" STREQUAL "") set(ROCM_PATH "$ENV{ROCM_PATH}") endif() -foreach(_DIR ${ROCM_PATH} /opt/rocm /opt/rocm/roctracer) +foreach(_DIR ${ROCmVersion_DIR} ${ROCM_PATH} /opt/rocm /opt/rocm/roctracer) if(EXISTS ${_DIR}) get_filename_component(_ABS_DIR "${_DIR}" REALPATH) list(APPEND _ROCM_ROCTRACER_PATHS ${_ABS_DIR}) @@ -70,7 +70,8 @@ find_library( PATHS ${roctracer_ROOT_DIR} ${_ROCM_ROCTRACER_PATHS} PATH_SUFFIXES lib lib64) -find_package(hsakmt) +find_package(hsakmt HINTS ${_ROCM_ROCTRACER_PATHS} PATHS ${_ROCM_ROCTRACER_PATHS}) + if(hsakmt_FOUND) set(roctracer_hsakmt_LIBRARY hsakmt::hsakmt diff --git a/cmake/Packages.cmake b/cmake/Packages.cmake index 8041a2830b..de68c1ec32 100644 --- a/cmake/Packages.cmake +++ b/cmake/Packages.cmake @@ -57,8 +57,14 @@ set(OMNITRACE_DEFAULT_ROCM_PATH /opt/rocm CACHE PATH "Default search path for ROCM") if(EXISTS ${OMNITRACE_DEFAULT_ROCM_PATH}) - get_filename_component(OMNITRACE_DEFAULT_ROCM_PATH "${OMNITRACE_DEFAULT_ROCM_PATH}" + get_filename_component(_OMNITRACE_DEFAULT_ROCM_PATH "${OMNITRACE_DEFAULT_ROCM_PATH}" REALPATH) + + if(NOT "${_OMNITRACE_DEFAULT_ROCM_PATH}" STREQUAL "${OMNITRACE_DEFAULT_ROCM_PATH}") + set(OMNITRACE_DEFAULT_ROCM_PATH + "${_OMNITRACE_DEFAULT_ROCM_PATH}" + CACHE PATH "Default search path for ROCM" FORCE) + endif() endif() # ----------------------------------------------------------------------------------------# @@ -93,6 +99,49 @@ foreach(_LIB dl rt) endif() endforeach() +# ----------------------------------------------------------------------------------------# +# +# hip version +# +# ----------------------------------------------------------------------------------------# + +if(OMNITRACE_USE_HIP + OR OMNITRACE_USE_ROCTRACER + OR OMNITRACE_USE_ROCPROFILER + OR OMNITRACE_USE_ROCM_SMI) + find_package(ROCmVersion) + + if(NOT ROCmVersion_FOUND) + find_package(hip ${omnitrace_FIND_QUIETLY} REQUIRED HINTS + ${OMNITRACE_DEFAULT_ROCM_PATH} PATHS ${OMNITRACE_DEFAULT_ROCM_PATH}) + find_package(ROCmVersion REQUIRED HINTS ${ROCM_PATH} PATHS ${ROCM_PATH}) + endif() + + list(APPEND CMAKE_PREFIX_PATH ${ROCmVersion_DIR}) + + set(OMNITRACE_ROCM_VERSION ${ROCmVersion_FULL_VERSION}) + set(OMNITRACE_HIP_VERSION_MAJOR ${ROCmVersion_MAJOR_VERSION}) + set(OMNITRACE_HIP_VERSION_MINOR ${ROCmVersion_MINOR_VERSION}) + set(OMNITRACE_HIP_VERSION_PATCH ${ROCmVersion_PATCH_VERSION}) + set(OMNITRACE_HIP_VERSION ${ROCmVersion_TRIPLE_VERSION}) + + if(OMNITRACE_HIP_VERSION_MAJOR GREATER_EQUAL 4 AND OMNITRACE_HIP_VERSION_MINOR + GREATER 3) + set(roctracer_kfdwrapper_LIBRARY) + endif() + + if(NOT roctracer_kfdwrapper_LIBRARY) + set(roctracer_kfdwrapper_LIBRARY) + endif() + + omnitrace_add_feature(OMNITRACE_ROCM_VERSION "ROCm version used by omnitrace") +else() + set(OMNITRACE_HIP_VERSION "0.0.0") + set(OMNITRACE_HIP_VERSION_MAJOR 0) + set(OMNITRACE_HIP_VERSION_MINOR 0) + set(OMNITRACE_HIP_VERSION_PATCH 0) +endif() + # ----------------------------------------------------------------------------------------# # # HIP @@ -100,7 +149,6 @@ endforeach() # ----------------------------------------------------------------------------------------# if(OMNITRACE_USE_HIP) - list(APPEND CMAKE_PREFIX_PATH ${OMNITRACE_DEFAULT_ROCM_PATH}) find_package(hip ${omnitrace_FIND_QUIETLY} REQUIRED) omnitrace_target_compile_definitions(omnitrace-hip INTERFACE OMNITRACE_USE_HIP) target_link_libraries(omnitrace-hip INTERFACE hip::host) @@ -113,7 +161,6 @@ endif() # ----------------------------------------------------------------------------------------# if(OMNITRACE_USE_ROCTRACER) - list(APPEND CMAKE_PREFIX_PATH ${OMNITRACE_DEFAULT_ROCM_PATH}) find_package(roctracer ${omnitrace_FIND_QUIETLY} REQUIRED) omnitrace_target_compile_definitions(omnitrace-roctracer INTERFACE OMNITRACE_USE_ROCTRACER) @@ -128,7 +175,6 @@ endif() # # ----------------------------------------------------------------------------------------# if(OMNITRACE_USE_ROCPROFILER) - list(APPEND CMAKE_PREFIX_PATH ${OMNITRACE_DEFAULT_ROCM_PATH}) find_package(rocprofiler ${omnitrace_FIND_QUIETLY} REQUIRED) omnitrace_target_compile_definitions(omnitrace-rocprofiler INTERFACE OMNITRACE_USE_ROCPROFILER) @@ -143,7 +189,6 @@ endif() # ----------------------------------------------------------------------------------------# if(OMNITRACE_USE_ROCM_SMI) - list(APPEND CMAKE_PREFIX_PATH ${OMNITRACE_DEFAULT_ROCM_PATH}) find_package(rocm-smi ${omnitrace_FIND_QUIETLY} REQUIRED) omnitrace_target_compile_definitions(omnitrace-rocm-smi INTERFACE OMNITRACE_USE_ROCM_SMI) @@ -151,36 +196,6 @@ if(OMNITRACE_USE_ROCM_SMI) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:${rocm-smi_LIBRARY_DIRS}") endif() -# ----------------------------------------------------------------------------------------# -# -# hip version -# -# ----------------------------------------------------------------------------------------# - -if(OMNITRACE_USE_HIP - OR OMNITRACE_USE_ROCTRACER - OR OMNITRACE_USE_ROCM_SMI) - find_package(ROCmVersion REQUIRED) - set(OMNITRACE_ROCM_VERSION ${ROCmVersion_FULL_VERSION}) - set(OMNITRACE_HIP_VERSION_MAJOR ${ROCmVersion_MAJOR_VERSION}) - set(OMNITRACE_HIP_VERSION_MINOR ${ROCmVersion_MINOR_VERSION}) - set(OMNITRACE_HIP_VERSION_PATCH ${ROCmVersion_PATCH_VERSION}) - set(OMNITRACE_HIP_VERSION ${ROCmVersion_TRIPLE_VERSION}) - if(OMNITRACE_HIP_VERSION_MAJOR GREATER_EQUAL 4 AND OMNITRACE_HIP_VERSION_MINOR - GREATER 3) - set(roctracer_kfdwrapper_LIBRARY) - endif() - if(NOT roctracer_kfdwrapper_LIBRARY) - set(roctracer_kfdwrapper_LIBRARY) - endif() - omnitrace_add_feature(OMNITRACE_ROCM_VERSION "ROCm version used by omnitrace") -else() - set(OMNITRACE_HIP_VERSION "0.0.0") - set(OMNITRACE_HIP_VERSION_MAJOR 0) - set(OMNITRACE_HIP_VERSION_MINOR 0) - set(OMNITRACE_HIP_VERSION_PATCH 0) -endif() - # ----------------------------------------------------------------------------------------# # # MPI @@ -276,7 +291,8 @@ if(OMNITRACE_BUILD_DYNINST) endif() endforeach() - omnitrace_install_tpl(dyninstAPI_RT omnitrace-rt "${PROJECT_BINARY_DIR}") + omnitrace_install_tpl(dyninstAPI_RT omnitrace-rt + "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}") # for packaging install( diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 057a4fdaa7..7fb9169bb3 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -12,8 +12,8 @@ option(BUILD_SHARED_LIBS "Build dynamic libraries" ON) if(CMAKE_PROJECT_NAME STREQUAL "omnitrace") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) omnitrace_add_option(OMNITRACE_INSTALL_EXAMPLES "Install omnitrace examples" OFF) else() option(OMNITRACE_INSTALL_EXAMPLES "Install omnitrace examples" ON) diff --git a/examples/lulesh/CMakeLists.txt b/examples/lulesh/CMakeLists.txt index df4b2fa0c9..81150a1b96 100644 --- a/examples/lulesh/CMakeLists.txt +++ b/examples/lulesh/CMakeLists.txt @@ -13,13 +13,13 @@ if(LULESH_BUILD_KOKKOS) kokkos_compilation(PROJECT) elseif(LULESH_USE_HIP AND NOT "${CMAKE_CXX_COMPILER}" MATCHES "hipcc") if(NOT HIPCC_EXECUTABLE) - find_package(hip QUIET) + find_package(hip QUIET HINTS ${ROCmVersion_DIR} PATHS ${ROCmVersion_DIR}) find_program( HIPCC_EXECUTABLE NAMES hipcc - HINTS ${ROCM_PATH} ENV ROCM_PATH /opt/rocm - PATHS ${ROCM_PATH} ENV ROCM_PATH /opt/rocm) + HINTS ${ROCmVersion_DIR} ${ROCM_PATH} ENV ROCM_PATH /opt/rocm + PATHS ${ROCmVersion_DIR} ${ROCM_PATH} ENV ROCM_PATH /opt/rocm) mark_as_advanced(HIPCC_EXECUTABLE) endif() kokkos_compilation(PROJECT COMPILER ${HIPCC_EXECUTABLE}) diff --git a/examples/transpose/CMakeLists.txt b/examples/transpose/CMakeLists.txt index b8b16b1d57..72962cecb4 100644 --- a/examples/transpose/CMakeLists.txt +++ b/examples/transpose/CMakeLists.txt @@ -2,13 +2,13 @@ cmake_minimum_required(VERSION 3.16 FATAL_ERROR) project(omnitrace-transpose LANGUAGES CXX) -find_package(hip QUIET) +find_package(hip QUIET HINTS ${ROCmVersion_DIR} PATHS ${ROCmVersion_DIR}) find_program( HIPCC_EXECUTABLE NAMES hipcc - HINTS ${ROCM_PATH} ENV ROCM_PATH /opt/rocm - PATHS ${ROCM_PATH} ENV ROCM_PATH /opt/rocm) + HINTS ${ROCmVersion_DIR} ${ROCM_PATH} ENV ROCM_PATH /opt/rocm + PATHS ${ROCmVersion_DIR} ${ROCM_PATH} ENV ROCM_PATH /opt/rocm NO_CACHE) mark_as_advanced(HIPCC_EXECUTABLE) if(NOT HIPCC_EXECUTABLE) diff --git a/examples/transpose/transpose.cpp b/examples/transpose/transpose.cpp index 3ca092603e..97c0f040a0 100644 --- a/examples/transpose/transpose.cpp +++ b/examples/transpose/transpose.cpp @@ -32,6 +32,7 @@ THE SOFTWARE. #include #include #include +#include #include #include @@ -46,7 +47,7 @@ using auto_lock_t = std::unique_lock; auto_lock_t _lk{ print_lock }; \ fprintf(stderr, "%s:%d :: HIP error : %s\n", __FILE__, __LINE__, \ hipGetErrorString(error_)); \ - exit(EXIT_FAILURE); \ + throw std::runtime_error("hip_api_call"); \ } \ } @@ -58,7 +59,7 @@ check_hip_error(void) { auto_lock_t _lk{ print_lock }; std::cerr << "Error: " << hipGetErrorString(err) << std::endl; - exit(err); + throw std::runtime_error("hip_api_call"); } } diff --git a/external/timemory b/external/timemory index 1c03bec283..127a235bc3 160000 --- a/external/timemory +++ b/external/timemory @@ -1 +1 @@ -Subproject commit 1c03bec2837823a3d574b83a688a2f61b515d862 +Subproject commit 127a235bc3f5f5f9e414a7001d6413c2e800d317 diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 84eb12cdda..b93a14d8c0 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -6,9 +6,9 @@ if(OMNITRACE_BUILD_LTO) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) endif() -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}) add_subdirectory(lib) add_subdirectory(bin) diff --git a/source/bin/omnitrace/details.cpp b/source/bin/omnitrace/details.cpp index 669203c585..a6c9fbd260 100644 --- a/source/bin/omnitrace/details.cpp +++ b/source/bin/omnitrace/details.cpp @@ -24,6 +24,9 @@ #include "fwd.hpp" #include "omnitrace.hpp" +#include +#include + static int expect_error = NO_ERROR; static int error_print = 0; @@ -513,6 +516,49 @@ get_whole_function_names() #endif } +//======================================================================================// +// +// Helper functions because the syntax for getting a function or module name is unwieldy +// +std::string_view +get_name(procedure_t* _func) +{ + static auto _v = std::unordered_map{}; + + auto itr = _v.find(_func); + if(itr == _v.end()) + { + _v.emplace(_func, (_func) ? _func->getDemangledName() : std::string{}); + } + + return _v.at(_func); +} + +std::string_view +get_name(module_t* _module) +{ + static auto _v = std::unordered_map{}; + + auto itr = _v.find(_module); + if(itr == _v.end()) + { + char _name[FUNCNAMELEN + 1]; + memset(_name, '\0', FUNCNAMELEN + 1); + + if(_module) + { + _module->getFullName(_name, FUNCNAMELEN); + _v.emplace(_module, std::string{ _name }); + } + else + { + _v.emplace(nullptr, std::string{}); + } + } + + return _v.at(_module); +} + //======================================================================================// // // For selective instrumentation (unused) @@ -523,6 +569,69 @@ are_file_include_exclude_lists_empty() return true; } +namespace +{ +std::string +get_return_type(procedure_t* func) +{ + if(func && func->isInstrumentable() && func->getReturnType()) + return func->getReturnType()->getName(); + return std::string{}; +} + +auto +get_parameter_types(procedure_t* func) +{ + auto _param_names = std::vector{}; + if(func && func->isInstrumentable()) + { + auto* _params = func->getParams(); + if(_params) + { + _param_names.reserve(_params->size()); + for(auto* itr : *_params) + { + std::string _name = itr->getType()->getName(); + if(_name.empty()) _name = itr->getName(); + _param_names.emplace_back(_name); + } + } + } + return _param_names; +} +} // namespace + +//======================================================================================// +// +// We create a new name that embeds the file and line information in the name +// +function_signature +get_func_file_line_info(module_t* module, procedure_t* func) +{ + using address_t = Dyninst::Address; + + auto _file_name = get_name(module); + auto _func_name = get_name(func); + auto _return_type = get_return_type(func); + auto _param_types = get_parameter_types(func); + auto _base_addr = address_t{}; + auto _last_addr = address_t{}; + auto _src_lines = std::vector{}; + + if(func->getAddressRange(_base_addr, _last_addr) && + module->getSourceLines(_base_addr, _src_lines) && !_src_lines.empty()) + { + auto _row = _src_lines.front().lineNumber(); + return function_signature(_return_type, _func_name, _file_name, _param_types, + { _row, 0 }, { 0, 0 }, false, true, false); + } + else + { + return function_signature(_return_type, _func_name, _file_name, _param_types, + { 0, 0 }, { 0, 0 }, false, false, false); + } +} + //======================================================================================// // // Gets information (line number, filename, and column number) about @@ -532,173 +641,84 @@ function_signature get_loop_file_line_info(module_t* module, procedure_t* func, flow_graph_t*, basic_loop_t* loopToInstrument) { - std::vector basic_blocks{}; + auto basic_blocks = std::vector{}; loopToInstrument->getLoopBasicBlocksExclusive(basic_blocks); if(basic_blocks.empty()) return function_signature{ "", "", "" }; - auto base_addr = basic_blocks.front()->getStartAddress(); - auto last_addr = basic_blocks.front()->getEndAddress(); - basic_block_t* block = basic_blocks.front(); + auto* _block = basic_blocks.front(); + auto _base_addr = _block->getStartAddress(); + auto _last_addr = _block->getEndAddress(); for(const auto& itr : basic_blocks) { - if(itr == block) continue; - if(itr->dominates(block)) + if(itr == _block) continue; + if(itr->dominates(_block)) { - base_addr = itr->getStartAddress(); - last_addr = itr->getEndAddress(); - block = itr; + _base_addr = itr->getStartAddress(); + _last_addr = itr->getEndAddress(); + _block = itr; } } - verbprintf(4, "Loop: size = %lu: base_addr = %lu, last_addr = %lu\n", - (unsigned long) (last_addr - base_addr), base_addr, last_addr); + auto _file_name = get_name(module); + auto _func_name = get_name(func); + auto _return_type = get_return_type(func); + auto _param_types = get_parameter_types(func); + auto _lines_beg = std::vector{}; + auto _lines_end = std::vector{}; - char fname[FUNCNAMELEN + 1]; - char mname[FUNCNAMELEN + 1]; - std::string typeName = {}; - - memset(fname, '\0', FUNCNAMELEN + 1); - memset(mname, '\0', FUNCNAMELEN + 1); - - module->getFullName(mname, FUNCNAMELEN); - func->getName(fname, FUNCNAMELEN); - - auto* returnType = func->getReturnType(); - - if(returnType) typeName = returnType->getName(); - - auto* params = func->getParams(); - std::vector _params; - if(params) - { - for(auto* itr : *params) - { - string_t _name = itr->getType()->getName(); - if(_name.empty()) _name = itr->getName(); - _params.push_back(_name); - } - } - - bpvector_t lines{}; - bpvector_t linesEnd{}; - - bool info1 = module->getSourceLines(base_addr, lines); - - string_t filename = mname; - - if(info1) + if(module->getSourceLines(_base_addr, _lines_beg)) { // filename = lines[0].fileName(); - int row1 = 0; - int col1 = 0; - for(auto& itr : lines) + int _row1 = 0; + int _col1 = 0; + for(auto& itr : _lines_beg) { if(itr.lineNumber() > 0) { - row1 = itr.lineNumber(); - col1 = itr.lineOffset(); + _row1 = itr.lineNumber(); + _col1 = itr.lineOffset(); break; } } - if(row1 == 0 && col1 == 0) - return function_signature(typeName, fname, filename, _params); + if(_row1 == 0 && _col1 == 0) + return function_signature(_return_type, _func_name, _file_name, _param_types); - int row2 = 0; - int col2 = 0; - for(auto& itr : lines) + int _row2 = 0; + int _col2 = 0; + for(auto& itr : _lines_beg) { - row2 = std::max(row2, itr.lineNumber()); - col2 = std::max(col2, itr.lineOffset()); + _row2 = std::max(_row2, itr.lineNumber()); + _col2 = std::max(_col2, itr.lineOffset()); } - if(col1 < 0) col1 = 0; + if(_col1 < 0) _col1 = 0; - bool info2 = module->getSourceLines(last_addr, linesEnd); - verbprintf(4, "size of linesEnd = %lu\n", (unsigned long) linesEnd.size()); - - if(info2) + if(module->getSourceLines(_last_addr, _lines_end)) { - for(auto& itr : linesEnd) + for(auto& itr : _lines_end) { - row2 = std::max(row2, itr.lineNumber()); - col2 = std::max(col2, itr.lineOffset()); + _row2 = std::max(_row2, itr.lineNumber()); + _col2 = std::max(_col2, itr.lineOffset()); } - if(col2 < 0) col2 = 0; - if(row2 < row1) row1 = row2; // Fix for wrong line numbers + if(_col2 < 0) _col2 = 0; + if(_row2 < _row1) _row1 = _row2; // Fix for wrong line numbers - return function_signature(typeName, fname, filename, _params, { row1, row2 }, - { col1, col2 }, true, info1, info2); + return function_signature(_return_type, _func_name, _file_name, _param_types, + { _row1, _row2 }, { _col1, _col2 }, true, true, + true); } else { - return function_signature(typeName, fname, filename, _params, { row1, 0 }, - { col1, 0 }, true, info1, info2); + return function_signature(_return_type, _func_name, _file_name, _param_types, + { _row1, 0 }, { _col1, 0 }, true, true, false); } } else { - return function_signature(typeName, fname, filename, _params, { 0, 0 }, { 0, 0 }, - true, false, false); - } -} - -//======================================================================================// -// -// We create a new name that embeds the file and line information in the name -// -function_signature -get_func_file_line_info(module_t* module, procedure_t* func) -{ - using address_t = Dyninst::Address; - - char fname[FUNCNAMELEN + 1]; - char mname[FUNCNAMELEN + 1]; - string_t typeName = {}; - - memset(fname, '\0', FUNCNAMELEN + 1); - memset(mname, '\0', FUNCNAMELEN + 1); - - module->getFullName(mname, FUNCNAMELEN); - func->getName(fname, FUNCNAMELEN); - - address_t base_addr{}; - address_t last_addr{}; - func->getAddressRange(base_addr, last_addr); - - auto* returnType = func->getReturnType(); - - if(returnType) typeName = returnType->getName(); - - auto* params = func->getParams(); - std::vector _params = {}; - if(params) - { - _params.reserve(params->size()); - for(auto* itr : *params) - { - string_t _name = itr->getType()->getName(); - if(_name.empty()) _name = itr->getName(); - _params.emplace_back(_name); - } - } - - bpvector_t lines = {}; - bool info = module->getSourceLines(base_addr, lines); - - string_t filename = mname; - - if(info && !lines.empty()) - { - auto row = lines.front().lineNumber(); - return function_signature(typeName, fname, filename, _params, { row, 0 }, - { 0, 0 }, false, info, false); - } - else - { - return function_signature(typeName, fname, filename, _params, { 0, 0 }, { 0, 0 }, - false, false, false); + return function_signature(_return_type, _func_name, _file_name, _param_types, + { 0, 0 }, { 0, 0 }, true, false, false); } } @@ -713,89 +733,69 @@ get_basic_block_file_line_info(module_t* module, procedure_t* func) std::map _data{}; if(!func) return _data; - auto* _cfg = func->getCFG(); - std::set _basic_blocks{}; + auto* _cfg = func->getCFG(); + auto _basic_blocks = std::set{}; _cfg->getAllBasicBlocks(_basic_blocks); if(_basic_blocks.empty()) return _data; - char fname[FUNCNAMELEN + 1]; - char mname[FUNCNAMELEN + 1]; - std::string typeName = {}; - - memset(fname, '\0', FUNCNAMELEN + 1); - memset(mname, '\0', FUNCNAMELEN + 1); - - module->getFullName(mname, FUNCNAMELEN); - func->getName(fname, FUNCNAMELEN); - - auto* returnType = func->getReturnType(); - - if(returnType) typeName = returnType->getName(); - - auto* params = func->getParams(); - std::vector _params; - if(params) - { - for(auto* itr : *params) - { - string_t _name = itr->getType()->getName(); - if(_name.empty()) _name = itr->getName(); - _params.push_back(_name); - } - } + auto _file_name = get_name(module); + auto _func_name = get_name(func); + auto _return_type = get_return_type(func); + auto _param_types = get_parameter_types(func); for(auto&& itr : _basic_blocks) { - auto base_addr = itr->getStartAddress(); - auto last_addr = itr->getEndAddress(); + auto _base_addr = itr->getStartAddress(); + auto _last_addr = itr->getEndAddress(); - verbprintf(4, "BB: size = %lu: base_addr = %lu, last_addr = %lu\n", - (unsigned long) (last_addr - base_addr), base_addr, last_addr); + verbprintf(4, + "[%s][%s] basic_block: size = %lu: base_addr = %lu, last_addr = %lu\n", + _file_name.data(), _func_name.data(), + (unsigned long) (_last_addr - _base_addr), _base_addr, _last_addr); - bpvector_t linesBeg{}; - bpvector_t linesEnd{}; + auto _lines_beg = std::vector{}; + auto _lines_end = std::vector{}; - string_t filename = mname; - - if(module->getSourceLines(base_addr, linesBeg) && !linesBeg.empty()) + if(module->getSourceLines(_base_addr, _lines_beg) && !_lines_beg.empty()) { - int row1 = linesBeg.front().lineNumber(); - int col1 = linesBeg.front().lineOffset(); + int _row1 = _lines_beg.front().lineNumber(); + int _col1 = _lines_beg.front().lineOffset(); - verbprintf(4, "size of linesEnd = %lu\n", (unsigned long) linesEnd.size()); + verbprintf(4, "size of _lines_end = %lu\n", + (unsigned long) _lines_end.size()); - if(module->getSourceLines(last_addr, linesEnd) && !linesEnd.empty()) + if(module->getSourceLines(_last_addr, _lines_end) && !_lines_end.empty()) { - int row2 = linesEnd.back().lineNumber(); - int col2 = linesEnd.back().lineOffset(); + int _row2 = _lines_end.back().lineNumber(); + int _col2 = _lines_end.back().lineOffset(); - if(row2 < row1) std::swap(row1, row2); - if(row1 == row2 && col2 < col1) std::swap(col1, col2); + if(_row2 < _row1) std::swap(_row1, _row2); + if(_row1 == _row2 && _col2 < _col1) std::swap(_col1, _col2); - _data.emplace(itr, - basic_block_signature{ - base_addr, last_addr, - function_signature(typeName, fname, filename, _params, - { row1, row2 }, { col1, col2 }, true, - true, true) }); + _data.emplace( + itr, basic_block_signature{ + _base_addr, _last_addr, + function_signature(_return_type, _func_name, _file_name, + _param_types, { _row1, _row2 }, + { _col1, _col2 }, true, true, true) }); } else { _data.emplace(itr, basic_block_signature{ - base_addr, last_addr, - function_signature(typeName, fname, filename, _params, - { row1, 0 }, { col1, 0 }, true, true, - false) }); + _base_addr, _last_addr, + function_signature(_return_type, _func_name, _file_name, + _param_types, { _row1, 0 }, + { _col1, 0 }, true, true, false) }); } } else { - _data.emplace(itr, - basic_block_signature{ - base_addr, last_addr, - function_signature(typeName, fname, filename, _params) }); + _data.emplace(itr, basic_block_signature{ + _base_addr, _last_addr, + function_signature(_return_type, _func_name, + _file_name, _param_types) }); } } @@ -861,7 +861,7 @@ find_function(image_t* app_image, const std::string& _name, const strset_t& _ext { if(_name.empty()) return nullptr; - auto _find = [app_image](const string_t& _f) -> procedure_t* { + auto _find = [app_image](const std::string& _f) -> procedure_t* { // Extract the vector of functions bpvector_t _found; auto* ret = app_image->findFunction(_f.c_str(), _found, false, true, true); diff --git a/source/bin/omnitrace/function_signature.cpp b/source/bin/omnitrace/function_signature.cpp index 0d535c33e4..ed28118549 100644 --- a/source/bin/omnitrace/function_signature.cpp +++ b/source/bin/omnitrace/function_signature.cpp @@ -22,25 +22,26 @@ #include "function_signature.hpp" -function_signature::function_signature(string_t _ret, const string_t& _name, - string_t _file, location_t _row, location_t _col, - bool _loop, bool _info_beg, bool _info_end) +function_signature::function_signature(std::string_view _ret, std::string_view _name, + std::string_view _file, location_t _row, + location_t _col, bool _loop, bool _info_beg, + bool _info_end) : m_loop(_loop) , m_info_beg(_info_beg) , m_info_end(_info_end) , m_row(std::move(_row)) , m_col(std::move(_col)) -, m_return(std::move(_ret)) -, m_name(tim::demangle(_name)) -, m_file(std::move(_file)) +, m_return(_ret) +, m_name(tim::demangle(_name.data())) +, m_file(_file) { - if(m_file.find('/') != string_t::npos) + if(m_file.find('/') != std::string_view::npos) m_file = m_file.substr(m_file.find_last_of('/') + 1); } -function_signature::function_signature(const string_t& _ret, const string_t& _name, - const string_t& _file, - const std::vector& _params, +function_signature::function_signature(std::string_view _ret, std::string_view _name, + std::string_view _file, + const std::vector& _params, location_t _row, location_t _col, bool _loop, bool _info_beg, bool _info_end) : function_signature(_ret, _name, _file, _row, _col, _loop, _info_beg, _info_end) @@ -52,13 +53,13 @@ function_signature::function_signature(const string_t& _ret, const string_t& _na m_params += ")"; } -string_t +std::string function_signature::get(function_signature& sig) { return sig.get(); } -string_t +std::string function_signature::get(bool _all, bool _save) const { if(!_all && _save && !m_signature.empty()) return m_signature; @@ -103,7 +104,7 @@ function_signature::get(bool _all, bool _save) const return ss.str(); } -string_t +std::string function_signature::get_coverage(bool _basic_block) const { std::stringstream ss; diff --git a/source/bin/omnitrace/function_signature.hpp b/source/bin/omnitrace/function_signature.hpp index e0fe4cd4ee..ac8edca3a7 100644 --- a/source/bin/omnitrace/function_signature.hpp +++ b/source/bin/omnitrace/function_signature.hpp @@ -24,49 +24,65 @@ #include "fwd.hpp" +#include + struct function_signature { using location_t = std::pair; TIMEMORY_DEFAULT_OBJECT(function_signature) - function_signature(string_t _ret, const string_t& _name, string_t _file, + function_signature(std::string_view _ret, std::string_view _name, + std::string_view _file, location_t _row = { 0, 0 }, + location_t _col = { 0, 0 }, bool _loop = false, + bool _info_beg = false, bool _info_end = false); + + function_signature(std::string_view _ret, std::string_view _name, + std::string_view _file, const std::vector& _params, location_t _row = { 0, 0 }, location_t _col = { 0, 0 }, bool _loop = false, bool _info_beg = false, bool _info_end = false); - function_signature(const string_t& _ret, const string_t& _name, const string_t& _file, - const std::vector& _params, location_t _row = { 0, 0 }, - location_t _col = { 0, 0 }, bool _loop = false, - bool _info_beg = false, bool _info_end = false); - function_signature& set_loop_number(uint32_t _n) { m_loop_num = _n; return *this; } - static string_t get(function_signature& sig); - string_t get(bool _all = false, bool _save = true) const; - string_t get_coverage(bool _is_basic_block) const; + static std::string get(function_signature& sig); + std::string get(bool _all = false, bool _save = true) const; + std::string get_coverage(bool _is_basic_block) const; - bool m_loop = false; - bool m_info_beg = false; - bool m_info_end = false; - uint32_t m_loop_num = std::numeric_limits::max(); - location_t m_row = { 0, 0 }; - location_t m_col = { 0, 0 }; - string_t m_return = {}; - string_t m_name = {}; - string_t m_params = "()"; - string_t m_file = {}; - mutable string_t m_signature = {}; + bool m_loop = false; + bool m_info_beg = false; + bool m_info_end = false; + uint32_t m_loop_num = std::numeric_limits::max(); + location_t m_row = { 0, 0 }; + location_t m_col = { 0, 0 }; + std::string m_return = {}; + std::string m_name = {}; + std::string m_params = "()"; + std::string m_file = {}; + mutable std::string m_signature = {}; friend bool operator==(const function_signature& lhs, const function_signature& rhs) { return lhs.get() == rhs.get(); } + friend bool operator<(const function_signature& lhs, const function_signature& rhs) + { + const auto loop_max = std::numeric_limits::max(); + if(lhs.m_loop && !rhs.m_loop) return false; + if(!lhs.m_loop && rhs.m_loop) return true; + if(lhs.m_loop_num < loop_max && rhs.m_loop_num == loop_max) return false; + if(lhs.m_loop_num == loop_max && rhs.m_loop_num < loop_max) return true; + return std::tie(lhs.m_file, lhs.m_name, lhs.m_return, lhs.m_params, + lhs.m_row.first, lhs.m_col.first, lhs.m_loop_num) < + std::tie(rhs.m_file, rhs.m_name, rhs.m_return, rhs.m_params, + rhs.m_row.first, rhs.m_col.first, rhs.m_loop_num); + } + template void serialize(ArchiveT& _ar, const unsigned) { diff --git a/source/bin/omnitrace/fwd.hpp b/source/bin/omnitrace/fwd.hpp index 61921a2d9d..a33b32ab13 100644 --- a/source/bin/omnitrace/fwd.hpp +++ b/source/bin/omnitrace/fwd.hpp @@ -42,11 +42,14 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include #include @@ -66,6 +69,7 @@ #include #include #include +#include #include #define MUTNAMELEN 1024 @@ -111,9 +115,12 @@ using basic_block_t = BPatch_basicBlock; using basic_loop_t = BPatch_basicBlockLoop; using procedure_loc_t = BPatch_procedureLocation; using point_t = BPatch_point; +using object_t = BPatch_object; using local_var_t = BPatch_localVar; +using sequence_t = BPatch_sequence; using const_expr_t = BPatch_constExpr; using error_level_t = BPatchErrorLevel; +using snippet_handle_t = BPatchSnippetHandle; using patch_pointer_t = std::shared_ptr; using snippet_pointer_t = std::shared_ptr; using call_expr_pointer_t = std::shared_ptr; @@ -166,6 +173,11 @@ extern bool debug_print; extern bool instr_print; extern int verbose_level; // +// instrumentation settings +// +extern bool simulate; +extern bool include_uninstr; +// // string settings // extern string_t main_fname; @@ -297,3 +309,9 @@ error_func_real(error_level_t level, int num, const char* const* params); void error_func_fake(error_level_t level, int num, const char* const* params); + +std::string_view +get_name(procedure_t* _module); + +std::string_view +get_name(module_t* _module); diff --git a/source/bin/omnitrace/module_function.cpp b/source/bin/omnitrace/module_function.cpp index d99914ea97..9e647956e2 100644 --- a/source/bin/omnitrace/module_function.cpp +++ b/source/bin/omnitrace/module_function.cpp @@ -55,44 +55,48 @@ module_function::module_function(module_t* mod, procedure_t* proc) : module{ mod } , function{ proc } , flow_graph{ proc->getCFG() } +, module_name{ get_name(module) } +, function_name{ get_name(function) } { - if(flow_graph) - { - flow_graph->getAllBasicBlocks(basic_blocks); - flow_graph->getOuterLoops(loop_blocks); - } - - instructions.reserve(basic_blocks.size()); - for(const auto& itr : basic_blocks) - { - std::vector _instructions{}; - itr->getInstructions(_instructions); - num_instructions += _instructions.size(); - if(debug_print || verbose_level > 3 || instr_print) - instructions.emplace_back(std::move(_instructions)); - } - - char modname[FUNCNAMELEN]; - char fname[FUNCNAMELEN]; - module->getFullName(modname, FUNCNAMELEN); - function->getName(fname, FUNCNAMELEN); - module_name = modname; - function_name = fname; - signature = get_func_file_line_info(module, function); - if(!function->isInstrumentable()) { - verbprintf(0, + verbprintf(1, "Warning! module function generated for un-instrumentable " "function: %s [%s]\n", function_name.c_str(), module_name.c_str()); } - std::pair _range{}; + + auto _range = std::pair{}; if(function->getAddressRange(_range.first, _range.second)) { start_address = _range.first; address_range = _range.second - _range.first; } + + signature = get_func_file_line_info(module, function); + + if(function->isInstrumentable()) + { + // this information is potentially not available and + // appears to be the cause of a segfault in testing + // so only attempt to extract it for instrumentable + // functions + if(flow_graph) + { + flow_graph->getAllBasicBlocks(basic_blocks); + flow_graph->getOuterLoops(loop_blocks); + } + + instructions.reserve(basic_blocks.size()); + for(const auto& itr : basic_blocks) + { + std::vector _instructions{}; + itr->getInstructions(_instructions); + num_instructions += _instructions.size(); + if(debug_print || verbose_level > 3 || instr_print) + instructions.emplace_back(std::move(_instructions)); + } + } } void diff --git a/source/bin/omnitrace/module_function.hpp b/source/bin/omnitrace/module_function.hpp index b15ec80723..4ced5b7684 100644 --- a/source/bin/omnitrace/module_function.hpp +++ b/source/bin/omnitrace/module_function.hpp @@ -30,6 +30,7 @@ #include #include +#include struct module_function { @@ -117,19 +118,18 @@ public: friend bool operator<(const module_function& lhs, const module_function& rhs) { - return (lhs.module_name == rhs.module_name) - ? ((lhs.function_name == rhs.function_name) - ? (lhs.signature.get() < rhs.signature.get()) - : (lhs.function_name < rhs.function_name)) - : (lhs.module_name < rhs.module_name); + return std::tie(lhs.module_name, lhs.start_address, lhs.function_name, + lhs.address_range, lhs.num_instructions, lhs.signature) < + std::tie(rhs.module_name, rhs.start_address, rhs.function_name, + rhs.address_range, rhs.num_instructions, rhs.signature); } friend bool operator==(const module_function& lhs, const module_function& rhs) { - return std::tie(lhs.module_name, lhs.function_name, lhs.signature, - lhs.address_range, lhs.num_instructions) == - std::tie(rhs.module_name, rhs.function_name, rhs.signature, - rhs.address_range, rhs.num_instructions); + return std::tie(lhs.module_name, lhs.start_address, lhs.function_name, + lhs.address_range, lhs.num_instructions, lhs.signature) == + std::tie(rhs.module_name, rhs.start_address, rhs.function_name, + rhs.address_range, rhs.num_instructions, rhs.signature); } friend std::ostream& operator<<(std::ostream& os, const module_function& rhs) diff --git a/source/bin/omnitrace/omnitrace.cpp b/source/bin/omnitrace/omnitrace.cpp index 86991f127e..962210a6d5 100644 --- a/source/bin/omnitrace/omnitrace.cpp +++ b/source/bin/omnitrace/omnitrace.cpp @@ -23,19 +23,23 @@ #include "omnitrace.hpp" #include "fwd.hpp" -#include -#include #include #include #include #include +#include +#include #include #include #include +#include #include #include #include +#include +#include +#include #include #include #include @@ -43,6 +47,7 @@ #include #include #include +#include #include #include @@ -70,6 +75,8 @@ size_t min_loop_instructions = (1 << 6); // 64 bool werror = false; bool debug_print = false; bool instr_print = false; +bool simulate = false; +bool include_uninstr = false; int verbose_level = tim::get_env("OMNITRACE_VERBOSE_INSTRUMENT", 0); string_t main_fname = "main"; string_t argv0 = {}; @@ -103,8 +110,8 @@ bool binary_rewrite = false; bool is_attached = false; bool use_mpi = false; bool is_static_exe = false; -bool simulate = false; -bool include_uninstr = false; +bool force_config = false; +bool parse_all_modules = false; size_t batch_size = 50; strset_t extra_libs = {}; std::vector> hash_ids = {}; @@ -126,6 +133,8 @@ string_t print_excluded = {}; string_t print_available = {}; string_t print_overlapping = {}; strset_t print_formats = { "txt", "json" }; +strvec_t libname_suffixes = {}; +strvec_t libname_fallbacks = {}; std::string modfunc_dump_dir = {}; auto regex_opts = std::regex_constants::egrep | std::regex_constants::optimize; @@ -271,12 +280,6 @@ main(int argc, char** argv) parser.add_argument({ "" }, ""); parser.add_argument({ "[DEBUG OPTIONS]" }, ""); parser.add_argument({ "" }, ""); - parser.add_argument({ "--debug" }, "Debug output") - .max_count(1) - .action([](parser_t& p) { - debug_print = p.get("debug"); - if(debug_print && !p.exists("verbose")) verbose_level = 256; - }); parser.add_argument({ "-v", "--verbose" }, "Verbose output") .max_count(1) .action([](parser_t& p) { @@ -289,6 +292,12 @@ main(int argc, char** argv) .dtype("boolean") .max_count(1) .action([](parser_t& p) { werror = p.get("error"); }); + parser.add_argument({ "--debug" }, "Debug output") + .max_count(1) + .action([](parser_t& p) { + debug_print = p.get("debug"); + if(debug_print && !p.exists("verbose")) verbose_level = 256; + }); parser .add_argument({ "--simulate" }, "Exit after outputting diagnostic " @@ -406,6 +415,16 @@ main(int argc, char** argv) if(instr_mode == "coverage" && !p.exists("coverage")) coverage_mode = CODECOV_FUNCTION; }); + parser + .add_argument( + { "-f", "--force" }, + "Force the command-line argument configuration, i.e. don't get cute. Useful " + "for forcing runtime instrumentation of an executable that [A] Dyninst " + "thinks is a library after reading ELF and [B] whose name makes it look like " + "a library (e.g. starts with 'lib' and/or ends in '.so', '.so.*', or '.a')") + .max_count(1) + .action([](parser_t& p) { force_config = p.get("force"); }); + if(_cmdc == 0) { parser @@ -616,6 +635,14 @@ main(int argc, char** argv) .dtype("int") .action( [](parser_t& p) { min_instructions = p.get("min-instructions"); }); + parser + .add_argument({ "-r", "--min-address-range" }, + "If the address range of a function is less than this value, " + "exclude it from instrumentation") + .count(1) + .dtype("int") + .action( + [](parser_t& p) { min_address_range = p.get("min-address-range"); }); parser .add_argument({ "--min-instructions-loop" }, "If the number of instructions in a function containing a loop is " @@ -625,14 +652,6 @@ main(int argc, char** argv) .action([](parser_t& p) { min_loop_instructions = p.get("min-instructions-loop"); }); - parser - .add_argument({ "-r", "--min-address-range" }, - "If the address range of a function is less than this value, " - "exclude it from instrumentation") - .count(1) - .dtype("int") - .action( - [](parser_t& p) { min_address_range = p.get("min-address-range"); }); parser .add_argument({ "--min-address-range-loop" }, "If the address range of a function containing a loop is less than " @@ -642,7 +661,13 @@ main(int argc, char** argv) .action([](parser_t& p) { min_loop_address_range = p.get("min-address-range-loop"); }); - parser.add_argument({ "--coverage" }, "Enable recording the code coverage") + parser + .add_argument( + { "--coverage" }, + "Enable recording the code coverage. If instrumenting in coverage mode ('-M " + "converage'), this simply specifies the granularity. If instrumenting in " + "trace or sampling mode, this enables recording code-coverage in addition to " + "the instrumentation of that mode (if any).") .max_count(1) .choices({ "none", "function", "basic_block" }) .action([](parser_t& p) { @@ -691,8 +716,20 @@ main(int argc, char** argv) "Allow dyninst to instrument either multiple functions which overlap (share " "part of same function body) or single functions with multiple entry points. " "For more info, see Section 2 of the DyninstAPI documentation.") - .count(0) - .action([](parser_t&) { allow_overlapping = true; }); + .max_count(1) + .action( + [](parser_t& p) { allow_overlapping = p.get("allow-overlapping"); }); + parser + .add_argument( + { "--parse-all-modules" }, + "By default, omnitrace simply requests Dyninst to provide all the procedures " + "in the application image. If this option is enabled, omnitrace will iterate " + "over all the modules and extract the functions. Theoretically, it should be " + "the same but the data is slightly different, possibly due to weak binding " + "scopes. In general, enabling option will probably have no visible effect") + .max_count(1) + .action( + [](parser_t& p) { parse_all_modules = p.get("parse-all-modules"); }); parser.add_argument({ "" }, ""); parser.add_argument({ "[DYNINST OPTIONS]" }, ""); @@ -824,6 +861,75 @@ main(int argc, char** argv) !parser.exists("min-instructions") && !parser.exists("min-address-range-loop")); + auto _omnitrace_exe_path = tim::dirname(::get_realpath("/proc/self/exe")); + verbprintf(4, "omnitrace exe path: %s\n", _omnitrace_exe_path.c_str()); + + if(strcmp(::basename(_omnitrace_exe_path.c_str()), "bin") == 0) + { + libname_suffixes.emplace_back("omnitrace"); + libname_suffixes.emplace_back("../lib"); + libname_suffixes.emplace_back("../lib64"); + libname_suffixes.emplace_back("../lib/omnitrace"); + libname_suffixes.emplace_back("../lib64/omnitrace"); + libname_suffixes.emplace_back("lib"); + libname_suffixes.emplace_back("lib64"); + libname_suffixes.emplace_back("lib/omnitrace"); + libname_suffixes.emplace_back("lib64/omnitrace"); + libname_fallbacks.emplace_back(_omnitrace_exe_path); + } + else + { + libname_suffixes.emplace_back("lib"); + libname_suffixes.emplace_back("lib64"); + libname_suffixes.emplace_back("lib/omnitrace"); + libname_suffixes.emplace_back("lib64/omnitrace"); + libname_fallbacks.emplace_back(tim::get_env("PWD", ".")); + } + + if(_cmdv && _cmdv[0] && strlen(_cmdv[0]) > 0) + { + auto _is_executable = omnitrace_get_is_executable(_cmdv[0], binary_rewrite); + std::string _cmdv_base = ::basename(_cmdv[0]); + auto _has_lib_suffix = _cmdv_base.length() > 3 && + (_cmdv_base.find(".so.") != std::string::npos || + _cmdv_base.find(".so") == (_cmdv_base.length() - 3) || + _cmdv_base.find(".a") == (_cmdv_base.length() - 2)); + auto _has_lib_prefix = _cmdv_base.length() > 3 && _cmdv_base.find("lib") == 0; + if(!force_config && !_is_executable && !binary_rewrite && + (_has_lib_prefix || _has_lib_suffix)) + { + fflush(stdout); + std::stringstream _separator{}; + // 18 is approximate length of '[omnitrace][exe] ' + // 32 is approximate length of 'Warning! "" is not executable!' + size_t _width = + std::min(std::get<0>(tim::utility::console::get_columns()) - 18, + strlen(_cmdv[0]) + 32); + _separator.fill('='); + _separator << "#" << std::setw(_width - 2) << "" + << "#"; + verbprintf(0, "%s\n", _separator.str().c_str()); + verbprintf(0, "\n"); + verbprintf(0, "Warning! '%s' is not executable!\n", _cmdv[0]); + verbprintf(0, "Runtime instrumentation is not possible!\n"); + verbprintf(0, "Switching to binary rewrite mode and assuming '--simulate " + "--all-functions'\n"); + verbprintf( + 0, "(which will provide an approximation for runtime instrumentation)\n"); + verbprintf(1, "%s :: (^lib)=%s, (.so$|.a$|.so.*)=%s\n", _cmdv_base.c_str(), + (_has_lib_prefix) ? "true" : "false", + (_has_lib_suffix) ? "true" : "false"); + verbprintf(0, "\n"); + verbprintf(0, "%s\n", _separator.str().c_str()); + verbprintf(0, "\n"); + fflush(stdout); + std::this_thread::sleep_for(std::chrono::milliseconds{ 500 }); + binary_rewrite = true; + simulate = true; + include_uninstr = true; + } + } + if(binary_rewrite && outfile.empty()) { auto _is_local = (get_realpath(cmdv0) == @@ -1020,6 +1126,22 @@ main(int argc, char** argv) errprintf(-1, "address space for dynamic instrumentation was not created\n"); } + if(dynamic_cast(addr_space) != nullptr && + dynamic_cast(addr_space) != nullptr) + { + errprintf(-1, "address space statisfied dynamic_cast<%s> and dynamic_cast<%s>.\n", + tim::demangle().c_str(), + tim::demangle().c_str()); + } + + auto _rewrite = (dynamic_cast(addr_space) != nullptr && + dynamic_cast(addr_space) == nullptr); + if(_rewrite != binary_rewrite) + { + errprintf(-1, "binary rewrite was %s but has been deduced to be %s\n", + (binary_rewrite) ? "ON" : "OFF", (_rewrite) ? "ON" : "OFF"); + } + process_t* app_thread = nullptr; binary_edit_t* app_binary = nullptr; @@ -1028,8 +1150,8 @@ main(int argc, char** argv) image_t* app_image = addr_space->getImage(); bpvector_t* app_modules = app_image->getModules(); bpvector_t* app_functions = app_image->getProcedures(include_uninstr); - bpvector_t modules; - bpvector_t functions; + std::set modules = {}; + std::set functions = {}; //----------------------------------------------------------------------------------// // @@ -1058,47 +1180,24 @@ main(int argc, char** argv) } }; - if(app_modules && !app_modules->empty()) - { - modules.reserve(app_modules->size()); - for(auto* itr : *app_modules) - { - if(!itr->isSystemLib()) modules.emplace_back(itr); - } - for(auto* itr : modules) - { - auto* procedures = itr->getProcedures(include_uninstr); - if(procedures) - { - for(auto* pitr : *procedures) - { - if(!pitr->isInstrumentable()) continue; - auto _modfn = module_function{ itr, pitr }; - module_names.insert(_modfn.module_name); - _insert_module_function(available_module_functions, _modfn); - _add_overlapping(itr, pitr); - } - } - } - } - else - { - verbprintf(0, "Warning! No modules in application...\n"); - } - if(app_functions && !app_functions->empty()) { - functions.reserve(app_functions->size()); for(auto* itr : *app_functions) { - if(!itr->getModule()->isSystemLib()) functions.emplace_back(itr); + if(itr->getModule() && !itr->getModule()->isSystemLib()) + { + functions.emplace(itr); + modules.emplace(itr->getModule()); + } } + verbprintf(2, "Adding %zu procedures found in the app image...\n", + functions.size()); for(auto* itr : functions) { - module_t* mod = itr->getModule(); - if(mod && itr->isInstrumentable()) + if(itr->isInstrumentable() || (simulate && include_uninstr)) { - auto _modfn = module_function{ mod, itr }; + module_t* mod = itr->getModule(); + auto _modfn = module_function{ mod, itr }; module_names.insert(_modfn.module_name); _insert_module_function(available_module_functions, _modfn); _add_overlapping(mod, itr); @@ -1107,11 +1206,48 @@ main(int argc, char** argv) } else { - verbprintf(0, "Warning! No functions in application...\n"); + verbprintf( + 0, "Warning! No functions in application. Enabling parsing all modules...\n"); + parse_all_modules = true; } - verbprintf(1, "Module size before loading instrumentation library: %lu\n", - (long unsigned) modules.size()); + if(parse_all_modules && app_modules && !app_modules->empty()) + { + for(auto* itr : *app_modules) + { + if(!itr->isSystemLib()) modules.emplace(itr); + } + verbprintf(2, + "Adding the procedures from %zu modules found in the app image...\n", + modules.size()); + for(auto* itr : modules) + { + auto* procedures = itr->getProcedures(include_uninstr); + if(procedures) + { + verbprintf(2, "Processing %zu procedures found in the %s module...\n", + procedures->size(), get_name(itr).data()); + for(auto* pitr : *procedures) + { + if(!pitr->isInstrumentable() && !simulate && !include_uninstr) + continue; + functions.emplace(pitr); + auto _modfn = module_function{ itr, pitr }; + module_names.insert(_modfn.module_name); + _insert_module_function(available_module_functions, _modfn); + _add_overlapping(itr, pitr); + } + } + } + } + else if(parse_all_modules) + { + verbprintf(0, "Warning! No modules in application...\n"); + } + + verbprintf(1, "\n"); + verbprintf(1, "Found %zu functions in %zu modules in instrumentation target\n", + functions.size(), modules.size()); if(debug_print || verbose_level > 2) { @@ -1221,8 +1357,6 @@ main(int argc, char** argv) // //----------------------------------------------------------------------------------// - auto* main_init = find_function(app_image, "_init"); - auto* main_fini = find_function(app_image, "_fini"); auto* main_func = find_function(app_image, main_fname.c_str()); auto* user_start_func = find_function(app_image, "omnitrace_user_start_trace", { "omnitrace_user_start_thread_trace" }); @@ -1383,30 +1517,6 @@ main(int argc, char** argv) // //----------------------------------------------------------------------------------// - if(!main_func) - { - if(!main_init && !main_fini) - { - errprintf(-1, "could not find '%s', '_init' or '_fini', aborting...\n", - main_fname.c_str()); - } - else if(!main_init) - { - errprintf(-1, "could not find '%s' or '_init', aborting...\n", - main_fname.c_str()); - } - else if(!main_fini) - { - errprintf(-1, "could not find '%s' or '_fini', aborting...\n", - main_fname.c_str()); - } - else - { - verbprintf(0, "using '%s' and '%s' in lieu of '%s'...\n", "_init", "_fini", - main_fname.c_str()); - } - } - using pair_t = std::pair; for(const auto& itr : @@ -1423,26 +1533,6 @@ main(int argc, char** argv) } } - auto check_for_debug_info = [](bool& _has_debug_info, auto* _func) { - // This heuristic guesses that debugging info is available if function - // is not defined in the DEFAULT_MODULE - if(_func && !_has_debug_info) - { - module_t* _module = _func->getModule(); - if(_module) - { - char moduleName[FUNCNAMELEN]; - _module->getFullName(moduleName, FUNCNAMELEN); - if(strcmp(moduleName, "DEFAULT_MODULE") != 0) _has_debug_info = true; - } - } - }; - - bool has_debug_info = false; - check_for_debug_info(has_debug_info, main_func); - check_for_debug_info(has_debug_info, main_init); - check_for_debug_info(has_debug_info, main_fini); - //----------------------------------------------------------------------------------// // // Find the entry/exit point of either the main (if executable) or the _init @@ -1460,16 +1550,6 @@ main(int argc, char** argv) main_exit_points = main_func->findPoint(BPatch_exit); verbprintf(2, "Done\n"); } - else - { - verbprintf(2, "Finding init entry... "); - main_entr_points = main_init->findPoint(BPatch_entry); - verbprintf(2, "Done\n"); - - verbprintf(2, "Finding fini exit... "); - main_exit_points = main_fini->findPoint(BPatch_exit); - verbprintf(2, "Done\n"); - } //----------------------------------------------------------------------------------// // @@ -1535,7 +1615,7 @@ main(int argc, char** argv) if(_libname.empty()) _libname = get_absolute_lib_filepath(itr, "LIBRARY_PATH"); if(_libname.empty()) _libname = get_absolute_lib_filepath(itr, "LD_LIBRARY_PATH"); } - if(_libname.empty()) _libname = "libomnitrace.so"; + if(_libname.empty()) _libname = "libomnitrace-dl.so"; // prioritize the user environment arguments auto env_vars = parser.get("env"); @@ -1634,13 +1714,10 @@ main(int argc, char** argv) } else { - // in sampling mode, we instrument either main or init + fini - for(auto&& itr : { main_func, main_init, main_fini }) - { - if(itr) - _insert_module_function(instrumented_module_functions, - module_function{ itr->getModule(), itr }); - } + // in sampling mode, we instrument either main or add init and fini callbacks + if(main_func) + _insert_module_function(instrumented_module_functions, + module_function{ main_func->getModule(), main_func }); for(const auto& itr : available_module_functions) { @@ -1662,6 +1739,11 @@ main(int argc, char** argv) // //----------------------------------------------------------------------------------// + auto _objs = std::vector{}; + addr_space->getImage()->getObjects(_objs); + auto _init_sequence = sequence_t{ init_names }; + auto _fini_sequence = sequence_t{ fini_names }; + if(app_thread && is_attached) { assert(app_thread != nullptr); @@ -1674,16 +1756,26 @@ main(int argc, char** argv) if(main_entr_points) { verbprintf(1, "Adding main entry snippets...\n"); - addr_space->insertSnippet(BPatch_sequence(init_names), *main_entr_points, + addr_space->insertSnippet(_init_sequence, *main_entr_points, BPatch_callBefore, BPatch_firstSnippet); } + else + { + for(auto* itr : _objs) + itr->insertInitCallback(_init_sequence); + } } if(main_exit_points) { verbprintf(1, "Adding main exit snippets...\n"); - addr_space->insertSnippet(BPatch_sequence(fini_names), *main_exit_points, - BPatch_callAfter, BPatch_firstSnippet); + addr_space->insertSnippet(_fini_sequence, *main_exit_points, BPatch_callAfter, + BPatch_firstSnippet); + } + else + { + for(auto* itr : _objs) + itr->insertFiniCallback(_fini_sequence); } //----------------------------------------------------------------------------------// @@ -1716,13 +1808,11 @@ main(int argc, char** argv) if(instr_mode != "coverage") { - std::map> _pass_info{}; - const int _pass_verbose_lvl = 0; + auto _pass_info = std::map>{}; + const int _pass_verbose_lvl = 0; for(const auto& itr : instrumented_module_functions) { - bool _is_main = itr.function == main_func || itr.function == main_init || - itr.function == main_fini; - if(_is_main) continue; + if(itr.function == main_func) continue; auto _count = itr(addr_space, entr_trace, exit_trace); _pass_info[itr.module_name].first += _count.first; _pass_info[itr.module_name].second += _count.second; @@ -1756,9 +1846,7 @@ main(int argc, char** argv) const int _covr_verbose_lvl = 1; for(const auto& itr : coverage_module_functions) { - bool _is_main = itr.function == main_func || itr.function == main_init || - itr.function == main_fini; - if(_is_main) continue; + if(itr.function == main_func) continue; itr.register_source(addr_space, reg_src_func, *main_entr_points); auto _count = itr.register_coverage(addr_space, reg_cov_func); _covr_info[itr.module_name].first += _count.first; @@ -1899,22 +1987,18 @@ main(int argc, char** argv) { for(const auto& itr : _modset) { - std::stringstream _ss{}; - _ss << std::boolalpha; - _ss << "" << itr.module_name << "] --> [" << itr.function_name << "][" - << itr.num_instructions << "]"; - _insert(itr.module_name, _ss.str()); + _insert(itr.module_name, TIMEMORY_JOIN("", "[", itr.module_name, + "] --> [", itr.function_name, "][", + itr.num_instructions, "]")); } } else if(_mode == "pair+") { for(const auto& itr : _modset) { - std::stringstream _ss{}; - _ss << std::boolalpha; - _ss << "[" << itr.module_name << "] --> [" << itr.signature.get() << "][" - << itr.num_instructions << "]"; - _insert(itr.module_name, _ss.str()); + _insert(itr.module_name, TIMEMORY_JOIN("", "[", itr.module_name, + "] --> [", itr.signature.get(), + "][", itr.num_instructions, "]")); } } else @@ -2246,6 +2330,9 @@ get_absolute_lib_filepath(std::string lib_name, const std::string& env_path, std::vector suffixes, std::vector fallbacks) { + if(suffixes.empty()) suffixes = libname_suffixes; + if(fallbacks.empty()) fallbacks = libname_fallbacks; + if(!lib_name.empty() && (!file_exists(lib_name) || std::regex_match(lib_name, std::regex("^[A-Za-z0-9].*")))) { @@ -2273,6 +2360,7 @@ get_absolute_lib_filepath(std::string lib_name, const std::string& env_path, break; } } + if(file_exists(lib_name)) break; } if(!file_exists(lib_name)) @@ -2295,6 +2383,7 @@ bool file_exists(const std::string& name) { struct stat buffer; + verbprintf(4, "querying whether file '%s' exists...\n", name.c_str()); return (stat(name.c_str(), &buffer) == 0); } @@ -2322,22 +2411,8 @@ using tim::dirname; void find_dyn_api_rt() { - auto _exe_path = dirname(::get_realpath("/proc/self/exe")); - - strvec_t _suffixes = {}; - strvec_t _fallbacks = {}; - - if(strcmp(::basename(_exe_path.c_str()), "bin") == 0) - { - _suffixes.emplace_back("omnitrace"); - _suffixes.emplace_back("../lib"); - _suffixes.emplace_back("../lib/omnitrace"); - _fallbacks.emplace_back(_exe_path); - } - else - { - _fallbacks.emplace_back(tim::get_env("PWD", ".")); - } + strvec_t _suffixes = libname_suffixes; + strvec_t _fallbacks = libname_fallbacks; std::copy(_dyn_api_rt_paths.begin(), _dyn_api_rt_paths.end(), std::back_inserter(_fallbacks)); diff --git a/source/bin/omnitrace/omnitrace.hpp b/source/bin/omnitrace/omnitrace.hpp index 87b266eb08..1f475f2ab9 100644 --- a/source/bin/omnitrace/omnitrace.hpp +++ b/source/bin/omnitrace/omnitrace.hpp @@ -27,6 +27,11 @@ #include "info.hpp" #include "module_function.hpp" +#include + +#include +#include + //======================================================================================// inline string_t @@ -153,6 +158,34 @@ private: // //======================================================================================// // +static inline bool +omnitrace_get_is_executable(std::string_view _cmd, bool _default_v) +{ + bool _is_executable = _default_v; + + if(_cmd.empty()) + { + if(!tim::filepath::exists(std::string{ _cmd })) + { + verbprintf( + 0, + "Warning! '%s' was not found. Dyninst may fail to open the binary for " + "instrumentation...\n", + _cmd.data()); + } + + Dyninst::SymtabAPI::Symtab* _symtab = nullptr; + if(Dyninst::SymtabAPI::Symtab::openFile(_symtab, _cmd.data())) + { + _is_executable = _symtab->isExecutable() && _symtab->isExec(); + Dyninst::SymtabAPI::Symtab::closeSymtab(_symtab); + } + } + return _is_executable; +} +// +//======================================================================================// +// static inline address_space_t* omnitrace_get_address_space(patch_pointer_t& _bpatch, int _cmdc, char** _cmdv, bool _rewrite, int _pid = -1, const string_t& _name = {}) diff --git a/source/bin/tests/CMakeLists.txt b/source/bin/tests/CMakeLists.txt index c880056dc9..24555e3348 100644 --- a/source/bin/tests/CMakeLists.txt +++ b/source/bin/tests/CMakeLists.txt @@ -2,12 +2,15 @@ function(OMNITRACE_ADD_BIN_TEST) cmake_parse_arguments( TEST - "" # options + "ADD_INVERSE" # options "NAME;TARGET;TIMEOUT;WORKING_DIRECTORY" # single value args "ARGS;ENVIRONMENT;LABELS;PROPERTIES;PASS_REGEX;FAIL_REGEX;SKIP_REGEX;DEPENDS;COMMAND" # multiple # value args ${ARGN}) + if(NOT TEST_WORKING_DIRECTORY) + set(TEST_WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + endif() if(NOT OMNITRACE_DYNINST_API_RT_DIR AND OMNITRACE_DYNINST_API_RT) get_filename_component(OMNITRACE_DYNINST_API_RT_DIR "${OMNITRACE_DYNINST_API_RT}" DIRECTORY) @@ -25,13 +28,19 @@ function(OMNITRACE_ADD_BIN_TEST) "OMNITRACE_USE_TIMEMORY=ON" "OMNITRACE_USE_SAMPLING=ON" "OMNITRACE_TIME_OUTPUT=OFF" - "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" + "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" ) endif() + # common list(APPEND TEST_ENVIRONMENT "OMNITRACE_CI=ON" - "OMNITRACE_OUTPUT_PATH=omnitrace-tests-output" - "OMNITRACE_OUTPUT_PREFIX=${TEST_NAME}/") + "OMNITRACE_OUTPUT_PATH=omnitrace-tests-output") + # copy for inverse + set(TEST_ENVIRONMENT_INV "${TEST_ENVIRONMENT}") + + # different for regular test and inverse test + list(APPEND TEST_ENVIRONMENT "OMNITRACE_OUTPUT_PREFIX=${TEST_NAME}/") + list(APPEND TEST_ENVIRONMENT_INV "OMNITRACE_OUTPUT_PREFIX=${TEST_NAME}-inverse/") if(TEST_COMMAND) add_test( @@ -56,11 +65,37 @@ function(OMNITRACE_ADD_BIN_TEST) SKIP_REGULAR_EXPRESSION "${TEST_SKIP_REGEX}" ${TEST_PROPERTIES}) + if(TEST_ADD_INVERSE) + add_test( + NAME ${TEST_NAME}-inverse + COMMAND ${TEST_COMMAND} ${TEST_ARGS} + WORKING_DIRECTORY ${TEST_WORKING_DIRECTORY}) + + set_tests_properties( + ${TEST_NAME}-inverse + PROPERTIES ENVIRONMENT + "${TEST_ENVIRONMENT_INV}" + TIMEOUT + ${TEST_TIMEOUT} + DEPENDS + "${TEST_DEPENDS}" + LABELS + "omnitrace-bin;${TEST_LABELS}" + PASS_REGULAR_EXPRESSION + "${TEST_FAIL_REGEX}" + FAIL_REGULAR_EXPRESSION + "${TEST_PASS_REGEX}" + SKIP_REGULAR_EXPRESSION + "${TEST_SKIP_REGEX}" + WILL_FAIL + ON + ${TEST_PROPERTIES}) + endif() elseif(TARGET ${TEST_TARGET}) add_test( NAME ${TEST_NAME} COMMAND $ ${TEST_ARGS} - WORKING_DIRECTORY $) + WORKING_DIRECTORY ${TEST_WORKING_DIRECTORY}) set_tests_properties( ${TEST_NAME} @@ -79,6 +114,32 @@ function(OMNITRACE_ADD_BIN_TEST) SKIP_REGULAR_EXPRESSION "${TEST_SKIP_REGEX}" ${TEST_PROPERTIES}) + if(TEST_ADD_INVERSE) + add_test( + NAME ${TEST_NAME}-inverse + COMMAND $ ${TEST_ARGS} + WORKING_DIRECTORY ${TEST_WORKING_DIRECTORY}) + + set_tests_properties( + ${TEST_NAME}-inverse + PROPERTIES ENVIRONMENT + "${TEST_ENVIRONMENT_INV}" + TIMEOUT + ${TEST_TIMEOUT} + DEPENDS + "${TEST_DEPENDS}" + LABELS + "omnitrace-bin;${TEST_LABELS}" + PASS_REGULAR_EXPRESSION + "${TEST_FAIL_REGEX}" + FAIL_REGULAR_EXPRESSION + "${TEST_PASS_REGEX}" + SKIP_REGULAR_EXPRESSION + "${TEST_SKIP_REGEX}" + WILL_FAIL + ON + ${TEST_PROPERTIES}) + endif() elseif(OMNITRACE_BUILD_TESTING) message(FATAL_ERROR "Error! ${TEST_TARGET} does not exist") endif() @@ -103,7 +164,7 @@ omnitrace_add_bin_test( txt xml -v - 1 + 2 --all-functions -- ls @@ -113,14 +174,23 @@ omnitrace_add_bin_test( omnitrace_add_bin_test( NAME omnitrace-exe-simulate-ls-check DEPENDS omnitrace-exe-simulate-ls - COMMAND ls - WORKING_DIRECTORY - ${PROJECT_BINARY_DIR}/omnitrace-tests-output/omnitrace-exe-simulate-ls + COMMAND ls omnitrace-tests-output/omnitrace-exe-simulate-ls TIMEOUT 60 PASS_REGEX ".*available-instr.json.*available-instr.txt.*available-instr.xml.*excluded-instr.json.*excluded-instr.txt.*excluded-instr.xml.*instrumented-instr.json.*instrumented-instr.txt.*instrumented-instr.xml.*overlapping-instr.json.*overlapping-instr.txt.*overlapping-instr.xml.*" ) +omnitrace_add_bin_test( + ADD_INVERSE + NAME omnitrace-exe-simulate-lib + TARGET omnitrace-exe + ARGS --print-available functions -v 2 -- $ + LABELS "simulate" + TIMEOUT 120 + PASS_REGEX + "\\\[omnitrace\\\]\\\[exe\\\] Runtime instrumentation is not possible!(.*)\n(.*)\\\[omnitrace\\\]\\\[exe\\\] Switching to binary rewrite mode and assuming '--simulate --all-functions'" + ) + omnitrace_add_bin_test( NAME omnitrace-avail-help TARGET omnitrace-avail diff --git a/source/lib/omnitrace-dl/CMakeLists.txt b/source/lib/omnitrace-dl/CMakeLists.txt index 6ae51d5b0f..08a33efc43 100644 --- a/source/lib/omnitrace-dl/CMakeLists.txt +++ b/source/lib/omnitrace-dl/CMakeLists.txt @@ -38,7 +38,7 @@ set_target_properties( omnitrace-dl-library PROPERTIES OUTPUT_NAME omnitrace-dl VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} + SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} BUILD_RPATH "\$ORIGIN" INSTALL_RPATH "\$ORIGIN") diff --git a/source/lib/omnitrace-user/CMakeLists.txt b/source/lib/omnitrace-user/CMakeLists.txt index 0b606eef5a..601f6e839c 100644 --- a/source/lib/omnitrace-user/CMakeLists.txt +++ b/source/lib/omnitrace-user/CMakeLists.txt @@ -26,7 +26,7 @@ set_target_properties( omnitrace-user-library PROPERTIES OUTPUT_NAME omnitrace-user VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} + SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} POSITION_INDEPENDENT_CODE ON BUILD_RPATH "\$ORIGIN" INSTALL_RPATH "\$ORIGIN") diff --git a/source/lib/omnitrace/CMakeLists.txt b/source/lib/omnitrace/CMakeLists.txt index b9fcaa78e3..0244cafbed 100644 --- a/source/lib/omnitrace/CMakeLists.txt +++ b/source/lib/omnitrace/CMakeLists.txt @@ -178,7 +178,7 @@ set_target_properties( omnitrace-library PROPERTIES OUTPUT_NAME omnitrace VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} + SOVERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} INSTALL_RPATH "${OMNITRACE_LIB_INSTALL_RPATH}") omnitrace_strip_target(omnitrace-library) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f1124f2fa1..c14f3003ab 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,7 +32,7 @@ set(_base_environment "OMP_PROC_BIND=spread" "OMP_PLACES=threads" "OMP_NUM_THREADS=2" - "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" + "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" ) set(_lock_environment @@ -45,7 +45,7 @@ set(_lock_environment "OMNITRACE_TIME_OUTPUT=OFF" "OMNITRACE_FLAT_PROFILE=ON" "OMNITRACE_TIMELINE_PROFILE=OFF" - "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" + "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" ) set(_ompt_environment @@ -57,7 +57,7 @@ set(_ompt_environment "OMP_PROC_BIND=spread" "OMP_PLACES=threads" "OMP_NUM_THREADS=2" - "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" + "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" ) set(_perfetto_environment @@ -69,7 +69,7 @@ set(_perfetto_environment "OMP_PROC_BIND=spread" "OMP_PLACES=threads" "OMP_NUM_THREADS=2" - "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" + "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" ) set(_timemory_environment @@ -81,7 +81,7 @@ set(_timemory_environment "OMP_PROC_BIND=spread" "OMP_PLACES=threads" "OMP_NUM_THREADS=2" - "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" + "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" ) set(_test_environment ${_base_environment} "OMNITRACE_CRITICAL_TRACE=OFF") @@ -95,7 +95,7 @@ set(_python_environment "OMNITRACE_TREE_OUTPUT=OFF" "OMNITRACE_USE_PID=OFF" "OMNITRACE_TIMEMORY_COMPONENTS=trip_count" - "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" + "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" "PYTHONPATH=${PROJECT_BINARY_DIR}/lib/python/site-packages") set(_attach_environment @@ -111,7 +111,7 @@ set(_attach_environment "OMP_PROC_BIND=spread" "OMP_PLACES=threads" "OMP_NUM_THREADS=2" - "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" + "LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}:${OMNITRACE_DYNINST_API_RT_DIR}:$ENV{LD_LIBRARY_PATH}" ) # -------------------------------------------------------------------------------------- #