Reorganization and critical trace support (#17)

* Roctracer wall clock integration (#16)

* Integrates roctracer values into wall-clock

* Fixed scoping + timemory roctracer

* Fixed data race in roctracer

* Synchronized HIP API on main thread

- Cache hip activity callbacks and execute on main thread
- Minor updates to transpose

* Debugging + MPI + transpose updates

* PTL + HSA and timemory + kernel timing

- PTL usage fixed HSA + timemory issues bc we could control the thread destruction
- Fixed laps counting in roctracer callbacks

* Ignore select HIP API types

- The ignored API types are ignored because there appears to be a bug
  which causes the "end" callback to be labeled as begin
- hipDeviceEnablePeerAccess
- hipImportExternalMemory
- hipDestroyExternalMemory

* Tweaks to PTL config

* Timemory update + pid-prefix w/ mpi headers

- %pid%- prefix with mpi headers
- timemory submodule update

* CMake + critical trace + reorganize library source

- clang-tidy tweaks
- cmake function updates to use hosttrace_ prefix
- update gitignore
- cmake HOSTTRACE_MAX_THREADS option
- Formatting.cmake
- cleaned up MacroUtilities.cmake
- PTL submodule + usage
- tweak to Findroctracer.cmake
- MT transpose
- Updated PTL submodule
- Updated timemory submodule
- fix to hosttrace return value type if type not found
- reorganized library source code
- support for critical trace

* Remove bits/stdint-uintn.h headers

* Rename + config + depth + critical path

- rename hosttrace_timemory_data to instrumentation_bundles
- rename hosttrace_bundle_t to main_bundle_t
- rename bundle_t to instrumentation_bundle_t
- rework of configuration setup
- critical_trace write directly to file option
- tweaked depth calculation
- updated timemory submodule
- improved parallel support in roctracer callbacks
- working critical_trace
- perfetto device-critical-trace and host-critical-trace categories
- made transpose example parallel
- made parallel-overhead example a bit uneven
- relocated LTO activation

* Fixed duplicates in perfetto critical-trace

* reworked critical trace support

- substantial perf improvement (30-45 min -> 30 sec)
- changes to configuration (new and removed options)

* Removed "%pid%-" output prefix in mpi_gotcha

* Update timemory submodule

[ROCm/rocprofiler-systems commit: 752424efc2]
This commit is contained in:
Jonathan R. Madsen
2021-11-23 02:53:14 -06:00
کامیت شده توسط GitHub
والد cdd2707058
کامیت efb6d766af
52فایلهای تغییر یافته به همراه7785 افزوده شده و 2394 حذف شده
@@ -18,6 +18,7 @@ modernize-*,\
-modernize-use-using,\
-modernize-use-auto,\
-modernize-concat-nested-namespaces,\
-modernize-use-nodiscard,\
performance-*,\
readability-*,\
-readability-function-size,\
@@ -1,6 +1,6 @@
parse:
additional_commands:
checkout_git_submodule:
hosttrace_checkout_git_submodule:
flags:
- RECURSIVE
kwargs:
@@ -33,3 +33,6 @@
/build*
/.vscode
/.cache
/.clangd
/compile_commands.json
@@ -10,3 +10,6 @@
[submodule "external/dyninst"]
path = external/dyninst
url = https://github.com/jrmadsen/dyninst.git
[submodule "external/PTL"]
path = external/PTL
url = https://github.com/jrmadsen/PTL.git
@@ -50,49 +50,124 @@ include(BuildSettings) # compiler flags
set(CMAKE_CXX_STANDARD
17
CACHE STRING "CXX language standard")
add_option(CMAKE_CXX_STANDARD_REQUIRED "Require C++ language standard" ON)
add_option(CMAKE_CXX_EXTENSIONS "Compiler specific language extensions" OFF)
add_option(CMAKE_INSTALL_RPATH_USE_LINK_PATH "Enable rpath to linked libraries" ON)
add_option(HOSTTRACE_USE_CLANG_TIDY "Enable clang-tidy" OFF)
add_option(HOSTTRACE_USE_MPI "Enable MPI support" OFF)
add_option(HOSTTRACE_CUSTOM_DATA_SOURCE "Enable custom data source" OFF)
add_option(HOSTTRACE_USE_ROCTRACER "Enable roctracer support" ON)
add_option(HOSTTRACE_BUILD_DYNINST "Build dyninst from submodule" OFF)
add_option(HOSTTRACE_USE_MPI_HEADERS
"Enable wrapping MPI functions w/o enabling MPI dependency" OFF)
hosttrace_add_feature(CMAKE_CXX_STANDARD "CXX language standard")
hosttrace_add_option(CMAKE_CXX_STANDARD_REQUIRED "Require C++ language standard" ON)
hosttrace_add_option(CMAKE_CXX_EXTENSIONS "Compiler specific language extensions" OFF)
hosttrace_add_option(CMAKE_INSTALL_RPATH_USE_LINK_PATH "Enable rpath to linked libraries"
ON)
hosttrace_add_option(HOSTTRACE_USE_CLANG_TIDY "Enable clang-tidy" OFF)
hosttrace_add_option(HOSTTRACE_USE_MPI "Enable MPI support" OFF)
hosttrace_add_option(HOSTTRACE_CUSTOM_DATA_SOURCE "Enable custom data source" OFF)
hosttrace_add_option(HOSTTRACE_USE_ROCTRACER "Enable roctracer support" ON)
hosttrace_add_option(HOSTTRACE_BUILD_DYNINST "Build dyninst from submodule" OFF)
hosttrace_add_option(HOSTTRACE_USE_MPI_HEADERS
"Enable wrapping MPI functions w/o enabling MPI dependency" OFF)
include(ProcessorCount)
processorcount(HOSTTRACE_PROCESSOR_COUNT)
math(EXPR HOSTTRACE_THREAD_COUNT "8 * ${HOSTTRACE_PROCESSOR_COUNT}")
set(HOSTTRACE_MAX_THREADS
"${HOSTTRACE_THREAD_COUNT}"
CACHE
STRING
"Maximum number of threads in the host application. Likely only needs to be increased if host app does not use thread-pool but creates many threads"
)
hosttrace_add_feature(
HOSTTRACE_MAX_THREADS
"Maximum number of total threads supported in the host application (default: 8 * nproc)"
)
# ensure synced
set(TIMEMORY_USE_MPI
${HOSTTRACE_USE_MPI}
CACHE BOOL "Enable MPI support" FORCE)
# default visibility settings
set(CMAKE_C_VISIBILITY_PRESET "default")
set(CMAKE_CXX_VISIBILITY_PRESET "default")
set(CMAKE_VISIBILITY_INLINES_HIDDEN OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include(Formatting) # format target
include(Packages) # finds third-party libraries
if(HOSTTRACE_USE_ROCTRACER)
find_package(HIP QUIET)
if(HIP_VERSION_MAJOR GREATER_EQUAL 4 AND HIP_VERSION_MINOR GREATER 3)
set(roctracer_kfdwrapper_LIBRARY)
endif()
else()
set(HIP_VERSION "0.0.0")
set(HIP_VERSION_MAJOR 0)
set(HIP_VERSION_MINOR 0)
set(HIP_VERSION_PATCH 0)
endif()
configure_file(${PROJECT_SOURCE_DIR}/include/library/defines.hpp.in
${PROJECT_BINARY_DIR}/include/library/defines.hpp @ONLY)
hosttrace_activate_clang_tidy()
# custom visibility settings
set(CMAKE_C_VISIBILITY_PRESET "hidden")
set(CMAKE_CXX_VISIBILITY_PRESET "hidden")
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
if(HOSTTRACE_BUILD_LTO)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
endif()
# ------------------------------------------------------------------------------#
#
# hosttrace-library target
#
# ------------------------------------------------------------------------------#
add_library(
hosttrace-library SHARED
${CMAKE_CURRENT_LIST_DIR}/src/library.cpp ${CMAKE_CURRENT_LIST_DIR}/src/libmisc.cpp
${CMAKE_CURRENT_LIST_DIR}/include/library.hpp ${perfetto_DIR}/sdk/perfetto.cc)
set(library_sources
${CMAKE_CURRENT_LIST_DIR}/src/library.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/config.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/critical_trace.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/fork_gotcha.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/hosttrace_component.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/mpi_gotcha.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/perfetto.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/ptl.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/thread_data.cpp
${CMAKE_CURRENT_LIST_DIR}/src/library/timemory.cpp
${perfetto_DIR}/sdk/perfetto.cc)
set(library_headers
${CMAKE_CURRENT_LIST_DIR}/include/library.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/api.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/config.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/common.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/critical_trace.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/debug.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/fork_gotcha.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/hosttrace_component.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/mpi_gotcha.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/perfetto.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/ptl.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/state.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/thread_data.hpp
${CMAKE_CURRENT_LIST_DIR}/include/library/timemory.hpp
${perfetto_DIR}/sdk/perfetto.h)
if(NOT TIMEMORY_USE_PERFETTO)
endif()
add_library(hosttrace-library SHARED ${library_sources} ${library_headers})
if(HOSTTRACE_USE_ROCTRACER)
target_sources(
hosttrace-library PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/roctracer.hpp
${CMAKE_CURRENT_LIST_DIR}/src/roctracer.cpp)
hosttrace-library
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/library/roctracer.hpp
${CMAKE_CURRENT_LIST_DIR}/src/library/roctracer.cpp
${CMAKE_CURRENT_LIST_DIR}/include/library/roctracer_callbacks.hpp
${CMAKE_CURRENT_LIST_DIR}/src/library/roctracer_callbacks.cpp)
endif()
target_include_directories(hosttrace-library PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include)
target_include_directories(hosttrace-library SYSTEM PRIVATE ${perfetto_DIR}/sdk)
target_compile_definitions(
@@ -101,10 +176,12 @@ target_compile_definitions(
target_link_libraries(
hosttrace-library
PRIVATE hosttrace::hosttrace-threading
PRIVATE hosttrace::hosttrace-headers
hosttrace::hosttrace-threading
hosttrace::hosttrace-compile-options
hosttrace::hosttrace-roctracer
hosttrace::hosttrace-mpi
hosttrace::hosttrace-ptl
$<BUILD_INTERFACE:timemory::timemory-headers>
$<BUILD_INTERFACE:timemory::timemory-gotcha>
$<BUILD_INTERFACE:timemory::timemory-cxx-shared>
@@ -134,13 +211,13 @@ add_executable(
hosttrace-exe
${_EXCLUDE} ${CMAKE_CURRENT_LIST_DIR}/src/hosttrace.cpp
${CMAKE_CURRENT_LIST_DIR}/include/hosttrace.hpp
${CMAKE_CURRENT_LIST_DIR}/src/hosttrace-details.cpp)
target_include_directories(hosttrace-exe PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include)
${CMAKE_CURRENT_LIST_DIR}/src/hosttrace/details.cpp)
target_link_libraries(
hosttrace-exe
PRIVATE hosttrace::hosttrace-dyninst hosttrace::hosttrace-compile-options
PRIVATE hosttrace::hosttrace-headers
hosttrace::hosttrace-dyninst
hosttrace::hosttrace-compile-options
$<BUILD_INTERFACE:timemory::timemory-headers>
$<IF:$<BOOL:${HOSTTRACE_USE_SANITIZER}>,hosttrace::hosttrace-sanitizer,>)
@@ -211,3 +288,11 @@ add_subdirectory(tests)
# ------------------------------------------------------------------------------#
include(ConfigCPack)
# ------------------------------------------------------------------------------#
#
# config info
#
# ------------------------------------------------------------------------------#
hosttrace_print_features()
@@ -68,7 +68,7 @@ endif()
# ----------------------------------------------------------------------------------------#
# extra flags for debug information in debug or optimized binaries
#
add_interface_library(
hosttrace_add_interface_library(
hosttrace-compile-debuginfo
"Attempts to set best flags for more expressive profiling information in debug or optimized binaries"
)
@@ -108,7 +108,7 @@ endif()
# ----------------------------------------------------------------------------------------#
# non-debug optimizations
#
add_interface_library(hosttrace-compile-extra "Extra optimization flags")
hosttrace_add_interface_library(hosttrace-compile-extra "Extra optimization flags")
if(NOT HOSTTRACE_USE_COVERAGE)
add_target_flag_if_avail(
hosttrace-compile-extra "-finline-functions" "-funroll-loops" "-ftree-vectorize"
@@ -130,21 +130,16 @@ endif()
#
add_cxx_flag_if_avail("-faligned-new")
if(HOSTTRACE_BUILD_LTO)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
endif()
hosttrace_save_variables(FLTO VARIABLES CMAKE_CXX_FLAGS)
set(CMAKE_CXX_FLAGS "-flto=thin ${CMAKE_CXX_FLAGS}")
add_interface_library(hosttrace-lto "Adds link-time-optimization flags")
hosttrace_add_interface_library(hosttrace-lto "Adds link-time-optimization flags")
add_target_flag_if_avail(hosttrace-lto "-flto=thin")
if(NOT cxx_hosttrace_lto_flto_thin)
set(CMAKE_CXX_FLAGS "-flto ${CMAKE_CXX_FLAGS}")
add_target_flag_if_avail(hosttrace-lto "-flto")
if(NOT cxx_hosttrace_lto_flto)
add_disabled_interface(hosttrace-lto)
set(hosttrace_BUILD_LTO OFF)
set(HOSTTRACE_BUILD_LTO OFF)
else()
target_link_options(hosttrace-lto INTERFACE -flto)
endif()
@@ -161,8 +156,9 @@ hosttrace_restore_variables(FLTO VARIABLES CMAKE_CXX_FLAGS)
# ----------------------------------------------------------------------------------------#
# print compilation timing reports (Clang compiler)
#
add_interface_library(hosttrace-compile-timing
"Adds compiler flags which report compilation timing metrics")
hosttrace_add_interface_library(
hosttrace-compile-timing
"Adds compiler flags which report compilation timing metrics")
if(CMAKE_CXX_COMPILER_IS_CLANG)
add_target_flag_if_avail(hosttrace-compile-timing "-ftime-trace")
if(NOT cxx_hosttrace_compile_timing_ftime_trace)
@@ -176,15 +172,10 @@ if(HOSTTRACE_USE_COMPILE_TIMING)
target_link_libraries(hosttrace-compile-options INTERFACE hosttrace-compile-timing)
endif()
if(NOT cxx_hosttrace_compile_timing_ftime_report
AND NOT cxx_hosttrace_compile_timing_ftime_trace)
add_disabled_interface(hosttrace-compile-timing)
endif()
# ----------------------------------------------------------------------------------------#
# developer build flags
#
add_interface_library(hosttrace-develop-options "Adds developer compiler flags")
hosttrace_add_interface_library(hosttrace-develop-options "Adds developer compiler flags")
if(HOSTTRACE_BUILD_DEVELOPER)
add_target_flag_if_avail(
hosttrace-develop-options
@@ -195,21 +186,15 @@ endif()
# ----------------------------------------------------------------------------------------#
# visibility build flags
#
add_interface_library(hosttrace-default-visibility
"Adds -fvisibility=default compiler flag")
add_interface_library(hosttrace-hidden-visibility
"Adds -fvisibility=hidden compiler flag")
hosttrace_add_interface_library(hosttrace-default-visibility
"Adds -fvisibility=default compiler flag")
hosttrace_add_interface_library(hosttrace-hidden-visibility
"Adds -fvisibility=hidden compiler flag")
add_target_flag_if_avail(hosttrace-default-visibility "-fvisibility=default")
add_target_flag_if_avail(hosttrace-hidden-visibility "-fvisibility=hidden"
"-fvisibility-inlines-hidden")
foreach(_TYPE default hidden)
if(NOT cxx_hosttrace_${_TYPE}_visibility_fvisibility_${_TYPE})
add_disabled_interface(hosttrace-${_TYPE}-visibility)
endif()
endforeach()
# ----------------------------------------------------------------------------------------#
# developer build flags
#
@@ -235,9 +220,9 @@ set(HOSTTRACE_SANITIZER_TYPES
alignment)
set_property(CACHE HOSTTRACE_SANITIZER_TYPE PROPERTY STRINGS
"${HOSTTRACE_SANITIZER_TYPES}")
add_interface_library(hosttrace-sanitizer-compile-options
"Adds compiler flags for sanitizers")
add_interface_library(
hosttrace_add_interface_library(hosttrace-sanitizer-compile-options
"Adds compiler flags for sanitizers")
hosttrace_add_interface_library(
hosttrace-sanitizer
"Adds compiler flags to enable ${HOSTTRACE_SANITIZER_TYPE} sanitizer (-fsanitizer=${HOSTTRACE_SANITIZER_TYPE})"
)
@@ -248,8 +233,9 @@ add_target_flag(hosttrace-sanitizer-compile-options ${COMMON_SANITIZER_FLAGS})
foreach(_TYPE ${HOSTTRACE_SANITIZER_TYPES})
set(_FLAG "-fsanitize=${_TYPE}")
add_interface_library(hosttrace-${_TYPE}-sanitizer
"Adds compiler flags to enable ${_TYPE} sanitizer (${_FLAG})")
hosttrace_add_interface_library(
hosttrace-${_TYPE}-sanitizer
"Adds compiler flags to enable ${_TYPE} sanitizer (${_FLAG})")
add_target_flag(hosttrace-${_TYPE}-sanitizer ${_FLAG})
target_link_libraries(hosttrace-${_TYPE}-sanitizer
INTERFACE hosttrace-sanitizer-compile-options)
@@ -273,7 +259,6 @@ if(HOSTTRACE_USE_SANITIZER)
endforeach()
else()
set(HOSTTRACE_USE_SANITIZER OFF)
inform_empty_interface(hosttrace-sanitizer "${HOSTTRACE_SANITIZER_TYPE} sanitizer")
endif()
if(MSVC)
@@ -31,8 +31,8 @@ if("${LIBNAME}" STREQUAL "")
string(TOLOWER "${PROJECT_NAME}" LIBNAME)
endif()
add_interface_library(${LIBNAME}-compile-options
"Adds the standard set of compiler flags used by timemory")
hosttrace_add_interface_library(
${LIBNAME}-compile-options "Adds the standard set of compiler flags used by timemory")
# ----------------------------------------------------------------------------------------#
# macro converting string to list
@@ -0,0 +1,60 @@
include_guard(DIRECTORY)
# ----------------------------------------------------------------------------------------#
#
# Clang Tidy
#
# ----------------------------------------------------------------------------------------#
# clang-tidy
macro(HOSTTRACE_ACTIVATE_CLANG_TIDY)
if(HOSTTRACE_USE_CLANG_TIDY)
find_program(CLANG_TIDY_COMMAND NAMES clang-tidy)
hosttrace_add_feature(CLANG_TIDY_COMMAND "Path to clang-tidy command")
if(NOT CLANG_TIDY_COMMAND)
timemory_message(
WARNING "HOSTTRACE_USE_CLANG_TIDY is ON but clang-tidy is not found!")
set(HOSTTRACE_USE_CLANG_TIDY OFF)
else()
set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_COMMAND})
# Create a preprocessor definition that depends on .clang-tidy content so the
# compile command will change when .clang-tidy changes. This ensures that a
# subsequent build re-runs clang-tidy on all sources even if they do not
# otherwise need to be recompiled. Nothing actually uses this definition. We
# add it to targets on which we run clang-tidy just to get the build
# dependency on the .clang-tidy file.
file(SHA1 ${CMAKE_CURRENT_LIST_DIR}/.clang-tidy clang_tidy_sha1)
set(CLANG_TIDY_DEFINITIONS "CLANG_TIDY_SHA1=${clang_tidy_sha1}")
unset(clang_tidy_sha1)
endif()
endif()
endmacro()
# ------------------------------------------------------------------------------#
#
# clang-format target
#
# ------------------------------------------------------------------------------#
find_program(HOSTTRACE_CLANG_FORMAT_EXE NAMES clang-format-11 clang-format-mp-11
clang-format)
if(HOSTTRACE_CLANG_FORMAT_EXE)
file(GLOB_RECURSE sources ${PROJECT_SOURCE_DIR}/src/*.cpp)
file(GLOB_RECURSE headers ${PROJECT_SOURCE_DIR}/include/*.hpp)
file(GLOB_RECURSE examples ${PROJECT_SOURCE_DIR}/examples/*.cpp
${PROJECT_SOURCE_DIR}/examples/*.hpp)
add_custom_target(
format-hosttrace
${HOSTTRACE_CLANG_FORMAT_EXE} -i ${sources} ${headers} ${examples}
COMMENT "Running C++ formatter ${HOSTTRACE_CLANG_FORMAT_EXE}...")
if(NOT TARGET format)
add_custom_target(format)
endif()
add_dependencies(format format-hosttrace)
else()
message(
AUTHOR_WARNING
"clang-format could not be found. format build target not available.")
endif()
تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است Diff را بارگزاری کن
تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است Diff را بارگزاری کن
@@ -100,10 +100,6 @@ if(roctracer_FOUND)
if(roctracer_kfdwrapper_LIBRARY)
list(APPEND roctracer_LIBRARIES ${roctracer_kfdwrapper_LIBRARY})
target_compile_definitions(
roctracer::roctracer
INTERFACE
HOSTTRACE_ROCTRACER_LIBKFDWRAPPER=\"${roctracer_kfdwrapper_LIBRARY}\")
target_link_libraries(roctracer::roctracer
INTERFACE ${roctracer_kfdwrapper_LIBRARY})
target_link_libraries(roctracer::roctx INTERFACE ${roctracer_kfdwrapper_LIBRARY})
@@ -7,14 +7,19 @@ include_guard(DIRECTORY)
#
# ########################################################################################
add_interface_library(hosttrace-headers
"Provides minimal set of include flags to compile with hosttrace")
add_interface_library(hosttrace-threading "Enables multithreading support")
add_interface_library(
hosttrace_add_interface_library(
hosttrace-headers "Provides minimal set of include flags to compile with hosttrace")
hosttrace_add_interface_library(hosttrace-threading "Enables multithreading support")
hosttrace_add_interface_library(
hosttrace-dyninst
"Provides flags and libraries for Dyninst (dynamic instrumentation)")
add_interface_library(hosttrace-roctracer "Provides flags and libraries for roctracer")
add_interface_library(hosttrace-mpi "Provides MPI or MPI headers")
hosttrace_add_interface_library(hosttrace-roctracer
"Provides flags and libraries for roctracer")
hosttrace_add_interface_library(hosttrace-mpi "Provides MPI or MPI headers")
hosttrace_add_interface_library(hosttrace-ptl "Enables PTL support (tasking)")
target_include_directories(hosttrace-headers INTERFACE ${PROJECT_SOURCE_DIR}/include
${PROJECT_BINARY_DIR}/include)
# include threading because of rooflines
target_link_libraries(hosttrace-headers INTERFACE hosttrace-threading)
@@ -80,7 +85,7 @@ endif()
# ----------------------------------------------------------------------------------------#
if(HOSTTRACE_BUILD_DYNINST)
checkout_git_submodule(
hosttrace_checkout_git_submodule(
RELATIVE_PATH external/dyninst
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
REPO_URL https://github.com/jrmadsen/dyninst.git
@@ -145,7 +150,7 @@ else()
hosttrace-dyninst INTERFACE DYNINST_API_RT="${HOSTTRACE_DYNINST_API_RT}")
endif()
add_rpath(${Dyninst_LIBRARIES})
hosttrace_add_rpath(${Dyninst_LIBRARIES})
target_link_libraries(hosttrace-dyninst INTERFACE Dyninst::Dyninst)
else() # updated Dyninst CMake system was not found
set(_BOOST_COMPONENTS atomic system thread date_time)
@@ -204,7 +209,7 @@ else()
endif()
endif()
add_rpath(${DYNINST_LIBRARIES} ${Boost_LIBRARIES})
hosttrace_add_rpath(${DYNINST_LIBRARIES} ${Boost_LIBRARIES})
target_link_libraries(hosttrace-dyninst INTERFACE ${DYNINST_LIBRARIES}
${Boost_LIBRARIES})
foreach(
@@ -242,7 +247,7 @@ endif()
# ----------------------------------------------------------------------------------------#
set(perfetto_DIR ${PROJECT_SOURCE_DIR}/external/perfetto)
checkout_git_submodule(
hosttrace_checkout_git_submodule(
RELATIVE_PATH external/perfetto
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
REPO_URL https://android.googlesource.com/platform/external/perfetto
@@ -256,7 +261,7 @@ checkout_git_submodule(
# ----------------------------------------------------------------------------------------#
if(HOSTTRACE_BUILD_DEVICETRACE)
checkout_git_submodule(
hosttrace_checkout_git_submodule(
RELATIVE_PATH external/elfio
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
REPO_URL https://github.com/jrmadsen/ELFIO.git
@@ -267,63 +272,10 @@ endif()
# ----------------------------------------------------------------------------------------#
#
# Clang Tidy
# timemory submodule
#
# ----------------------------------------------------------------------------------------#
# clang-tidy
macro(HOSTTRACE_ACTIVATE_CLANG_TIDY)
if(HOSTTRACE_USE_CLANG_TIDY)
find_program(CLANG_TIDY_COMMAND NAMES clang-tidy)
add_feature(CLANG_TIDY_COMMAND "Path to clang-tidy command")
if(NOT CLANG_TIDY_COMMAND)
timemory_message(
WARNING "HOSTTRACE_USE_CLANG_TIDY is ON but clang-tidy is not found!")
set(HOSTTRACE_USE_CLANG_TIDY OFF)
else()
set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_COMMAND})
# Create a preprocessor definition that depends on .clang-tidy content so the
# compile command will change when .clang-tidy changes. This ensures that a
# subsequent build re-runs clang-tidy on all sources even if they do not
# otherwise need to be recompiled. Nothing actually uses this definition. We
# add it to targets on which we run clang-tidy just to get the build
# dependency on the .clang-tidy file.
file(SHA1 ${CMAKE_CURRENT_LIST_DIR}/.clang-tidy clang_tidy_sha1)
set(CLANG_TIDY_DEFINITIONS "CLANG_TIDY_SHA1=${clang_tidy_sha1}")
unset(clang_tidy_sha1)
endif()
endif()
endmacro()
# ------------------------------------------------------------------------------#
#
# clang-format target
#
# ------------------------------------------------------------------------------#
find_program(HOSTTRACE_CLANG_FORMAT_EXE NAMES clang-format-11 clang-format-mp-11
clang-format)
if(HOSTTRACE_CLANG_FORMAT_EXE)
file(GLOB sources ${PROJECT_SOURCE_DIR}/src/*.cpp)
file(GLOB headers ${PROJECT_SOURCE_DIR}/include/*.hpp)
file(GLOB_RECURSE examples ${PROJECT_SOURCE_DIR}/examples/*.cpp
${PROJECT_SOURCE_DIR}/examples/*.hpp)
add_custom_target(
format
${HOSTTRACE_CLANG_FORMAT_EXE} -i ${sources} ${headers} ${examples}
COMMENT "Running ${HOSTTRACE_CLANG_FORMAT_EXE}...")
else()
message(
AUTHOR_WARNING
"clang-format could not be found. format build target not available.")
endif()
# ----------------------------------------------------------------------------------------#
# configure submodule
# ----------------------------------------------------------------------------------------#
set(TIMEMORY_INSTALL_HEADERS
OFF
CACHE BOOL "Disable timemory header install")
@@ -365,7 +317,7 @@ set(TIMEMORY_TLS_MODEL
"global-dynamic"
CACHE STRING "Thread-local static model" FORCE)
checkout_git_submodule(
hosttrace_checkout_git_submodule(
RELATIVE_PATH external/timemory
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
REPO_URL https://github.com/NERSC/timemory.git
@@ -384,3 +336,41 @@ add_subdirectory(external/timemory)
hosttrace_restore_variables(BUILD_CONFIG VARIABLES BUILD_SHARED_LIBS BUILD_STATIC_LIBS
CMAKE_POSITION_INDEPENDENT_CODE)
# ----------------------------------------------------------------------------------------#
#
# PTL (Parallel Tasking Library) submodule
#
# ----------------------------------------------------------------------------------------#
# timemory might provide PTL::ptl-shared
if(NOT TARGET PTL::ptl-shared)
hosttrace_checkout_git_submodule(
RELATIVE_PATH external/PTL
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
REPO_URL https://github.com/jrmadsen/PTL.git
REPO_BRANCH master)
set(PTL_BUILD_EXAMPLES OFF)
set(PTL_USE_TBB OFF)
set(PTL_USE_GPU OFF)
set(PTL_DEVELOPER_INSTALL OFF)
hosttrace_save_variables(
BUILD_CONFIG
VARIABLES BUILD_SHARED_LIBS BUILD_STATIC_LIBS CMAKE_POSITION_INDEPENDENT_CODE
CMAKE_CXX_VISIBILITY_PRESET CMAKE_VISIBILITY_INLINES_HIDDEN)
set(BUILD_SHARED_LIBS ON)
set(BUILD_STATIC_LIBS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
add_subdirectory(external/PTL)
hosttrace_restore_variables(
BUILD_CONFIG
VARIABLES BUILD_SHARED_LIBS BUILD_STATIC_LIBS CMAKE_POSITION_INDEPENDENT_CODE
CMAKE_CXX_VISIBILITY_PRESET CMAKE_VISIBILITY_INLINES_HIDDEN)
endif()
target_link_libraries(hosttrace-ptl INTERFACE PTL::ptl-shared)
@@ -38,7 +38,10 @@ main(int argc, char** argv)
std::vector<std::thread> threads{};
for(size_t i = 0; i < nthread; ++i)
threads.emplace_back(&run, nitr, nfib);
{
size_t _nitr = ((i % 2) == 1) ? (nitr - (0.1 * nitr)) : (nitr + (0.1 * nitr));
threads.emplace_back(&run, _nitr, nfib);
}
for(auto& itr : threads)
itr.join();
@@ -29,6 +29,7 @@ THE SOFTWARE.
#include <fstream>
#include <iomanip>
#include <iostream>
#include <thread>
#include <vector>
#define HIP_API_CALL(CALL) \
@@ -88,8 +89,8 @@ run(int rank, int argc, char** argv)
{
(void) argc;
(void) argv;
unsigned int M = 4960;
unsigned int N = 4960;
unsigned int M = 4960 * 2;
unsigned int N = 4960 * 2;
std::cout << "[" << rank << "] M: " << M << " N: " << N << std::endl;
size_t size = sizeof(int) * M * N;
@@ -102,29 +103,30 @@ run(int rank, int argc, char** argv)
HIP_API_CALL(hipMalloc(&in, size));
HIP_API_CALL(hipMalloc(&out, size));
check_hip_error();
HIP_API_CALL(hipMemset(in, 0, size));
HIP_API_CALL(hipMemset(out, 0, size));
HIP_API_CALL(hipMemcpy(in, matrix, size, hipMemcpyHostToDevice));
HIP_API_CALL(hipDeviceSynchronize());
check_hip_error();
hipDeviceProp_t props;
HIP_API_CALL(hipGetDeviceProperties(&props, 0));
dim3 grid(M / 32, N / 32, 1);
dim3 block(32, 32, 1); // transpose_a
// warmup
hipLaunchKernelGGL(transpose_a, grid, block, 0, 0, in, out, M, N);
check_hip_error();
t1 = std::chrono::high_resolution_clock::now();
const unsigned times = 10000;
for(size_t i = 0; i < times; i++)
{
hipLaunchKernelGGL(transpose_a, grid, block, 0, 0, in, out, M, N);
}
check_hip_error();
auto _func = [&](hipStream_t stream) {
for(size_t i = 0; i < times / 2; i++)
{
transpose_a<<<grid, block, 0, stream>>>(in, out, M, N);
check_hip_error();
}
HIP_API_CALL(hipStreamSynchronize(stream));
};
hipStream_t _stream{};
HIP_API_CALL(hipStreamCreate(&_stream));
std::thread _t{ _func, _stream };
_t.join();
_func(0);
HIP_API_CALL(hipDeviceSynchronize());
t2 = std::chrono::high_resolution_clock::now();
double time =
@@ -136,14 +138,12 @@ run(int rank, int argc, char** argv)
int* out_matrix = (int*) malloc(size);
HIP_API_CALL(hipMemcpy(out_matrix, out, size, hipMemcpyDeviceToHost));
check_hip_error();
// cpu_transpose(matrix, out_matrix, M, N);
verify(matrix, out_matrix, M, N);
HIP_API_CALL(hipFree(in));
HIP_API_CALL(hipFree(out));
check_hip_error();
free(matrix);
free(out_matrix);
@@ -171,12 +171,32 @@ do_a2a(int rank)
int
main(int argc, char** argv)
{
int rank = 0;
int rank = 0;
int nthreads = 2;
if(argc > 1) nthreads = atoi(argv[1]);
#if defined(USE_MPI)
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
#endif
if(rank == 0) run(rank, argc, argv);
// this is a temporary workaround in hosttrace when HIP + MPI is enabled
int ndevice = 0;
int devid = rank;
HIP_API_CALL(hipGetDeviceCount(&ndevice));
if(ndevice > 0)
{
devid = rank % ndevice;
HIP_API_CALL(hipSetDevice(devid));
}
if(rank == devid && rank < ndevice)
{
std::vector<std::thread> _threads{};
for(int i = 1; i < nthreads; ++i)
_threads.emplace_back(run, rank, argc, argv);
run(rank, argc, argv);
for(auto& itr : _threads)
itr.join();
}
#if defined(USE_MPI)
MPI_Barrier(MPI_COMM_WORLD);
do_a2a(rank);
فروخته شده Submodule
+1
Submodule projects/rocprofiler-systems/external/PTL added at dd1b67829c
Submodule projects/rocprofiler-systems/external/timemory updated: 11183bbdd7...c040fe7022
@@ -1,27 +1,30 @@
// MIT License
//
// Copyright (c) 2020, The Regents of the University of California,
// through Lawrence Berkeley National Laboratory (subject to receipt of any
// required approvals from the U.S. Dept. of Energy). All rights reserved.
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
@@ -274,7 +277,7 @@ struct function_signature
bool m_info_end = false;
location_t m_row = { 0, 0 };
location_t m_col = { 0, 0 };
string_t m_return = "void";
string_t m_return = {};
string_t m_name = {};
string_t m_params = "()";
string_t m_file = {};
@@ -318,7 +321,7 @@ struct function_signature
string_t get() const
{
std::stringstream ss;
if(use_return_info) ss << m_return << " ";
if(use_return_info && !m_return.empty()) ss << m_return << " ";
ss << m_name;
if(use_args_info) ss << m_params;
if(m_loop && m_info_beg)
@@ -1,275 +1,112 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#if !defined(TIMEMORY_USE_PERFETTO)
# include <perfetto.h>
# define PERFETTO_CATEGORIES \
perfetto::Category("host").SetDescription("Host-side function tracing"), \
perfetto::Category("device").SetDescription("Device-side function tracing")
#else
# define PERFETTO_CATEGORIES \
perfetto::Category("host").SetDescription("Host-side function tracing"), \
perfetto::Category("device").SetDescription("Device-side function tracing")
perfetto::Category("timemory")
.SetDescription("Events from the timemory API")
# define TIMEMORY_PERFETTO_CATEGORIES PERFETTO_CATEGORIES
#endif
// this always needs to included first
// clang-format off
#include "library/perfetto.hpp"
// clang-format on
#include "library/timemory.hpp"
#include "library/roctracer.hpp"
#include "library/api.hpp"
#include "library/fork_gotcha.hpp"
#include "library/mpi_gotcha.hpp"
#include "library/api.hpp"
#include "library/common.hpp"
#include "library/state.hpp"
#include "library/config.hpp"
#include "library/thread_data.hpp"
#include "library/ptl.hpp"
#include "library/debug.hpp"
#include "library/critical_trace.hpp"
#include "timemory/macros/language.hpp"
#include "timemory/utility/utility.hpp"
#include <cassert>
#include <cstdint>
#include <cstdio>
#include <fstream>
#include <memory>
#include <mutex>
#include <string>
#include <sys/types.h>
#include <thread>
#include <unistd.h>
#include <utility>
#include <vector>
#include "timemory/api.hpp"
#include "timemory/backends/mpi.hpp"
#include "timemory/backends/process.hpp"
#include "timemory/backends/threading.hpp"
#include "timemory/components.hpp"
#include "timemory/components/gotcha/mpip.hpp"
#include "timemory/components/papi/papi_tuple.hpp"
#include "timemory/config.hpp"
#include "timemory/environment.hpp"
#include "timemory/manager.hpp"
#include "timemory/mpl/apply.hpp"
#include "timemory/operations.hpp"
#include "timemory/runtime.hpp"
#include "timemory/settings.hpp"
#include "timemory/storage.hpp"
#include "timemory/variadic.hpp"
#include "roctracer.hpp"
// forward decl of the API
extern "C"
template <critical_trace::Device DevID, critical_trace::Phase PhaseID,
bool UpdateStack = true>
inline void
add_critical_trace(int64_t _tid, size_t _cpu_cid, size_t _gpu_cid, size_t _parent_cid,
int64_t _ts_beg, int64_t _ts_val, size_t _hash, uint16_t _depth,
uint16_t _prio = 0)
{
void hosttrace_push_trace(const char* name) TIMEMORY_VISIBILITY("default");
void hosttrace_pop_trace(const char* name) TIMEMORY_VISIBILITY("default");
void hosttrace_trace_init(const char*, bool, const char*)
TIMEMORY_VISIBILITY("default");
void hosttrace_trace_finalize(void) TIMEMORY_VISIBILITY("default");
void hosttrace_trace_set_env(const char* env_name, const char* env_val)
TIMEMORY_VISIBILITY("default");
void hosttrace_trace_set_mpi(bool use, bool attached) TIMEMORY_VISIBILITY("default");
}
if(!get_use_critical_trace()) return;
//--------------------------------------------------------------------------------------//
// clang-format off
// these are used to create unique type mutexes
struct critical_insert {};
struct cpu_cid_stack {};
// clang-format on
// same sort of functionality as python's " ".join([...])
#if !defined(JOIN)
# define JOIN(...) tim::mpl::apply<std::string>::join(__VA_ARGS__)
#endif
using tim::type_mutex;
using auto_lock_t = tim::auto_lock_t;
static constexpr auto num_mutexes = max_supported_threads;
static auto _update_freq = critical_trace::get_update_frequency();
#define HOSTTRACE_DEBUG(...) \
if(get_debug()) \
{ \
fprintf(stderr, __VA_ARGS__); \
fflush(stderr); \
}
//--------------------------------------------------------------------------------------//
namespace audit = tim::audit;
namespace comp = tim::component;
namespace quirk = tim::quirk;
namespace threading = tim::threading;
namespace scope = tim::scope;
namespace dmp = tim::dmp;
namespace process = tim::process;
namespace units = tim::units;
namespace trait = tim::trait;
// this is used to wrap fork()
struct fork_gotcha : comp::base<fork_gotcha, void>
{
using gotcha_data_t = comp::gotcha_data;
TIMEMORY_DEFAULT_OBJECT(fork_gotcha)
// this will get called right before fork
void audit(const gotcha_data_t& _data, audit::incoming);
// this will get called right after fork with the return value
void audit(const gotcha_data_t& _data, audit::outgoing, pid_t _pid);
};
// this is used to wrap MPI_Init and MPI_Init_thread
struct mpi_gotcha : comp::base<mpi_gotcha, void>
{
using gotcha_data_t = comp::gotcha_data;
TIMEMORY_DEFAULT_OBJECT(mpi_gotcha)
// this will get called right before MPI_Init with that functions arguments
void audit(const gotcha_data_t& _data, audit::incoming, int*, char***);
// this will get called right before MPI_Init_thread with that functions arguments
void audit(const gotcha_data_t& _data, audit::incoming, int*, char***, int, int*);
// this will get called right after MPI_Init and MPI_Init_thread with the return value
void audit(const gotcha_data_t& _data, audit::outgoing, int _retval);
// this will get called right before MPI_Finalize
void audit(const gotcha_data_t& _data, audit::incoming);
};
// timemory api struct
struct hosttrace : tim::concepts::api
{};
// timemory component which calls hosttrace functions
// (used in gotcha wrappers)
struct hosttrace_component : tim::component::base<hosttrace_component, void>
{
void start();
void stop();
void set_prefix(const char*);
private:
const char* m_prefix = nullptr;
};
using papi_tot_ins = comp::papi_tuple<PAPI_TOT_INS>;
using fork_gotcha_t = comp::gotcha<4, tim::component_tuple<fork_gotcha>, hosttrace>;
using mpi_gotcha_t = comp::gotcha<4, tim::component_tuple<mpi_gotcha>, hosttrace>;
using hosttrace_bundle_t =
tim::lightweight_tuple<comp::wall_clock, comp::peak_rss, comp::cpu_clock,
comp::cpu_util, comp::roctracer, papi_tot_ins,
comp::user_global_bundle, fork_gotcha_t, mpi_gotcha_t>;
using hosttrace_thread_bundle_t =
tim::lightweight_tuple<comp::wall_clock, comp::thread_cpu_clock,
comp::thread_cpu_util, papi_tot_ins>;
using bundle_t =
tim::component_bundle<hosttrace, comp::wall_clock*, comp::user_global_bundle*>;
using bundle_allocator_t = tim::data::ring_buffer_allocator<bundle_t>;
//--------------------------------------------------------------------------------------//
#if !defined(TIMEMORY_USE_PERFETTO)
PERFETTO_DEFINE_CATEGORIES(PERFETTO_CATEGORIES);
#endif
#if defined(CUSTOM_DATA_SOURCE)
class CustomDataSource : public perfetto::DataSource<CustomDataSource>
{
public:
void OnSetup(const SetupArgs&) override
if constexpr(PhaseID != critical_trace::Phase::NONE)
{
// Use this callback to apply any custom configuration to your data source
// based on the TraceConfig in SetupArgs.
PRINT_HERE("%s", "setup");
// unique lock per thread
auto& _mtx = type_mutex<critical_insert, hosttrace, num_mutexes>(_tid);
auto_lock_t _lk{ _mtx };
auto& _critical_trace = critical_trace::get(_tid);
_critical_trace->emplace_back(
critical_trace::entry{ _prio, DevID, PhaseID, _depth, _tid, _cpu_cid,
_gpu_cid, _parent_cid, _ts_beg, _ts_val, _hash });
}
void OnStart(const StartArgs&) override
if constexpr(UpdateStack)
{
// This notification can be used to initialize the GPU driver, enable
// counters, etc. StartArgs will contains the DataSourceDescriptor,
// which can be extended.
PRINT_HERE("%s", "start");
// unique lock per thread
auto& _mtx = type_mutex<cpu_cid_stack, hosttrace, num_mutexes>(_tid);
if constexpr(PhaseID == critical_trace::Phase::NONE)
{
auto_lock_t _lk{ _mtx };
get_cpu_cid_stack(_tid)->emplace_back(_cpu_cid);
}
else if constexpr(PhaseID == critical_trace::Phase::BEGIN)
{
auto_lock_t _lk{ _mtx };
get_cpu_cid_stack(_tid)->emplace_back(_cpu_cid);
}
else if constexpr(PhaseID == critical_trace::Phase::END)
{
auto_lock_t _lk{ _mtx };
get_cpu_cid_stack(_tid)->pop_back();
if(_gpu_cid == 0 && _cpu_cid % _update_freq == (_update_freq - 1))
critical_trace::update(_tid);
}
}
void OnStop(const StopArgs&) override
{
// Undo any initialization done in OnStart.
PRINT_HERE("%s", "stop");
}
// Data sources can also have per-instance state.
int my_custom_state = 0;
};
PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(CustomDataSource);
#endif
//--------------------------------------------------------------------------------------//
// used for specifying the state of hosttrace
enum class State : unsigned short
{
DelayedInit = 0,
PreInit,
Active,
Finalized
};
bool
get_debug();
State&
get_state();
std::unique_ptr<hosttrace_bundle_t>&
get_main_bundle();
bool
get_use_perfetto();
bool
get_use_timemory();
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t MaxThreads = 1024>
struct hosttrace_thread_data
{
static constexpr size_t max_supported_threads = MaxThreads;
using instance_array_t = std::array<std::unique_ptr<Tp>, max_supported_threads>;
template <typename... Args>
static void construct(Args&&...);
static std::unique_ptr<Tp>& instance();
static instance_array_t& instances();
};
template <typename Tp, size_t MaxThreads>
template <typename... Args>
void
hosttrace_thread_data<Tp, MaxThreads>::construct(Args&&... _args)
{
static thread_local bool _v = [&_args...]() {
instances().at(threading::get_id()) =
std::make_unique<Tp>(std::forward<Args>(_args)...);
return true;
}();
(void) _v;
tim::consume_parameters(_tid, _cpu_cid, _gpu_cid, _parent_cid, _ts_beg, _ts_val,
_hash, _depth, _prio);
}
template <typename Tp, size_t MaxThreads>
std::unique_ptr<Tp>&
hosttrace_thread_data<Tp, MaxThreads>::instance()
{
return instances().at(threading::get_id());
}
template <typename Tp, size_t MaxThreads>
typename hosttrace_thread_data<Tp, MaxThreads>::instance_array_t&
hosttrace_thread_data<Tp, MaxThreads>::instances()
{
static auto _v = instance_array_t{};
return _v;
}
//--------------------------------------------------------------------------------------//
// there are currently some strange things that happen with vector<bundle_t> so using
// vector<bundle_t*> and timemory's ring_buffer_allocator to create contiguous memory-page
// aligned instances of the bundle
struct hosttrace_timemory_data
{
static constexpr size_t max_supported_threads = 1024;
using instance_array_t = std::array<hosttrace_timemory_data, max_supported_threads>;
bundle_allocator_t allocator{};
std::vector<bundle_t*> bundles{};
static instance_array_t& instances();
};
//--------------------------------------------------------------------------------------//
@@ -0,0 +1,44 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include <timemory/compat/macros.h>
// forward decl of the API
extern "C"
{
void hosttrace_push_trace(const char* name) TIMEMORY_VISIBILITY("default");
void hosttrace_pop_trace(const char* name) TIMEMORY_VISIBILITY("default");
void hosttrace_trace_init(const char*, bool, const char*)
TIMEMORY_VISIBILITY("default");
void hosttrace_trace_finalize(void) TIMEMORY_VISIBILITY("default");
void hosttrace_trace_set_env(const char* env_name, const char* env_val)
TIMEMORY_VISIBILITY("default");
void hosttrace_trace_set_mpi(bool use, bool attached) TIMEMORY_VISIBILITY("default");
}
@@ -0,0 +1,50 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include <timemory/api.hpp>
#include <timemory/backends/dmp.hpp>
#include <timemory/backends/process.hpp>
#include <cassert>
#include <cstdint>
#include <cstdio>
#include <fstream>
#include <memory>
#include <mutex>
#include <string>
#include <sys/types.h>
#include <thread>
#include <unistd.h>
#include <utility>
#include <vector>
// timemory api struct
struct hosttrace : tim::concepts::api
{};
@@ -0,0 +1,163 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include "library/api.hpp"
#include "library/common.hpp"
#include "library/fork_gotcha.hpp"
#include "library/mpi_gotcha.hpp"
#include "library/roctracer.hpp"
#include "library/state.hpp"
#include "library/timemory.hpp"
#include <timemory/backends/threading.hpp>
#include <string_view>
// bundle of components around hosttrace_init and hosttrace_finalize
using main_bundle_t =
tim::lightweight_tuple<comp::wall_clock, comp::peak_rss, comp::cpu_clock,
comp::cpu_util, comp::roctracer, papi_tot_ins,
comp::user_global_bundle, fork_gotcha_t, mpi_gotcha_t>;
// bundle of components used in instrumentation
using instrumentation_bundle_t =
tim::component_bundle<hosttrace, comp::wall_clock*, comp::user_global_bundle*>;
// allocator for instrumentation_bundle_t
using bundle_allocator_t = tim::data::ring_buffer_allocator<instrumentation_bundle_t>;
// bundle of components around each thread
using hosttrace_thread_bundle_t =
tim::lightweight_tuple<comp::wall_clock, comp::thread_cpu_clock,
comp::thread_cpu_util,
#if defined(TIMEMORY_RUSAGE_THREAD) && TIMEMORY_RUSAGE_THREAD > 0
comp::peak_rss,
#endif
papi_tot_ins>;
//
// Initialization routines
//
void
configure_settings();
void
print_config_settings(std::ostream& _os,
std::function<bool(const std::string_view&)>&& _filter);
std::string&
get_exe_name();
//
// User-configurable settings
//
std::string
get_config_file();
bool
get_debug();
bool
get_use_perfetto();
bool
get_use_timemory();
bool&
get_use_pid();
bool
get_use_mpip();
bool
get_use_critical_trace();
bool
get_roctracer_timeline_profile();
bool
get_roctracer_flat_profile();
bool
get_trace_hsa_api();
bool
get_trace_hsa_activity();
bool
get_critical_trace_debug();
bool
get_critical_trace_serialize_names();
size_t
get_perfetto_shmem_size_hint();
size_t
get_perfetto_buffer_size();
uint64_t
get_critical_trace_update_freq();
uint64_t
get_critical_trace_num_threads();
std::string
get_trace_hsa_api_types();
std::string&
get_backend();
std::string
get_perfetto_output_filename();
int64_t
get_critical_trace_count();
size_t&
get_sample_rate();
int64_t
get_critical_trace_per_row();
//
// Runtime configuration data
//
State&
get_state();
std::unique_ptr<main_bundle_t>&
get_main_bundle();
std::atomic<uint64_t>&
get_cpu_cid();
std::unique_ptr<std::vector<uint64_t>>&
get_cpu_cid_stack(int64_t _tid = threading::get_id());
@@ -0,0 +1,209 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include "library/config.hpp"
#include "library/thread_data.hpp"
#include "timemory/tpls/cereal/cereal/cereal.hpp"
#include <cstdint>
#include <cstdlib>
#include <ostream>
#include <string>
#include <vector>
namespace critical_trace
{
enum class Device : short
{
NONE = 0,
CPU,
GPU,
};
enum class Phase : short
{
NONE = 0,
BEGIN,
END,
DELTA,
};
struct entry
{
entry() = default;
~entry() = default;
entry(const entry&) = default;
entry(entry&&) noexcept = default;
entry& operator=(const entry&) = default;
entry& operator=(entry&&) noexcept = default;
uint16_t priority = 0; // priority value (for sorting)
Device device = Device::CPU; // which device it executed on
Phase phase = Phase::NONE; // start / stop / unspecified
uint16_t depth = 0; // call-stack depth
int64_t tid = 0; // thread id it was registered on
uint64_t cpu_cid = 0; // CPU correlation id
uint64_t gpu_cid = 0; // GPU correlation id
uint64_t parent_cid = 0; // parent CPU correlation id
int64_t begin_ns = 0; // timestamp of start
int64_t end_ns = 0; // timestamp of end
size_t hash = 0; // hash for name
bool operator==(const entry& rhs) const;
bool operator!=(const entry& rhs) const { return !(*this == rhs); }
bool operator<(const entry& rhs) const;
bool operator>(const entry& rhs) const;
bool operator<=(const entry& rhs) const { return !(*this > rhs); }
bool operator>=(const entry& rhs) const { return !(*this < rhs); }
entry& operator+=(const entry& rhs);
size_t get_hash() const;
int64_t get_timestamp() const;
int64_t get_cost() const;
bool is_bounded(const entry& rhs) const;
int64_t get_overlap(const entry& rhs) const;
int64_t get_independent(const entry& rhs) const;
int64_t get_overlap(const entry& rhs, int64_t _tid) const;
int64_t get_independent(const entry& rhs, int64_t _tid) const;
bool is_bounded(const entry& rhs, int64_t _tid) const;
void write(std::ostream& _os) const;
static bool is_delta(const entry&, const std::string_view&);
friend std::ostream& operator<<(std::ostream& _os, const entry& _v)
{
_v.write(_os);
return _os;
}
template <typename Archive>
void serialize(Archive& ar, unsigned int);
};
template <typename Archive>
void
entry::serialize(Archive& ar, unsigned int)
{
namespace cereal = tim::cereal;
ar(cereal::make_nvp("priority", priority), cereal::make_nvp("device", device),
cereal::make_nvp("phase", phase), cereal::make_nvp("depth", depth),
cereal::make_nvp("tid", tid), cereal::make_nvp("cpu_cid", cpu_cid),
cereal::make_nvp("gpu_cid", gpu_cid), cereal::make_nvp("parent_cid", parent_cid),
cereal::make_nvp("begin_ns", begin_ns), cereal::make_nvp("end_ns", end_ns),
cereal::make_nvp("hash", hash));
if(get_critical_trace_serialize_names())
{
std::string _name{};
if(hash > 0) _name = tim::demangle(tim::get_hash_identifier(hash));
ar(cereal::make_nvp("name", _name));
}
}
struct call_chain : private std::vector<entry>
{
using base_type = std::vector<entry>;
using base_type::at;
using base_type::back;
using base_type::begin;
using base_type::cbegin;
using base_type::cend;
using base_type::clear;
using base_type::emplace_back;
using base_type::empty;
using base_type::end;
using base_type::erase;
using base_type::front;
using base_type::pop_back;
using base_type::push_back;
using base_type::rbegin;
using base_type::rend;
using base_type::reserve;
using base_type::size;
size_t get_hash() const;
int64_t get_cost(int64_t _tid = -1) const;
int64_t get_overlap(int64_t _tid = -1) const;
int64_t get_independent(int64_t _tid = -1) const;
static std::vector<call_chain>& get_top_chains();
bool operator==(const call_chain& rhs) const;
bool operator!=(const call_chain& rhs) const { return !(*this == rhs); }
friend std::ostream& operator<<(std::ostream& _os, const call_chain& _v)
{
size_t _n = 0;
for(const auto& itr : _v)
_os << " [" << _n++ << "] " << itr << "\n";
return _os;
}
template <typename Archive>
void serialize(Archive& ar, unsigned int)
{
namespace cereal = tim::cereal;
ar(cereal::make_nvp("call_chain", static_cast<base_type&>(*this)));
}
template <Device DevT>
void generate_perfetto(std::set<entry>& _used) const;
template <bool BoolV = true, typename FuncT>
bool query(FuncT&&) const;
};
using hash_ids = std::unordered_set<std::string>;
uint64_t
get_update_frequency();
std::unique_ptr<call_chain>&
get(int64_t _tid = threading::get_id());
size_t
add_hash_id(const std::string& _label);
void
add_hash_id(const hash_ids&);
void
update(int64_t _tid = threading::get_id());
void
compute(int64_t _tid = threading::get_id());
struct id
{};
} // namespace critical_trace
@@ -0,0 +1,80 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include <cstdio>
#include <timemory/api.hpp>
#include <timemory/backends/dmp.hpp>
#include <timemory/backends/process.hpp>
#include <timemory/utility/utility.hpp>
bool
get_debug();
bool
get_critical_trace_debug();
#if defined(TIMEMORY_USE_MPI)
# define HOSTTRACE_CONDITIONAL_PRINT(COND, ...) \
if(COND) \
{ \
fflush(stderr); \
tim::auto_lock_t _lk{ tim::type_mutex<decltype(std::cerr)>() }; \
fprintf(stderr, "[hosttrace][%i][%li] ", static_cast<int>(tim::dmp::rank()), \
tim::threading::get_id()); \
fprintf(stderr, __VA_ARGS__); \
fflush(stderr); \
}
#else
# define HOSTTRACE_CONDITIONAL_PRINT(COND, ...) \
if(COND) \
{ \
fflush(stderr); \
tim::auto_lock_t _lk{ tim::type_mutex<decltype(std::cerr)>() }; \
fprintf(stderr, "[hosttrace][%i][%li] ", \
static_cast<int>(tim::process::get_id()), tim::threading::get_id()); \
fprintf(stderr, __VA_ARGS__); \
fflush(stderr); \
}
#endif
#define HOSTTRACE_CONDITIONAL_BASIC_PRINT(COND, ...) \
if(COND) \
{ \
fflush(stderr); \
tim::auto_lock_t _lk{ tim::type_mutex<decltype(std::cerr)>() }; \
fprintf(stderr, "[hosttrace] "); \
fprintf(stderr, __VA_ARGS__); \
fflush(stderr); \
}
#define HOSTTRACE_DEBUG(...) HOSTTRACE_CONDITIONAL_PRINT(get_debug(), __VA_ARGS__)
#define HOSTTRACE_PRINT(...) HOSTTRACE_CONDITIONAL_PRINT(true, __VA_ARGS__)
#define HOSTTRACE_CT_DEBUG(...) \
HOSTTRACE_CONDITIONAL_PRINT(get_critical_trace_debug(), __VA_ARGS__)
@@ -0,0 +1,42 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
// clang-format off
#define HOSTTRACE_HIP_VERSION_STRING "@HIP_VERSION@"
#define HOSTTRACE_HIP_VERSION_MAJOR @HIP_VERSION_MAJOR@
#define HOSTTRACE_HIP_VERSION_MINOR @HIP_VERSION_MINOR@
#define HOSTTRACE_HIP_VERSION_PATCH @HIP_VERSION_PATCH@
// clang-format on
#if defined(HOSTTRACE_USE_ROCTRACER)
# define HOSTTRACE_ROCTRACER_LIBKFDWRAPPER "@roctracer_kfdwrapper_LIBRARY@"
#else
# define HOSTTRACE_ROCTRACER_LIBKFDWRAPPER "/opt/rocm/roctracer/lib/libkfdwrapper64.so"
#endif
@@ -0,0 +1,71 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include "library/debug.hpp"
#include <dlfcn.h>
#include <string>
#include <timemory/environment.hpp>
struct dynamic_library
{
dynamic_library() = delete;
dynamic_library(const dynamic_library&) = delete;
dynamic_library(dynamic_library&&) noexcept = default;
dynamic_library& operator=(const dynamic_library&) = delete;
dynamic_library& operator=(dynamic_library&&) noexcept = default;
dynamic_library(const char* _env, const char* _fname,
int _flags = (RTLD_NOW | RTLD_GLOBAL), bool _store = false)
: envname{ _env }
, filename{ tim::get_env<std::string>(_env, _fname, _store) }
, flags{ _flags }
{
if(!filename.empty())
{
handle = dlopen(filename.c_str(), flags);
if(!handle)
{
HOSTTRACE_DEBUG("%s\n", dlerror());
}
dlerror(); // Clear any existing error
}
}
~dynamic_library()
{
if(handle) dlclose(handle);
}
std::string envname = {};
std::string filename = {};
int flags = 0;
void* handle = nullptr;
};
@@ -0,0 +1,48 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include "library/common.hpp"
#include "library/timemory.hpp"
// this is used to wrap fork()
struct fork_gotcha : comp::base<fork_gotcha, void>
{
using gotcha_data_t = comp::gotcha_data;
TIMEMORY_DEFAULT_OBJECT(fork_gotcha)
// this will get called right before fork
void audit(const gotcha_data_t& _data, audit::incoming);
// this will get called right after fork with the return value
void audit(const gotcha_data_t& _data, audit::outgoing, pid_t _pid);
};
using fork_gotcha_t = comp::gotcha<4, tim::component_tuple<fork_gotcha>, hosttrace>;
@@ -0,0 +1,43 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include "library/timemory.hpp"
// timemory component which calls hosttrace functions
// (used in gotcha wrappers)
struct hosttrace_component : comp::base<hosttrace_component, void>
{
void start();
void stop();
void set_prefix(const char*);
private:
const char* m_prefix = nullptr;
};
@@ -0,0 +1,54 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include "library/common.hpp"
#include "library/timemory.hpp"
// this is used to wrap MPI_Init and MPI_Init_thread
struct mpi_gotcha : comp::base<mpi_gotcha, void>
{
using gotcha_data_t = comp::gotcha_data;
TIMEMORY_DEFAULT_OBJECT(mpi_gotcha)
// this will get called right before MPI_Init with that functions arguments
void audit(const gotcha_data_t& _data, audit::incoming, int*, char***);
// this will get called right before MPI_Init_thread with that functions arguments
void audit(const gotcha_data_t& _data, audit::incoming, int*, char***, int, int*);
// this will get called right after MPI_Init and MPI_Init_thread with the return value
void audit(const gotcha_data_t& _data, audit::outgoing, int _retval);
// this will get called right before MPI_Finalize
void audit(const gotcha_data_t& _data, audit::incoming);
};
using mpi_gotcha_t = comp::gotcha<4, tim::component_tuple<mpi_gotcha>, hosttrace>;
@@ -0,0 +1,91 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#if defined(PERFETTO_CATEGORIES)
# error "PERFETTO_CATEGORIES is already defined. Please include \"" __FILE__ "\" before including any timemory files"
#endif
#if !defined(TIMEMORY_USE_PERFETTO)
# include <perfetto.h>
# define PERFETTO_CATEGORIES \
perfetto::Category("host").SetDescription("Host-side function tracing"), \
perfetto::Category("device").SetDescription("Device-side function tracing"), \
perfetto::Category("host-critical-trace") \
.SetDescription("Host-side critical traces"), \
perfetto::Category("device-critical-trace") \
.SetDescription("Device-side critical traces")
#else
# define PERFETTO_CATEGORIES \
perfetto::Category("host").SetDescription("Host-side function tracing"), \
perfetto::Category("device").SetDescription("Device-side function tracing"), \
perfetto::Category("host-critical-trace") \
.SetDescription("Host-side critical traces"), \
perfetto::Category("device-critical-trace") \
.SetDescription("Device-side critical traces"), \
perfetto::Category("timemory") \
.SetDescription("Events from the timemory API")
# define TIMEMORY_PERFETTO_CATEGORIES PERFETTO_CATEGORIES
#endif
#if !defined(TIMEMORY_USE_PERFETTO)
PERFETTO_DEFINE_CATEGORIES(PERFETTO_CATEGORIES);
#endif
#if defined(CUSTOM_DATA_SOURCE)
class CustomDataSource : public perfetto::DataSource<CustomDataSource>
{
public:
void OnSetup(const SetupArgs&) override
{
// Use this callback to apply any custom configuration to your data source
// based on the TraceConfig in SetupArgs.
PRINT_HERE("%s", "setup");
}
void OnStart(const StartArgs&) override
{
// This notification can be used to initialize the GPU driver, enable
// counters, etc. StartArgs will contains the DataSourceDescriptor,
// which can be extended.
PRINT_HERE("%s", "start");
}
void OnStop(const StopArgs&) override
{
// Undo any initialization done in OnStart.
PRINT_HERE("%s", "stop");
}
// Data sources can also have per-instance state.
int my_custom_state = 0;
};
PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(CustomDataSource);
#endif
@@ -0,0 +1,55 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include "PTL/PTL.hh"
#include "timemory/macros/attributes.hpp"
#include <mutex>
namespace tasking
{
std::mutex&
get_roctracer_mutex();
PTL::ThreadPool&
get_roctracer_thread_pool();
PTL::TaskGroup<void>&
get_roctracer_task_group();
std::mutex&
get_critical_trace_mutex();
PTL::ThreadPool&
get_critical_trace_thread_pool();
PTL::TaskGroup<void>&
get_critical_trace_task_group();
} // namespace tasking
@@ -1,3 +1,30 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
@@ -0,0 +1,96 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include "library/config.hpp"
#include "library/debug.hpp"
#include "library/dynamic_library.hpp"
#include "library/perfetto.hpp"
#include "library/ptl.hpp"
#include "library/roctracer.hpp"
#include <roctracer.h>
#include <roctracer_ext.h>
#include <roctracer_hcc.h>
#include <roctracer_hip.h>
#define AMD_INTERNAL_BUILD 1
#include <ext/hsa_rt_utils.hpp>
#include <roctracer_hsa.h>
#include <iostream>
#include <memory>
// Macro to check ROC-tracer calls status
#define ROCTRACER_CALL(call) \
do \
{ \
int err = call; \
if(err != 0) \
{ \
std::cerr << roctracer_error_string() << " in: " << #call << std::flush; \
} \
} while(0)
using hsa_timer_t = hsa_rt_utils::Timer;
using timestamp_t = hsa_timer_t::timestamp_t;
using roctracer_bundle_t = tim::component_bundle<hosttrace, comp::roctracer_data,
comp::wall_clock, quirk::explicit_pop>;
using roctracer_hsa_bundle_t = tim::component_bundle<hosttrace, comp::roctracer_data>;
using roctracer_functions_t = std::vector<std::pair<std::string, std::function<void()>>>;
std::unique_ptr<hsa_timer_t>&
get_hsa_timer();
// HSA API callback function
void
hsa_api_callback(uint32_t domain, uint32_t cid, const void* callback_data, void* arg);
void
hsa_activity_callback(uint32_t op, activity_record_t* record, void* arg);
void
hip_exec_activity_callbacks(int64_t _tid);
// HIP API callback function
void
hip_api_callback(uint32_t domain, uint32_t cid, const void* callback_data, void* arg);
// Activity tracing callback
void
hip_activity_callback(const char* begin, const char* end, void*);
bool&
roctracer_is_setup();
roctracer_functions_t&
roctracer_setup_routines();
roctracer_functions_t&
roctracer_tear_down_routines();
@@ -0,0 +1,38 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
// used for specifying the state of hosttrace
enum class State : unsigned short
{
DelayedInit = 0,
PreInit,
Active,
Finalized
};
@@ -0,0 +1,126 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include "library/config.hpp"
#include <array>
#include <cstdint>
#include <cstdlib>
#include <memory>
#include <type_traits>
#if !defined(HOSTTRACE_MAX_THREADS)
# define HOSTTRACE_MAX_THREADS 1024
#endif
static constexpr size_t max_supported_threads = HOSTTRACE_MAX_THREADS;
template <typename Tp, typename Tag = void, size_t MaxThreads = max_supported_threads>
struct hosttrace_thread_data
{
using instance_array_t = std::array<std::unique_ptr<Tp>, MaxThreads>;
using construct_on_init = std::true_type;
template <typename... Args>
static void construct(Args&&...);
static std::unique_ptr<Tp>& instance();
static instance_array_t& instances();
template <typename... Args>
static std::unique_ptr<Tp>& instance(construct_on_init, Args&&...);
template <typename... Args>
static instance_array_t& instances(construct_on_init, Args&&...);
};
template <typename Tp, typename Tag, size_t MaxThreads>
template <typename... Args>
void
hosttrace_thread_data<Tp, Tag, MaxThreads>::construct(Args&&... _args)
{
static thread_local bool _v = [&_args...]() {
instances().at(threading::get_id()) =
std::make_unique<Tp>(std::forward<Args>(_args)...);
return true;
}();
(void) _v;
}
template <typename Tp, typename Tag, size_t MaxThreads>
std::unique_ptr<Tp>&
hosttrace_thread_data<Tp, Tag, MaxThreads>::instance()
{
return instances().at(threading::get_id());
}
template <typename Tp, typename Tag, size_t MaxThreads>
typename hosttrace_thread_data<Tp, Tag, MaxThreads>::instance_array_t&
hosttrace_thread_data<Tp, Tag, MaxThreads>::instances()
{
static auto _v = instance_array_t{};
return _v;
}
template <typename Tp, typename Tag, size_t MaxThreads>
template <typename... Args>
std::unique_ptr<Tp>&
hosttrace_thread_data<Tp, Tag, MaxThreads>::instance(construct_on_init, Args&&... _args)
{
construct(std::forward<Args>(_args)...);
return instances().at(threading::get_id());
}
template <typename Tp, typename Tag, size_t MaxThreads>
template <typename... Args>
typename hosttrace_thread_data<Tp, Tag, MaxThreads>::instance_array_t&
hosttrace_thread_data<Tp, Tag, MaxThreads>::instances(construct_on_init, Args&&... _args)
{
static auto _v = [&]() {
auto _internal = instance_array_t{};
for(size_t i = 0; i < MaxThreads; ++i)
_internal.at(i) = std::make_unique<Tp>(std::forward<Args>(_args)...);
return _internal;
}();
return _v;
}
//--------------------------------------------------------------------------------------//
// there are currently some strange things that happen with
// vector<instrumentation_bundle_t> so using vector<instrumentation_bundle_t*> and
// timemory's ring_buffer_allocator to create contiguous memory-page aligned instances of
// the bundle
struct instrumentation_bundles
{
using instance_array_t = std::array<instrumentation_bundles, max_supported_threads>;
bundle_allocator_t allocator{};
std::vector<instrumentation_bundle_t*> bundles{};
static instance_array_t& instances();
};
@@ -0,0 +1,63 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
#include <timemory/api.hpp>
#include <timemory/backends/mpi.hpp>
#include <timemory/backends/process.hpp>
#include <timemory/backends/threading.hpp>
#include <timemory/components.hpp>
#include <timemory/components/gotcha/mpip.hpp>
#include <timemory/components/papi/papi_tuple.hpp>
#include <timemory/config.hpp>
#include <timemory/environment.hpp>
#include <timemory/manager.hpp>
#include <timemory/mpl/apply.hpp>
#include <timemory/operations.hpp>
#include <timemory/runtime.hpp>
#include <timemory/settings.hpp>
#include <timemory/storage.hpp>
#include <timemory/variadic.hpp>
namespace audit = tim::audit;
namespace comp = tim::component;
namespace quirk = tim::quirk;
namespace threading = tim::threading;
namespace scope = tim::scope;
namespace dmp = tim::dmp;
namespace process = tim::process;
namespace units = tim::units;
namespace trait = tim::trait;
// same sort of functionality as python's " ".join([...])
#if !defined(JOIN)
# define JOIN(...) tim::mpl::apply<std::string>::join(__VA_ARGS__)
#endif
using papi_tot_ins = comp::papi_tuple<PAPI_TOT_INS>;
@@ -0,0 +1,29 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#pragma once
@@ -1,27 +1,30 @@
// MIT License
//
// Copyright (c) 2020, The Regents of the University of California,
// through Lawrence Berkeley National Laboratory (subject to receipt of any
// required approvals from the U.S. Dept. of Energy). All rights reserved.
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "hosttrace.hpp"
@@ -1183,7 +1186,7 @@ main(int argc, char** argv)
auto mpie_fini_args = hosttrace_call_expr("HOSTTRACE_MPI_FINALIZE", "OFF");
auto trace_call_args =
hosttrace_call_expr("HOSTTRACE_COMPONENTS", default_components);
auto use_mpi_call_args = hosttrace_call_expr("HOSTTRACE_USE_MPI", "ON");
auto use_mpi_call_args = hosttrace_call_expr("HOSTTRACE_USE_PID", "ON");
auto use_mpip_call_args = hosttrace_call_expr(
"HOSTTRACE_USE_MPIP", (binary_rewrite && use_mpi && use_mpip) ? "ON" : "OFF");
auto none_call_args = hosttrace_call_expr();
@@ -1777,7 +1780,7 @@ main(int argc, char** argv)
const auto& outf = outfile;
if(outf.find('/') != string_t::npos)
{
auto outdir = outf.substr(0, outf.find_last_of('/') - 1);
auto outdir = outf.substr(0, outf.find_last_of('/'));
tim::makedir(outdir);
}
@@ -1,26 +1,30 @@
// MIT License
//
// Copyright (c) 2020, The Regents of the University of California,
// through Lawrence Berkeley National Laboratory (subject to receipt of any
// required approvals from the U.S. Dept. of Energy). All rights reserved.
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "hosttrace.hpp"
@@ -47,7 +51,7 @@ get_loop_file_line_info(module_t* mutatee_module, procedure_t* f, flow_graph_t*
char fname[MUTNAMELEN];
char mname[MUTNAMELEN];
const char* typeName = nullptr;
std::string typeName = {};
mutatee_module->getName(mname, MUTNAMELEN);
@@ -73,8 +77,6 @@ get_loop_file_line_info(module_t* mutatee_module, procedure_t* f, flow_graph_t*
{
typeName = returnType->getName();
}
else
typeName = "void";
auto params = f->getParams();
std::vector<string_t> _params;
@@ -148,8 +150,8 @@ get_func_file_line_info(module_t* mutatee_module, procedure_t* f)
char fname[MUTNAMELEN];
char mname[MUTNAMELEN];
int row1, col1, row2, col2;
string_t filename;
string_t typeName;
string_t filename = {};
string_t typeName = {};
mutatee_module->getName(mname, MUTNAMELEN);
@@ -164,8 +166,6 @@ get_func_file_line_info(module_t* mutatee_module, procedure_t* f)
{
typeName = returnType->getName();
}
else
typeName = "void";
auto params = f->getParams();
std::vector<string_t> _params;
@@ -1,51 +1,39 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "library.hpp"
bool
get_debug()
{
static bool _v = tim::get_env("HOSTTRACE_DEBUG", false);
return _v;
}
State&
get_state()
{
static State _v{ State::PreInit };
return _v;
}
bool
get_use_perfetto()
{
// if using timemory, default to perfetto being off
static auto _default_v = !tim::get_env<bool>("HOSTTRACE_USE_TIMEMORY", false, false);
// explicit env control for using perfetto
static auto _v = tim::get_env<bool>("HOSTTRACE_USE_PERFETTO", _default_v);
return _v;
}
bool
get_use_timemory()
{
// default to opposite of whether perfetto setting
// to use both timemory and perfetto, both HOSTTRACE_USE_TIMEMORY and
// HOSTTRACE_USE_PERFETTO must be true
static auto _v = tim::get_env<bool>("HOSTTRACE_USE_TIMEMORY", !get_use_perfetto());
return _v;
}
//--------------------------------------------------------------------------------------//
#include "library/config.hpp"
#include "library/critical_trace.hpp"
#include "library/thread_data.hpp"
#include <string_view>
namespace
{
size_t&
get_sample_rate()
{
static auto _v = tim::get_env<size_t>("HOSTTRACE_SAMPLE_RATE", 1);
return _v;
}
std::vector<bool>&
get_sample_data()
{
@@ -53,17 +41,6 @@ get_sample_data()
return _v;
}
bool&
get_use_mpi()
{
#if defined(TIMEMORY_USE_MPI)
static bool _v = tim::get_env("HOSTTRACE_USE_MPI", false);
#else
static bool _v = false;
#endif
return _v;
}
void
setup_gotchas()
{
@@ -83,16 +60,17 @@ setup_gotchas()
mpi_gotcha_t::template configure<0, int, int*, char***>("MPI_Init");
mpi_gotcha_t::template configure<1, int, int*, char***, int, int*>(
"MPI_Init_thread");
#if defined(HOSTTRACE_USE_MPI_HEADERS)
mpi_gotcha_t::template configure<3, int>("MPI_Finalize");
#endif
};
}
auto
ensure_finalization()
ensure_finalization(bool _static_init = false)
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
if(!_static_init)
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
}
return scope::destructor{ []() { hosttrace_trace_finalize(); } };
}
@@ -103,45 +81,6 @@ get_trace_session()
return _session;
}
auto
get_perfetto_output_filename()
{
static auto _v = []() {
// default name: perfetto-trace.<pid>.proto or perfetto-trace.<rank>.proto
auto _default_fname = tim::settings::compose_output_filename(
JOIN('.', "perfetto-trace", (get_use_mpi()) ? "%rank%" : "%pid%"), "proto");
// have the default display the full path to the output file
return tim::get_env<std::string>(
"HOSTTRACE_OUTPUT_FILE",
JOIN('/', tim::get_env<std::string>("PWD", ".", false), _default_fname));
}();
auto _tmp = _v;
auto _replace = [&_tmp](const std::string& _key, auto&& _val) {
auto _pos = _tmp.find(_key);
if(_pos != std::string::npos)
_tmp.replace(_pos, _key.length(), std::to_string(_val()));
};
_replace("%pid%", []() { return process::get_id(); });
_replace("%rank%", []() { return tim::mpi::rank(); });
// backwards compatibility
_replace("%p", []() { return process::get_id(); });
return _tmp;
}
auto&
get_backend()
{
// select inprocess, system, or both (i.e. all)
static auto _v = tim::get_env_choice<std::string>(
"HOSTTRACE_BACKEND",
tim::get_env("HOSTTRACE_BACKEND_SYSTEM", false, false)
? "system" // if HOSTTRACE_BACKEND_SYSTEM is true, default to system.
: "inprocess", // Otherwise, default to inprocess
{ "inprocess", "system", "all" });
return _v;
}
auto
is_system_backend()
{
@@ -150,10 +89,10 @@ is_system_backend()
}
auto&
get_timemory_data()
get_instrumentation_bundles()
{
static thread_local auto& _v =
hosttrace_timemory_data::instances().at(threading::get_id());
instrumentation_bundles::instances().at(threading::get_id());
return _v;
}
@@ -166,6 +105,17 @@ get_functors()
return _v;
}
auto&
get_cpu_cid_parents()
{
static thread_local auto _v =
std::unordered_map<uint64_t, std::tuple<uint64_t, uint16_t>>{};
return _v;
}
using Device = critical_trace::Device;
using Phase = critical_trace::Phase;
bool
hosttrace_init_tooling()
{
@@ -184,26 +134,17 @@ hosttrace_init_tooling()
return false;
}
// always initialize timemory because gotcha wrappers are always used
tim::settings::flamegraph_output() = false;
tim::settings::cout_output() = false;
tim::settings::file_output() = true;
tim::settings::enable_signal_handler() = true;
tim::settings::collapse_processes() = false;
tim::settings::collapse_threads() = false;
tim::settings::max_thread_bookmarks() = 1;
tim::settings::global_components() = tim::get_env<std::string>(
"HOSTTRACE_COMPONENTS", "wall_clock", get_use_timemory());
int _threadpool_verbose = (get_debug()) ? 4 : -1;
tasking::get_roctracer_thread_pool().set_verbose(_threadpool_verbose);
tasking::get_critical_trace_thread_pool().set_verbose(_threadpool_verbose);
// enable timestamp directories when perfetto + mpi is activated
if(get_use_perfetto() && get_use_mpi()) tim::settings::time_output() = true;
// below will effectively do:
// get_cpu_cid_stack(0)->emplace_back(-1);
// plus query some env variables
add_critical_trace<Device::CPU, Phase::NONE>(0, -1, 0, 0, 0, 0, 0, 0);
auto _cmd = tim::read_command_line(process::get_id());
auto _exe = (_cmd.empty()) ? "hosttrace" : _cmd.front();
auto _pos = _exe.find_last_of('/');
if(_pos < _exe.length() - 1) _exe = _exe.substr(_pos + 1);
tim::timemory_init({ _exe }, "hosttrace-");
// configure the settings
configure_settings();
if(get_sample_rate() < 1) get_sample_rate() = 1;
get_sample_data().reserve(512);
@@ -218,16 +159,18 @@ hosttrace_init_tooling()
if(_comps.size() == 1 && _comps.find(TIMEMORY_WALL_CLOCK) != _comps.end())
{
// using wall_clock directly is lower overhead than using it via user_bundle
bundle_t::get_initializer() = [](bundle_t& _bundle) {
_bundle.initialize<comp::wall_clock>();
};
instrumentation_bundle_t::get_initializer() =
[](instrumentation_bundle_t& _bundle) {
_bundle.initialize<comp::wall_clock>();
};
}
else if(!_comps.empty())
{
// use user_bundle for other than wall-clock
bundle_t::get_initializer() = [](bundle_t& _bundle) {
_bundle.initialize<comp::user_global_bundle>();
};
instrumentation_bundle_t::get_initializer() =
[](instrumentation_bundle_t& _bundle) {
_bundle.initialize<comp::user_global_bundle>();
};
}
else
{
@@ -252,9 +195,8 @@ hosttrace_init_tooling()
if(get_use_perfetto())
{
// environment settings
auto shmem_size_hint =
tim::get_env<size_t>("HOSTTRACE_SHMEM_SIZE_HINT_KB", 40960);
auto buffer_size = tim::get_env<size_t>("HOSTTRACE_BUFFER_SIZE_KB", 1024000);
auto shmem_size_hint = get_perfetto_shmem_size_hint();
auto buffer_size = get_perfetto_buffer_size();
auto* buffer_config = cfg.add_buffers();
buffer_config->set_size_kb(buffer_size);
@@ -276,6 +218,7 @@ hosttrace_init_tooling()
(void) get_perfetto_output_filename();
}
auto _exe = get_exe_name();
static auto _thread_init = [_exe]() {
hosttrace_thread_data<hosttrace_thread_bundle_t>::construct(
TIMEMORY_JOIN("", _exe, "/thread-", threading::get_id()),
@@ -285,10 +228,11 @@ hosttrace_init_tooling()
} };
(void) _dtor;
};
// functors for starting and stopping timemory
static auto _push_timemory = [](const char* name) {
_thread_init();
auto& _data = get_timemory_data();
auto& _data = get_instrumentation_bundles();
// this generates a hash for the raw string array
auto _hash = tim::add_hash_id(tim::string_view_t{ name });
auto* _bundle = _data.allocator.allocate(1);
@@ -311,7 +255,7 @@ hosttrace_init_tooling()
};
static auto _pop_timemory = [](const char* name) {
auto& _data = get_timemory_data();
auto& _data = get_instrumentation_bundles();
if(_data.bundles.empty())
{
HOSTTRACE_DEBUG("[%s] skipped %s :: empty bundle stack\n",
@@ -358,8 +302,22 @@ hosttrace_init_tooling()
if(dmp::rank() == 0)
{
tim::print_env(std::cerr,
[](const std::string& _v) { return _v.find("HOSTTRACE_") == 0; });
// generic filter for filtering relevant options
auto _is_hosttrace_option = [](const auto& _v) {
#if !defined(HOSTTRACE_USE_ROCTRACER)
if(_v.find("HOSTTRACE_ROCTRACER_") == 0) return false;
#endif
if(!get_use_critical_trace() && _v.find("HOSTTRACE_CRITICAL_TRACE_") == 0)
return false;
return (_v.find("HOSTTRACE_") == 0) ||
((_v.find("TIMEMORY_") != 0) && (_v.find("SIGNAL_") != 0));
};
tim::print_env(std::cerr, [_is_hosttrace_option](const std::string& _v) {
return _is_hosttrace_option(_v);
});
print_config_settings(std::cerr, _is_hosttrace_option);
}
if(get_use_perfetto() && !is_system_backend())
@@ -421,6 +379,21 @@ extern "C"
auto _enabled = (_sample_idx++ % _sample_rate == 0);
get_sample_data().emplace_back(_enabled);
if(_enabled) get_functors().first(name);
if(get_use_critical_trace())
{
auto _ts = comp::wall_clock::record();
auto _cid = get_cpu_cid()++;
uint16_t _depth = (get_cpu_cid_stack()->empty())
? get_cpu_cid_stack(0)->size()
: get_cpu_cid_stack()->size() - 1;
auto _parent_cid = (get_cpu_cid_stack()->empty())
? get_cpu_cid_stack(0)->back()
: get_cpu_cid_stack()->back();
get_cpu_cid_parents().emplace(_cid, std::make_tuple(_parent_cid, _depth));
add_critical_trace<Device::CPU, Phase::BEGIN>(
threading::get_id(), _cid, 0, _parent_cid, _ts, 0,
critical_trace::add_hash_id(name), _depth);
}
}
void hosttrace_pop_trace(const char* name)
@@ -434,6 +407,20 @@ extern "C"
if(_sample_data.back()) get_functors().second(name);
_sample_data.pop_back();
}
if(get_use_critical_trace())
{
if(get_cpu_cid_stack() && !get_cpu_cid_stack()->empty())
{
auto _ts = comp::wall_clock::record();
auto _cid = get_cpu_cid_stack()->back();
uint64_t _parent_cid = 0;
uint16_t _depth = 0;
std::tie(_parent_cid, _depth) = get_cpu_cid_parents().at(_cid);
add_critical_trace<Device::CPU, Phase::END>(
threading::get_id(), _cid, 0, _parent_cid, _ts, _ts,
critical_trace::add_hash_id(name), _depth);
}
}
}
else
{
@@ -463,15 +450,19 @@ extern "C"
comp::roctracer::tear_down();
#endif
// join extra thread(s) used by roctracer
HOSTTRACE_DEBUG("[%s] waiting for all roctracer tasks to complete...\n",
__FUNCTION__);
tasking::get_roctracer_task_group().join();
// stop the main bundle and report the high-level metrics
if(get_main_bundle())
{
get_main_bundle()->stop();
int64_t _id = (get_use_mpi()) ? dmp::rank() : process::get_id();
std::stringstream _ss{};
_ss << "[" << __FUNCTION__ << "][" << _id << "] " << *get_main_bundle()
<< "\n";
std::cerr << _ss.str();
std::string _msg = JOIN("", *get_main_bundle());
auto _pos = _msg.find(">>> ");
if(_pos != std::string::npos) _msg = _msg.substr(_pos + 5);
HOSTTRACE_PRINT("%s\n", _msg.c_str());
get_main_bundle().reset();
}
@@ -484,14 +475,15 @@ extern "C"
if(itr && itr->get<comp::wall_clock>() &&
!itr->get<comp::wall_clock>()->get_is_running())
{
std::stringstream _ss{};
_ss << *itr << "\n";
std::cerr << _ss.str();
std::string _msg = JOIN("", *itr);
auto _pos = _msg.find(">>> ");
if(_pos != std::string::npos) _msg = _msg.substr(_pos + 5);
HOSTTRACE_PRINT("%s\n", _msg.c_str());
}
}
// ensure that all the MT instances are flushed
for(auto& itr : hosttrace_timemory_data::instances())
for(auto& itr : instrumentation_bundles::instances())
{
while(!itr.bundles.empty())
{
@@ -503,6 +495,44 @@ extern "C"
}
}
if(get_use_critical_trace())
{
// increase the thread-pool size
tasking::get_critical_trace_thread_pool().initialize_threadpool(
get_critical_trace_num_threads());
for(size_t i = 0; i < max_supported_threads; ++i)
{
using critical_trace_hash_data =
hosttrace_thread_data<critical_trace::hash_ids, critical_trace::id>;
if(critical_trace_hash_data::instances().at(i))
critical_trace::add_hash_id(
*critical_trace_hash_data::instances().at(i));
}
for(size_t i = 0; i < max_supported_threads; ++i)
{
using critical_trace_chain_data =
hosttrace_thread_data<critical_trace::call_chain>;
if(critical_trace_chain_data::instances().at(i))
critical_trace::update(i); // launch update task
}
// make sure outstanding hash tasks completed before compute
HOSTTRACE_PRINT("[%s] waiting for all critical trace tasks to complete...\n",
__FUNCTION__);
tasking::get_critical_trace_task_group().join();
// launch compute task
HOSTTRACE_PRINT("[%s] launching critical trace compute task...\n",
__FUNCTION__);
critical_trace::compute();
}
tasking::get_critical_trace_task_group().join();
bool _perfetto_output_error = false;
if(get_use_perfetto() && !is_system_backend())
{
@@ -530,20 +560,27 @@ extern "C"
static_cast<double>(trace_data.size()) / units::KB,
static_cast<double>(trace_data.size()) / units::MB,
static_cast<double>(trace_data.size()) / units::GB);
std::ofstream output{};
output.open(get_perfetto_output_filename(), std::ios::out | std::ios::binary);
if(!output)
std::ofstream ofs{};
if(!tim::filepath::open(ofs, get_perfetto_output_filename(),
std::ios::out | std::ios::binary))
{
fprintf(stderr, "[%s]> Error opening '%s'...\n", __FUNCTION__,
get_perfetto_output_filename().c_str());
_perfetto_output_error = true;
}
else
output.write(&trace_data[0], trace_data.size());
output.close();
ofs.write(&trace_data[0], trace_data.size());
ofs.close();
}
// these should be destroyed before timemory is finalized, especially the
// roctracer thread-pool
tasking::get_roctracer_thread_pool().destroy_threadpool();
tasking::get_critical_trace_thread_pool().destroy_threadpool();
HOSTTRACE_DEBUG("Finalizing timemory...\n");
tim::timemory_finalize();
HOSTTRACE_DEBUG("Finalizing timemory... Done\n");
if(_perfetto_output_error)
throw std::runtime_error("Unable to create perfetto output file");
@@ -564,20 +601,17 @@ extern "C"
{
auto& _main_bundle = get_main_bundle();
_main_bundle->start();
#if defined(TIMEMORY_USE_MPI)
tim::set_env("HOSTTRACE_USE_MPI", "ON", 1);
get_use_mpi() = true;
#endif
get_state() = State::DelayedInit;
get_use_pid() = true;
get_state() = State::DelayedInit;
}
}
}
std::unique_ptr<hosttrace_bundle_t>&
std::unique_ptr<main_bundle_t>&
get_main_bundle()
{
static auto _v =
(setup_gotchas(), std::make_unique<hosttrace_bundle_t>(
(setup_gotchas(), std::make_unique<main_bundle_t>(
"hosttrace", quirk::config<quirk::auto_start>{}));
return _v;
}
@@ -587,5 +621,5 @@ namespace
// if static objects are destroyed randomly (relatively uncommon behavior)
// this might call finalization before perfetto ends the tracing session
// but static variable in hosttrace_init_tooling is more likely
auto _ensure_finalization = ensure_finalization();
auto _ensure_finalization = ensure_finalization(true);
} // namespace
@@ -0,0 +1,528 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "library/config.hpp"
#include "library/debug.hpp"
#include "library/thread_data.hpp"
#include "timemory/backends/dmp.hpp"
#include "timemory/backends/process.hpp"
#include "timemory/settings/types.hpp"
#include "timemory/utility/argparse.hpp"
#include <array>
#include <cstdint>
#include <cstdlib>
#include <numeric>
#include <ostream>
#include <string>
#include <timemory/environment.hpp>
#include <timemory/settings.hpp>
using settings = tim::settings;
namespace
{
auto
get_config()
{
static auto _once = (configure_settings(), true);
return settings::shared_instance();
(void) _once;
}
#define HOSTTRACE_CONFIG_SETTING(TYPE, ENV_NAME, DESCRIPTION, INITIAL_VALUE) \
_config->insert<TYPE, TYPE>(ENV_NAME, ENV_NAME, DESCRIPTION, INITIAL_VALUE, \
std::vector<std::string>{})
} // namespace
void
configure_settings()
{
static bool _once = false;
if(_once) return;
_once = true;
static auto _config = settings::shared_instance();
// auto* _config = settings::instance();
// if using timemory, default to perfetto being off
auto _default_perfetto_v =
!tim::get_env<bool>("HOSTTRACE_USE_TIMEMORY", false, false);
auto _default_config_file =
JOIN("/", tim::get_env<std::string>("HOME", "."), "hosttrace.cfg");
auto _system_backend = tim::get_env("HOSTTRACE_BACKEND_SYSTEM", false, false);
HOSTTRACE_CONFIG_SETTING(std::string, "HOSTTRACE_CONFIG_FILE",
"Configuration file of hosttrace and timemory settings",
_default_config_file);
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_DEBUG", "Enable debugging output",
_config->get_debug());
auto _hosttrace_debug = _config->get<bool>("HOSTTRACE_DEBUG");
if(_hosttrace_debug) tim::set_env("TIMEMORY_DEBUG_SETTINGS", "1", 0);
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_USE_PERFETTO", "Enable perfetto backend",
_default_perfetto_v);
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_USE_TIMEMORY", "Enable timemory backend",
!_config->get<bool>("HOSTTRACE_USE_PERFETTO"));
HOSTTRACE_CONFIG_SETTING(
bool, "HOSTTRACE_USE_PID",
"Enable tagging filenames with process identifier (either MPI rank or pid)",
true);
HOSTTRACE_CONFIG_SETTING(
size_t, "HOSTTRACE_SAMPLE_RATE",
"Counts every function call (N), only record function if (N % <VALUE> == 0)", 1);
auto _backend = tim::get_env_choice<std::string>(
"HOSTTRACE_BACKEND",
(_system_backend)
? "system" // if HOSTTRACE_BACKEND_SYSTEM is true, default to system.
: "inprocess", // Otherwise, default to inprocess
{ "inprocess", "system", "all" }, false);
HOSTTRACE_CONFIG_SETTING(std::string, "HOSTTRACE_BACKEND",
"Specify the perfetto backend to activate. Options are: "
"'inprocess', 'system', or 'all'",
_backend);
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_CRITICAL_TRACE",
"Enable generation of the critical trace", false);
HOSTTRACE_CONFIG_SETTING(
bool, "HOSTTRACE_ROCTRACER_TIMELINE_PROFILE",
"Create unique entries for every kernel with timemory backend",
_config->get_timeline_profile());
HOSTTRACE_CONFIG_SETTING(
bool, "HOSTTRACE_ROCTRACER_FLAT_PROFILE",
"Ignore hierarchy in all kernels entries with timemory backend",
_config->get_flat_profile());
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_ROCTRACER_HSA_ACTIVITY",
"Enable HSA activity tracing support", false);
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_ROCTRACER_HSA_API",
"Enable HSA API tracing support", false);
HOSTTRACE_CONFIG_SETTING(std::string, "HOSTTRACE_ROCTRACER_HSA_API_TYPES",
"HSA API type to collect", "");
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_CRITICAL_TRACE_DEBUG",
"Enable debugging for critical trace", _hosttrace_debug);
HOSTTRACE_CONFIG_SETTING(
bool, "HOSTTRACE_CRITICAL_TRACE_SERIALIZE_NAMES",
"Include names in serialization of critical trace (mainly for debugging)",
_hosttrace_debug);
HOSTTRACE_CONFIG_SETTING(size_t, "HOSTTRACE_SHMEM_SIZE_HINT_KB",
"Hint for shared-memory buffer size in perfetto (in KB)",
40960);
HOSTTRACE_CONFIG_SETTING(size_t, "HOSTTRACE_BUFFER_SIZE_KB",
"Size of perfetto buffer (in KB)", 1024000);
HOSTTRACE_CONFIG_SETTING(int64_t, "HOSTTRACE_CRITICAL_TRACE_COUNT",
"Number of critical trace to export (0 == all)", 0);
HOSTTRACE_CONFIG_SETTING(uint64_t, "HOSTTRACE_CRITICAL_TRACE_BUFFER_COUNT",
"Number of critical trace records to store in thread-local "
"memory before submitting to shared buffer",
2000);
HOSTTRACE_CONFIG_SETTING(
uint64_t, "HOSTTRACE_CRITICAL_TRACE_NUM_THREADS",
"Number of threads to use when generating the critical trace",
std::min<uint64_t>(8, std::thread::hardware_concurrency()));
HOSTTRACE_CONFIG_SETTING(
int64_t, "HOSTTRACE_CRITICAL_TRACE_PER_ROW",
"How many critical traces per row in perfetto (0 == all in one row)", 0);
HOSTTRACE_CONFIG_SETTING(
std::string, "HOSTTRACE_COMPONENTS",
"List of components to collect via timemory (see timemory-avail)", "wall_clock");
HOSTTRACE_CONFIG_SETTING(std::string, "HOSTTRACE_OUTPUT_FILE", "Perfetto filename",
"");
HOSTTRACE_CONFIG_SETTING(bool, "HOSTTRACE_SETTINGS_DESC",
"Provide descriptions when printing settings", false);
_config->get_flamegraph_output() = false;
_config->get_cout_output() = false;
_config->get_file_output() = true;
_config->get_json_output() = true;
_config->get_tree_output() = true;
_config->get_enable_signal_handler() = true;
_config->get_collapse_processes() = false;
_config->get_collapse_threads() = false;
_config->get_stack_clearing() = false;
_config->get_time_output() = true;
_config->get_timing_precision() = 6;
for(auto&& itr :
tim::delimit(_config->get<std::string>("HOSTTRACE_CONFIG_FILE"), ";:"))
{
HOSTTRACE_CONDITIONAL_BASIC_PRINT(true, "Reading config file %s\n", itr.c_str());
_config->read(itr);
}
_config->get_global_components() = _config->get<std::string>("HOSTTRACE_COMPONENTS");
// always initialize timemory because gotcha wrappers are always used
auto _cmd = tim::read_command_line(process::get_id());
auto _exe = (_cmd.empty()) ? "exe" : _cmd.front();
auto _pos = _exe.find_last_of('/');
if(_pos < _exe.length() - 1) _exe = _exe.substr(_pos + 1);
get_exe_name() = _exe;
scope::get_fields()[scope::flat::value] = tim::settings::flat_profile();
scope::get_fields()[scope::timeline::value] = tim::settings::timeline_profile();
bool _found_sep = false;
for(const auto& itr : _cmd)
{
if(itr == "--") _found_sep = true;
}
if(!_found_sep && _cmd.size() > 1) _cmd.insert(_cmd.begin() + 1, "--");
using argparser_t = tim::argparse::argument_parser;
argparser_t _parser{ _exe };
tim::timemory_init(_cmd, _parser, "hosttrace-");
settings::suppress_parsing() = true;
settings::suppress_config() = true;
settings::use_output_suffix() = _config->get<bool>("HOSTTRACE_USE_PID");
}
void
print_config_settings(std::ostream& _os,
std::function<bool(const std::string_view&)>&& _filter)
{
auto _flags = _os.flags();
constexpr size_t nfields = 3;
using str_array_t = std::array<std::string, nfields>;
std::vector<str_array_t> _data{};
std::array<size_t, nfields> _widths{};
_widths.fill(0);
for(const auto& itr : *get_config())
{
if(_filter(itr.first))
{
auto _disp = itr.second->get_display(std::ios::boolalpha);
_data.emplace_back(str_array_t{ _disp.at("name"), _disp.at("value"),
_disp.at("description") });
for(size_t i = 0; i < nfields; ++i)
_widths.at(i) =
std::max<size_t>(_widths.at(i), _data.back().at(i).length());
}
}
std::sort(_data.begin(), _data.end(), [](const auto& lhs, const auto& rhs) {
auto _npos = std::string::npos;
// HOSTTRACE_CONFIG_FILE always first
if(lhs.at(0).find("HOSTTRACE_CONFIG") != _npos) return true;
if(rhs.at(0).find("HOSTTRACE_CONFIG") != _npos) return false;
// HOSTTRACE_USE_* prioritized
auto _lhs_use = lhs.at(0).find("HOSTTRACE_USE_");
auto _rhs_use = rhs.at(0).find("HOSTTRACE_USE_");
if(_lhs_use != _rhs_use && _lhs_use < _rhs_use) return true;
if(_lhs_use != _rhs_use && _lhs_use > _rhs_use) return false;
// length sort followed by alphabetical sort
return (lhs.at(0).length() == rhs.at(0).length())
? (lhs.at(0) < rhs.at(0))
: (lhs.at(0).length() < rhs.at(0).length());
});
bool _print_desc = get_debug() || get_config()->get<bool>("HOSTTRACE_SETTINGS_DESC");
auto tot_width = std::accumulate(_widths.begin(), _widths.end(), 0);
if(!_print_desc) tot_width -= _widths.back() + 4;
std::stringstream _spacer{};
_spacer.fill('-');
_spacer << "#" << std::setw(tot_width + 11) << ""
<< "#";
_os << _spacer.str() << "\n";
// _os << "# Hosttrace settings:" << std::setw(tot_width - 8) << "#" << "\n";
for(const auto& itr : _data)
{
_os << "# ";
for(size_t i = 0; i < nfields; ++i)
{
switch(i)
{
case 0: _os << std::left; break;
case 1: _os << std::left; break;
case 2: _os << std::left; break;
}
_os << std::setw(_widths.at(i)) << itr.at(i) << " ";
if(!_print_desc && i == 1) break;
switch(i)
{
case 0: _os << "= "; break;
case 1: _os << "[ "; break;
case 2: _os << "]"; break;
}
}
_os << " #\n";
}
_os << _spacer.str() << "\n";
_os.setf(_flags);
}
std::string&
get_exe_name()
{
static std::string _v = {};
return _v;
}
std::string
get_config_file()
{
static auto _v = get_config()->find("HOSTTRACE_CONFIG_FILE");
return static_cast<tim::tsettings<std::string>&>(*_v->second).get();
}
bool
get_debug()
{
static auto _v = get_config()->find("HOSTTRACE_DEBUG");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_use_perfetto()
{
static auto _v = get_config()->find("HOSTTRACE_USE_PERFETTO");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_use_timemory()
{
static auto _v = get_config()->find("HOSTTRACE_USE_TIMEMORY");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool&
get_use_pid()
{
static auto _v = get_config()->find("HOSTTRACE_USE_PID");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_use_mpip()
{
static bool _v = tim::get_env("HOSTTRACE_USE_MPIP", false, false);
return _v;
}
bool
get_use_critical_trace()
{
static auto _v = get_config()->find("HOSTTRACE_CRITICAL_TRACE");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_critical_trace_debug()
{
static auto _v = get_config()->find("HOSTTRACE_CRITICAL_TRACE_DEBUG");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_critical_trace_serialize_names()
{
static auto _v = get_config()->find("HOSTTRACE_CRITICAL_TRACE_SERIALIZE_NAMES");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_roctracer_timeline_profile()
{
static auto _v = get_config()->find("HOSTTRACE_ROCTRACER_TIMELINE_PROFILE");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_roctracer_flat_profile()
{
static auto _v = get_config()->find("HOSTTRACE_ROCTRACER_FLAT_PROFILE");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_trace_hsa_api()
{
static auto _v = get_config()->find("HOSTTRACE_ROCTRACER_HSA_API");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
bool
get_trace_hsa_activity()
{
static auto _v = get_config()->find("HOSTTRACE_ROCTRACER_HSA_ACTIVITY");
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
}
int64_t
get_critical_trace_per_row()
{
static auto _v = get_config()->find("HOSTTRACE_CRITICAL_TRACE_PER_ROW");
return static_cast<tim::tsettings<int64_t>&>(*_v->second).get();
}
size_t
get_perfetto_shmem_size_hint()
{
static auto _v = get_config()->find("HOSTTRACE_SHMEM_SIZE_HINT_KB");
return static_cast<tim::tsettings<size_t>&>(*_v->second).get();
}
size_t
get_perfetto_buffer_size()
{
static auto _v = get_config()->find("HOSTTRACE_BUFFER_SIZE_KB");
return static_cast<tim::tsettings<size_t>&>(*_v->second).get();
}
uint64_t
get_critical_trace_update_freq()
{
static uint64_t _v =
get_config()->get<uint64_t>("HOSTTRACE_CRITICAL_TRACE_BUFFER_COUNT");
return _v;
}
uint64_t
get_critical_trace_num_threads()
{
static uint64_t _v =
get_config()->get<uint64_t>("HOSTTRACE_CRITICAL_TRACE_NUM_THREADS");
return _v;
}
std::string
get_trace_hsa_api_types()
{
static std::string _v =
get_config()->get<std::string>("HOSTTRACE_ROCTRACER_HSA_API_TYPES");
return _v;
}
std::string&
get_backend()
{
// select inprocess, system, or both (i.e. all)
static auto _v = get_config()->find("HOSTTRACE_BACKEND");
return static_cast<tim::tsettings<std::string>&>(*_v->second).get();
}
std::string
get_perfetto_output_filename()
{
static auto _v = get_config()->find("HOSTTRACE_OUTPUT_FILE");
static auto& _t = static_cast<tim::tsettings<std::string>&>(*_v->second);
if(_t.get().empty())
{
// default name: perfetto-trace.<pid>.proto or perfetto-trace.<rank>.proto
auto _default_fname = settings::compose_output_filename(
"perfetto-trace", "proto", get_use_pid(),
(tim::dmp::is_initialized()) ? tim::dmp::rank() : process::get_id());
auto _pid_patch = std::string{ "/" } + std::to_string(tim::process::get_id()) +
"-perfetto-trace";
auto _dpos = _default_fname.find(_pid_patch);
if(_dpos != std::string::npos)
_default_fname =
_default_fname.replace(_dpos, _pid_patch.length(), "/perfetto-trace");
// have the default display the full path to the output file
_t.set(tim::get_env<std::string>(
"HOSTTRACE_OUTPUT_FILE",
JOIN('/', tim::get_env<std::string>("PWD", ".", false), _default_fname),
false));
}
return _t.get();
}
size_t&
get_sample_rate()
{
static auto _v = get_config()->find("HOSTTRACE_SAMPLE_RATE");
return static_cast<tim::tsettings<size_t>&>(*_v->second).get();
}
int64_t
get_critical_trace_count()
{
static auto _v = get_config()->find("HOSTTRACE_CRITICAL_TRACE_COUNT");
return static_cast<tim::tsettings<int64_t>&>(*_v->second).get();
}
State&
get_state()
{
static State _v{ State::PreInit };
return _v;
}
std::atomic<uint64_t>&
get_cpu_cid()
{
static std::atomic<uint64_t> _v{ 0 };
return _v;
}
std::unique_ptr<std::vector<uint64_t>>&
get_cpu_cid_stack(int64_t _tid)
{
struct hosttrace_cpu_cid_stack
{};
using thread_data_t =
hosttrace_thread_data<std::vector<uint64_t>, hosttrace_cpu_cid_stack>;
static auto& _v = thread_data_t::instances();
static thread_local auto _v_check = [_tid]() {
thread_data_t::construct((_tid > 0) ? *thread_data_t::instances().at(0)
: std::vector<uint64_t>{});
return true;
}();
return _v.at(_tid);
(void) _v_check;
}
تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است Diff را بارگزاری کن
@@ -0,0 +1,46 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "library/fork_gotcha.hpp"
#include "library/config.hpp"
#include "library/debug.hpp"
void
fork_gotcha::audit(const gotcha_data_t&, audit::incoming)
{
HOSTTRACE_DEBUG(
"Warning! Calling fork() within an OpenMPI application using libfabric "
"may result is segmentation fault\n");
TIMEMORY_CONDITIONAL_DEMANGLED_BACKTRACE(get_debug(), 16);
}
void
fork_gotcha::audit(const gotcha_data_t& _data, audit::outgoing, pid_t _pid)
{
HOSTTRACE_DEBUG("%s() return PID %i\n", _data.tool_id.c_str(), (int) _pid);
}
@@ -0,0 +1,50 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "library/hosttrace_component.hpp"
#include "library/api.hpp"
void
hosttrace_component::start()
{
if(m_prefix) hosttrace_push_trace(m_prefix);
}
void
hosttrace_component::stop()
{
if(m_prefix) hosttrace_pop_trace(m_prefix);
}
void
hosttrace_component::set_prefix(const char* _prefix)
{
m_prefix = _prefix;
}
TIMEMORY_INITIALIZE_STORAGE(hosttrace_component)
@@ -1,14 +1,40 @@
#include "library.hpp"
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
//
// This file contains miscellaneous function definitions related to timemory
// placed in separate file so that, during development, the long compile-times
// arising from compiling timemory's gotcha wrappers are reduced
//
#include "library/mpi_gotcha.hpp"
#include "library/config.hpp"
#include "library/debug.hpp"
#include "library/hosttrace_component.hpp"
namespace
{
uint64_t mpip_index = std::numeric_limits<uint64_t>::max();
uint64_t mpip_index = std::numeric_limits<uint64_t>::max();
std::string mpi_init_string = {};
// this ensures hosttrace_trace_finalize is called before MPI_Finalize
void
@@ -19,10 +45,12 @@ hosttrace_mpi_set_attr()
return MPI_SUCCESS;
};
static auto _mpi_fini = [](MPI_Comm, int, void*, void*) {
HOSTTRACE_DEBUG("MPI Comm attribute finalize\n");
if(mpip_index != std::numeric_limits<uint64_t>::max())
comp::deactivate_mpip<tim::component_tuple<hosttrace_component>, hosttrace>(
mpip_index);
hosttrace_pop_trace("MPI_Finalize()");
if(!mpi_init_string.empty()) hosttrace_pop_trace(mpi_init_string.c_str());
mpi_init_string = {};
hosttrace_trace_finalize();
return MPI_SUCCESS;
};
@@ -37,26 +65,15 @@ hosttrace_mpi_set_attr()
}
} // namespace
void
fork_gotcha::audit(const gotcha_data_t&, audit::incoming)
{
HOSTTRACE_DEBUG(
"Warning! Calling fork() within an OpenMPI application using libfabric "
"may result is segmentation fault\n");
TIMEMORY_CONDITIONAL_DEMANGLED_BACKTRACE(get_debug(), 16);
}
void
fork_gotcha::audit(const gotcha_data_t& _data, audit::outgoing, pid_t _pid)
{
HOSTTRACE_DEBUG("%s() return PID %i\n", _data.tool_id.c_str(), (int) _pid);
}
void
mpi_gotcha::audit(const gotcha_data_t& _data, audit::incoming, int*, char***)
{
HOSTTRACE_DEBUG("[%s] %s(int*, char***)\n", __FUNCTION__, _data.tool_id.c_str());
if(get_state() == ::State::DelayedInit) get_state() = ::State::PreInit;
if(get_state() == ::State::DelayedInit)
{
get_state() = ::State::PreInit;
mpi_init_string = _data.tool_id;
}
}
void
@@ -64,7 +81,11 @@ mpi_gotcha::audit(const gotcha_data_t& _data, audit::incoming, int*, char***, in
{
HOSTTRACE_DEBUG("[%s] %s(int*, char***, int, int*)\n", __FUNCTION__,
_data.tool_id.c_str());
if(get_state() == ::State::DelayedInit) get_state() = ::State::PreInit;
if(get_state() == ::State::DelayedInit)
{
get_state() = ::State::PreInit;
mpi_init_string = _data.tool_id;
}
}
void
@@ -80,7 +101,7 @@ mpi_gotcha::audit(const gotcha_data_t& _data, audit::outgoing, int _retval)
// being activated unwaringly during runtime instrumentation because that
// will result in double instrumenting the MPI functions (unless the MPI functions
// were excluded via a regex expression)
if(tim::get_env("HOSTTRACE_USE_MPIP", false, false))
if(get_use_mpip())
{
HOSTTRACE_DEBUG("[%s] Activating MPI wrappers...\n", __FUNCTION__);
comp::configure_mpip<tim::component_tuple<hosttrace_component>, hosttrace>();
@@ -98,39 +119,9 @@ mpi_gotcha::audit(const gotcha_data_t& _data, audit::incoming)
if(mpip_index != std::numeric_limits<uint64_t>::max())
comp::deactivate_mpip<tim::component_tuple<hosttrace_component>, hosttrace>(
mpip_index);
hosttrace_pop_trace("MPI_Finalize()");
if(!mpi_init_string.empty()) hosttrace_pop_trace(mpi_init_string.c_str());
mpi_init_string = {};
hosttrace_trace_finalize();
}
void
hosttrace_component::start()
{
if(m_prefix) hosttrace_push_trace(m_prefix);
}
void
hosttrace_component::stop()
{
if(m_prefix) hosttrace_pop_trace(m_prefix);
}
void
hosttrace_component::set_prefix(const char* _prefix)
{
m_prefix = _prefix;
}
hosttrace_timemory_data::instance_array_t&
hosttrace_timemory_data::instances()
{
static auto _v = instance_array_t{};
return _v;
}
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
TIMEMORY_INITIALIZE_STORAGE(fork_gotcha, mpi_gotcha, comp::wall_clock,
comp::user_global_bundle)
#if defined(CUSTOM_DATA_SOURCE)
PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(CustomDataSource);
#endif
TIMEMORY_INITIALIZE_STORAGE(mpi_gotcha)
@@ -0,0 +1,35 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "library/perfetto.hpp"
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
#if defined(CUSTOM_DATA_SOURCE)
PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(CustomDataSource);
#endif
@@ -0,0 +1,80 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "library/ptl.hpp"
namespace tasking
{
std::mutex&
get_roctracer_mutex()
{
static std::mutex _v{};
return _v;
}
PTL::ThreadPool&
get_roctracer_thread_pool()
{
static auto _v = PTL::ThreadPool{ 1 };
return _v;
}
PTL::TaskGroup<void>&
get_roctracer_task_group()
{
static PTL::TaskGroup<void> _v{ &get_roctracer_thread_pool() };
return _v;
}
std::mutex&
get_critical_trace_mutex()
{
static std::mutex _v{};
return _v;
}
PTL::ThreadPool&
get_critical_trace_thread_pool()
{
static auto _v = PTL::ThreadPool{ 1 };
return _v;
}
PTL::TaskGroup<void>&
get_critical_trace_task_group()
{
static PTL::TaskGroup<void> _v{ &get_critical_trace_thread_pool() };
return _v;
}
namespace
{
bool _ptl_initialized =
(get_roctracer_thread_pool(), get_critical_trace_thread_pool(), true);
}
} // namespace tasking
@@ -0,0 +1,283 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "library/roctracer.hpp"
#include "library/config.hpp"
#include "library/defines.hpp"
#include "library/roctracer_callbacks.hpp"
#include "library/thread_data.hpp"
namespace tim
{
namespace component
{
void
roctracer::preinit()
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
roctracer_data::label() = "roctracer";
roctracer_data::description() = "ROCm tracer (activity API)";
}
bool
roctracer::is_setup()
{
return roctracer_is_setup();
}
void
roctracer::add_setup(const std::string& _lbl, std::function<void()>&& _func)
{
roctracer_setup_routines().emplace_back(_lbl, std::move(_func));
}
void
roctracer::add_tear_down(const std::string& _lbl, std::function<void()>&& _func)
{
roctracer_tear_down_routines().emplace_back(_lbl, std::move(_func));
}
void
roctracer::remove_setup(const std::string& _lbl)
{
auto& _data = roctracer_setup_routines();
for(auto itr = _data.begin(); itr != _data.end(); ++itr)
{
if(itr->first == _lbl)
{
_data.erase(itr);
break;
}
}
}
void
roctracer::remove_tear_down(const std::string& _lbl)
{
auto& _data = roctracer_setup_routines();
for(auto itr = _data.begin(); itr != _data.end(); ++itr)
{
if(itr->first == _lbl)
{
_data.erase(itr);
break;
}
}
}
void
roctracer::setup()
{
if(!get_use_timemory() && !get_use_perfetto()) return;
auto_lock_t _lk{ type_mutex<roctracer>() };
if(roctracer_is_setup()) return;
roctracer_is_setup() = true;
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
tim::set_env("HSA_TOOLS_LIB", "libhosttrace.so", 0);
auto _kfdwrapper = dynamic_library{ "HOSTTRACE_ROCTRACER_LIBKFDWRAPPER",
HOSTTRACE_ROCTRACER_LIBKFDWRAPPER };
ROCTRACER_CALL(roctracer_set_properties(ACTIVITY_DOMAIN_HIP_API, nullptr));
// if(roctracer_default_pool() == nullptr)
{
// Allocating tracing pool
roctracer_properties_t properties{};
memset(&properties, 0, sizeof(roctracer_properties_t));
properties.mode = 0x1000;
properties.buffer_size = 0x1000;
properties.buffer_callback_fun = hip_activity_callback;
ROCTRACER_CALL(roctracer_open_pool(&properties));
}
// Enable API callbacks, all domains
ROCTRACER_CALL(roctracer_enable_callback(hip_api_callback, nullptr));
// Enable activity tracing, all domains
ROCTRACER_CALL(roctracer_enable_activity());
// callback for HSA
for(auto& itr : roctracer_setup_routines())
itr.second();
}
void
roctracer::tear_down()
{
auto_lock_t _lk{ type_mutex<roctracer>() };
if(!roctracer_is_setup()) return;
roctracer_is_setup() = false;
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
// flush all the activity
if(roctracer_default_pool() != nullptr)
{
ROCTRACER_CALL(roctracer_flush_activity());
}
// flush all buffers
roctracer_flush_buf();
// make sure all async operations are executed
for(size_t i = 0; i < max_supported_threads; ++i)
hip_exec_activity_callbacks(i);
// callback for hsa
for(auto& itr : roctracer_tear_down_routines())
itr.second();
// Disable tracing and closing the pool
ROCTRACER_CALL(roctracer_disable_callback());
ROCTRACER_CALL(roctracer_disable_activity());
ROCTRACER_CALL(roctracer_close_pool());
}
void
roctracer::start()
{
if(tracker_type::start() == 0) setup();
}
void
roctracer::stop()
{
if(tracker_type::stop() == 0) tear_down();
}
} // namespace component
} // namespace tim
TIMEMORY_INSTANTIATE_EXTERN_COMPONENT(roctracer, false, void)
TIMEMORY_INSTANTIATE_EXTERN_COMPONENT(roctracer_data, true, double)
// HSA-runtime tool on-load method
extern "C"
{
bool OnLoad(HsaApiTable* table, uint64_t runtime_version, uint64_t failed_tool_count,
const char* const* failed_tool_names) TIMEMORY_VISIBILITY("default");
void OnUnload() TIMEMORY_VISIBILITY("default");
bool OnLoad(HsaApiTable* table, uint64_t runtime_version, uint64_t failed_tool_count,
const char* const* failed_tool_names)
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
tim::consume_parameters(table, runtime_version, failed_tool_count,
failed_tool_names);
// ONLOAD_TRACE_BEG();
// on_exit(exit_handler, nullptr);
auto _setup = [=]() {
get_hsa_timer() =
std::make_unique<hsa_timer_t>(table->core_->hsa_system_get_info_fn);
// const char* output_prefix = getenv("ROCP_OUTPUT_DIR");
const char* output_prefix = nullptr;
// App begin timestamp begin_ts_file.txt
// begin_ts_file_handle = open_output_file(output_prefix,
// "begin_ts_file.txt"); const timestamp_t app_start_time =
// timer->timestamp_fn_ns(); fprintf(begin_ts_file_handle, "%lu\n",
// app_start_time);
bool trace_hsa_api = get_trace_hsa_api();
std::vector<std::string> hsa_api_vec =
tim::delimit(get_trace_hsa_api_types());
// Enable HSA API callbacks/activity
if(trace_hsa_api)
{
// hsa_api_file_handle = open_output_file(output_prefix,
// "hsa_api_trace.txt");
// initialize HSA tracing
roctracer_set_properties(ACTIVITY_DOMAIN_HSA_API, (void*) table);
HOSTTRACE_DEBUG(" HSA-trace(");
if(!hsa_api_vec.empty())
{
for(const auto& itr : hsa_api_vec)
{
uint32_t cid = HSA_API_ID_NUMBER;
const char* api = itr.c_str();
ROCTRACER_CALL(roctracer_op_code(ACTIVITY_DOMAIN_HSA_API, api,
&cid, nullptr));
ROCTRACER_CALL(roctracer_enable_op_callback(
ACTIVITY_DOMAIN_HSA_API, cid, hsa_api_callback, nullptr));
HOSTTRACE_DEBUG(" %s", api);
}
}
else
{
ROCTRACER_CALL(roctracer_enable_domain_callback(
ACTIVITY_DOMAIN_HSA_API, hsa_api_callback, nullptr));
}
HOSTTRACE_DEBUG("\n");
}
bool trace_hsa_activity = get_trace_hsa_activity();
// Enable HSA GPU activity
if(trace_hsa_activity)
{
// initialize HSA tracing
::roctracer::hsa_ops_properties_t ops_properties{
table,
reinterpret_cast<activity_async_callback_t>(hsa_activity_callback),
nullptr, output_prefix
};
roctracer_set_properties(ACTIVITY_DOMAIN_HSA_OPS, &ops_properties);
HOSTTRACE_DEBUG(" HSA-activity-trace()\n");
ROCTRACER_CALL(roctracer_enable_op_activity(ACTIVITY_DOMAIN_HSA_OPS,
HSA_OP_ID_COPY));
}
};
auto _tear_down = []() {
ROCTRACER_CALL(roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HSA_API));
ROCTRACER_CALL(
roctracer_disable_op_activity(ACTIVITY_DOMAIN_HSA_OPS, HSA_OP_ID_COPY));
};
if(comp::roctracer::is_setup()) _setup();
comp::roctracer::add_setup("hsa", std::move(_setup));
comp::roctracer::add_tear_down("hsa", std::move(_tear_down));
return true;
}
// HSA-runtime on-unload method
void OnUnload()
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
// ONLOAD_TRACE("");
}
}
@@ -0,0 +1,599 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "library/roctracer_callbacks.hpp"
#include "library.hpp"
#include "library/config.hpp"
#include "library/critical_trace.hpp"
#include "library/thread_data.hpp"
#include "timemory/backends/threading.hpp"
#include <cstdint>
TIMEMORY_DEFINE_API(roctracer)
namespace api = tim::api;
std::unordered_set<uint64_t>&
get_roctracer_kernels()
{
static auto _v = std::unordered_set<uint64_t>{};
return _v;
}
auto&
get_roctracer_hip_data(int64_t _tid = threading::get_id())
{
using data_t = std::unordered_map<uint64_t, roctracer_bundle_t>;
using thread_data_t = hosttrace_thread_data<data_t, api::roctracer>;
static auto& _v = thread_data_t::instances(thread_data_t::construct_on_init{});
return _v.at(_tid);
}
std::unordered_map<uint64_t, const char*>&
get_roctracer_key_data()
{
static auto _v = std::unordered_map<uint64_t, const char*>{};
return _v;
}
std::unordered_map<uint64_t, int64_t>&
get_roctracer_tid_data()
{
static auto _v = std::unordered_map<uint64_t, int64_t>{};
return _v;
}
using cid_tuple_t = std::tuple<uint64_t, uint64_t, uint16_t>;
std::unordered_map<uint64_t, cid_tuple_t>&
get_roctracer_cid_data()
{
static auto _v = std::unordered_map<uint64_t, cid_tuple_t>{};
return _v;
}
auto&
get_hip_activity_callbacks(int64_t _tid = threading::get_id())
{
using thread_data_t =
hosttrace_thread_data<std::vector<std::function<void()>>, api::roctracer>;
static auto& _v = thread_data_t::instances(thread_data_t::construct_on_init{});
return _v.at(_tid);
}
std::unique_ptr<hsa_timer_t>&
get_hsa_timer()
{
static auto _v = std::unique_ptr<hsa_timer_t>{};
return _v;
}
using hip_activity_mutex_t = std::decay_t<decltype(get_hip_activity_callbacks())>;
using key_data_mutex_t = std::decay_t<decltype(get_roctracer_key_data())>;
using hip_data_mutex_t = std::decay_t<decltype(get_roctracer_hip_data())>;
using cid_data_mutex_t = std::decay_t<decltype(get_roctracer_cid_data())>;
auto&
get_hip_activity_mutex(int64_t _tid = threading::get_id())
{
return tim::type_mutex<hip_activity_mutex_t, api::roctracer, max_supported_threads>(
_tid);
}
// HSA API callback function
void
hsa_api_callback(uint32_t domain, uint32_t cid, const void* callback_data, void* arg)
{
if(get_state() != State::Active || !trait::runtime_enabled<comp::roctracer>::get())
return;
(void) arg;
const hsa_api_data_t* data = reinterpret_cast<const hsa_api_data_t*>(callback_data);
HOSTTRACE_DEBUG("<%-30s id(%u)\tcorrelation_id(%lu) %s>\n",
roctracer_op_string(domain, cid, 0), cid, data->correlation_id,
(data->phase == ACTIVITY_API_PHASE_ENTER) ? "on-enter" : "on-exit");
static thread_local timestamp_t begin_timestamp = 0;
static auto& timer = get_hsa_timer();
static auto _scope = []() {
auto _v = scope::config{};
if(get_roctracer_timeline_profile()) _v += scope::timeline{};
if(get_roctracer_flat_profile()) _v += scope::flat{};
return _v;
}();
if(!timer) return;
switch(cid)
{
case HSA_API_ID_hsa_init:
case HSA_API_ID_hsa_shut_down:
case HSA_API_ID_hsa_agent_get_exception_policies:
case HSA_API_ID_hsa_agent_get_info:
case HSA_API_ID_hsa_amd_agent_iterate_memory_pools:
case HSA_API_ID_hsa_amd_agent_memory_pool_get_info:
case HSA_API_ID_hsa_amd_coherency_get_type:
case HSA_API_ID_hsa_amd_memory_pool_get_info:
case HSA_API_ID_hsa_amd_pointer_info:
case HSA_API_ID_hsa_amd_pointer_info_set_userdata:
case HSA_API_ID_hsa_amd_profiling_async_copy_enable:
case HSA_API_ID_hsa_amd_profiling_get_async_copy_time:
case HSA_API_ID_hsa_amd_profiling_get_dispatch_time:
case HSA_API_ID_hsa_amd_profiling_set_profiler_enabled:
case HSA_API_ID_hsa_cache_get_info:
case HSA_API_ID_hsa_code_object_get_info:
case HSA_API_ID_hsa_code_object_get_symbol:
case HSA_API_ID_hsa_code_object_get_symbol_from_name:
case HSA_API_ID_hsa_code_object_reader_create_from_memory:
case HSA_API_ID_hsa_code_symbol_get_info:
case HSA_API_ID_hsa_executable_create_alt:
case HSA_API_ID_hsa_executable_freeze:
case HSA_API_ID_hsa_executable_get_info:
case HSA_API_ID_hsa_executable_get_symbol:
case HSA_API_ID_hsa_executable_get_symbol_by_name:
case HSA_API_ID_hsa_executable_symbol_get_info:
case HSA_API_ID_hsa_extension_get_name:
case HSA_API_ID_hsa_ext_image_data_get_info:
case HSA_API_ID_hsa_ext_image_data_get_info_with_layout:
case HSA_API_ID_hsa_ext_image_get_capability:
case HSA_API_ID_hsa_ext_image_get_capability_with_layout:
case HSA_API_ID_hsa_isa_get_exception_policies:
case HSA_API_ID_hsa_isa_get_info:
case HSA_API_ID_hsa_isa_get_info_alt:
case HSA_API_ID_hsa_isa_get_round_method:
case HSA_API_ID_hsa_region_get_info:
case HSA_API_ID_hsa_system_extension_supported:
case HSA_API_ID_hsa_system_get_extension_table:
case HSA_API_ID_hsa_system_get_info:
case HSA_API_ID_hsa_system_get_major_extension_table:
case HSA_API_ID_hsa_wavefront_get_info: break;
default:
{
if(data->phase == ACTIVITY_API_PHASE_ENTER)
{
begin_timestamp = timer->timestamp_fn_ns();
}
else
{
const auto* _name = roctracer_op_string(domain, cid, 0);
const timestamp_t end_timestamp = (cid == HSA_API_ID_hsa_shut_down)
? begin_timestamp
: timer->timestamp_fn_ns();
if(begin_timestamp > end_timestamp) return;
if(get_use_perfetto())
{
TRACE_EVENT_BEGIN("device", perfetto::StaticString{ _name },
begin_timestamp);
TRACE_EVENT_END("device", end_timestamp);
}
if(get_use_timemory())
{
std::unique_lock<std::mutex> _lk{ tasking::get_roctracer_mutex() };
auto _begin_ns = begin_timestamp;
auto _end_ns = end_timestamp;
tasking::get_roctracer_task_group().exec(
[_name, _begin_ns, _end_ns]() {
roctracer_hsa_bundle_t _bundle{ _name, _scope };
_bundle.start()
.store(std::plus<double>{},
static_cast<double>(_end_ns - _begin_ns))
.stop();
});
}
// timemory is disabled in this callback because collecting data in this
// thread causes strange segmentation faults
}
}
}
}
void
hsa_activity_callback(uint32_t op, activity_record_t* record, void* arg)
{
static const char* copy_op_name = "hsa_async_copy";
static const char* dispatch_op_name = "hsa_dispatch";
static const char* barrier_op_name = "hsa_barrier";
const char** _name = nullptr;
switch(op)
{
case HSA_OP_ID_DISPATCH: _name = &dispatch_op_name; break;
case HSA_OP_ID_COPY: _name = &copy_op_name; break;
case HSA_OP_ID_BARRIER: _name = &barrier_op_name; break;
default: break;
}
if(!_name) return;
auto _begin_ns = record->begin_ns;
auto _end_ns = record->end_ns;
static auto _scope = []() {
auto _v = scope::config{};
if(get_roctracer_timeline_profile()) _v += scope::timeline{};
if(get_roctracer_flat_profile()) _v += scope::flat{};
return _v;
}();
auto _func = [_begin_ns, _end_ns, _name]() {
if(get_use_perfetto())
{
TRACE_EVENT_BEGIN("device", perfetto::StaticString{ *_name }, _begin_ns);
TRACE_EVENT_END("device", _end_ns);
}
if(get_use_timemory())
{
roctracer_hsa_bundle_t _bundle{ *_name, _scope };
_bundle.start()
.store(std::plus<double>{}, static_cast<double>(_end_ns - _begin_ns))
.stop();
}
};
std::unique_lock<std::mutex> _lk{ tasking::get_roctracer_mutex() };
tasking::get_roctracer_task_group().exec(_func);
// timemory is disabled in this callback because collecting data in this thread
// causes strange segmentation faults
tim::consume_parameters(arg);
}
void
hip_exec_activity_callbacks(int64_t _tid)
{
// ROCTRACER_CALL(roctracer_flush_activity());
tim::auto_lock_t _lk{ get_hip_activity_mutex(_tid) };
auto& _async_ops = get_hip_activity_callbacks(_tid);
for(auto& itr : *_async_ops)
itr();
_async_ops->clear();
}
namespace
{
thread_local std::unordered_map<size_t, size_t> gpu_cids = {};
}
// HIP API callback function
void
hip_api_callback(uint32_t domain, uint32_t cid, const void* callback_data, void* arg)
{
if(get_state() != State::Active || !trait::runtime_enabled<comp::roctracer>::get())
return;
using Device = critical_trace::Device;
using Phase = critical_trace::Phase;
const char* op_name = roctracer_op_string(domain, cid, 0);
if(op_name == nullptr) op_name = hip_api_name(cid);
if(op_name == nullptr) return;
const hip_api_data_t* data = reinterpret_cast<const hip_api_data_t*>(callback_data);
HOSTTRACE_DEBUG("<%-30s id(%u)\tcorrelation_id(%lu) %s>\n", op_name, cid,
data->correlation_id,
(data->phase == ACTIVITY_API_PHASE_ENTER) ? "on-enter" : "on-exit");
switch(cid)
{
case HIP_API_ID___hipPushCallConfiguration:
case HIP_API_ID___hipPopCallConfiguration:
case HIP_API_ID_hipDeviceEnablePeerAccess:
case HIP_API_ID_hipImportExternalMemory:
case HIP_API_ID_hipDestroyExternalMemory: return;
default: break;
}
if(data->phase == ACTIVITY_API_PHASE_ENTER)
{
switch(cid)
{
case HIP_API_ID_hipLaunchKernel:
case HIP_API_ID_hipLaunchCooperativeKernel:
{
const char* _name =
hipKernelNameRefByPtr(data->args.hipLaunchKernel.function_address,
data->args.hipLaunchKernel.stream);
if(_name != nullptr)
{
if(get_use_perfetto() || get_use_timemory())
{
tim::auto_lock_t _lk{ tim::type_mutex<key_data_mutex_t>() };
get_roctracer_key_data().emplace(data->correlation_id, _name);
get_roctracer_tid_data().emplace(data->correlation_id,
threading::get_id());
}
}
break;
}
case HIP_API_ID_hipModuleLaunchKernel:
{
const char* _name = hipKernelNameRef(data->args.hipModuleLaunchKernel.f);
if(_name != nullptr)
{
if(get_use_perfetto() || get_use_timemory())
{
tim::auto_lock_t _lk{ tim::type_mutex<key_data_mutex_t>() };
get_roctracer_key_data().emplace(data->correlation_id, _name);
get_roctracer_tid_data().emplace(data->correlation_id,
threading::get_id());
}
}
break;
}
default:
{
if(get_use_perfetto() || get_use_timemory())
{
tim::auto_lock_t _lk{ tim::type_mutex<key_data_mutex_t>() };
get_roctracer_key_data().emplace(data->correlation_id, op_name);
get_roctracer_tid_data().emplace(data->correlation_id,
threading::get_id());
}
}
}
if(get_use_perfetto())
{
TRACE_EVENT_BEGIN("device", perfetto::StaticString{ op_name });
}
if(get_use_timemory())
{
get_roctracer_hip_data()->emplace(
data->correlation_id,
roctracer_bundle_t{ op_name, quirk::config<quirk::auto_start>{} });
}
if(get_use_critical_trace())
{
auto _cid = get_cpu_cid()++;
uint16_t _depth = (get_cpu_cid_stack()->empty())
? get_cpu_cid_stack(0)->size()
: get_cpu_cid_stack()->size() - 1;
auto _parent_cid = (get_cpu_cid_stack()->empty())
? get_cpu_cid_stack(0)->back()
: get_cpu_cid_stack()->back();
int64_t _ts = comp::wall_clock::record();
add_critical_trace<Device::GPU, Phase::BEGIN>(
threading::get_id(), _cid, data->correlation_id, _parent_cid, _ts, 0,
critical_trace::add_hash_id(op_name), _depth);
tim::auto_lock_t _lk{ tim::type_mutex<cid_data_mutex_t>() };
get_roctracer_cid_data().emplace(data->correlation_id,
cid_tuple_t{ _cid, _parent_cid, _depth });
}
hip_exec_activity_callbacks(threading::get_id());
}
else if(data->phase == ACTIVITY_API_PHASE_EXIT)
{
hip_exec_activity_callbacks(threading::get_id());
if(get_use_perfetto())
{
TRACE_EVENT_END("device");
}
if(get_use_timemory())
{
auto _stop = [data](int64_t _tid) {
auto& _data = get_roctracer_hip_data(_tid);
auto itr = _data->find(data->correlation_id);
if(itr != get_roctracer_hip_data()->end())
{
itr->second.stop().pop();
_data->erase(itr);
return true;
}
return false;
};
if(!_stop(threading::get_id()))
{
for(size_t i = 0; i < max_supported_threads; ++i)
{
if(_stop(i)) break;
}
}
}
if(get_use_critical_trace())
{
uint16_t _depth = 0;
uint64_t _cid = 0;
uint64_t _parent_cid = 0;
{
tim::auto_lock_t _lk{ tim::type_mutex<cid_data_mutex_t>() };
std::tie(_cid, _parent_cid, _depth) =
get_roctracer_cid_data().at(data->correlation_id);
}
int64_t _ts = comp::wall_clock::record();
add_critical_trace<Device::GPU, Phase::END>(
threading::get_id(), _cid, data->correlation_id, _parent_cid, _ts, _ts,
critical_trace::add_hash_id(op_name), _depth);
}
}
tim::consume_parameters(arg);
}
// Activity tracing callback
void
hip_activity_callback(const char* begin, const char* end, void*)
{
using Device = critical_trace::Device;
using Phase = critical_trace::Phase;
if(!trait::runtime_enabled<comp::roctracer>::get()) return;
static auto _kernel_names = std::unordered_map<const char*, std::string>{};
static auto _indexes = std::unordered_map<uint64_t, int>{};
const roctracer_record_t* record = reinterpret_cast<const roctracer_record_t*>(begin);
const roctracer_record_t* end_record =
reinterpret_cast<const roctracer_record_t*>(end);
HOSTTRACE_DEBUG("Activity records:\n");
while(record < end_record)
{
const char* op_name =
roctracer_op_string(record->domain, record->correlation_id, 0);
if(op_name == nullptr) op_name = hip_api_name(record->correlation_id);
if(op_name != nullptr)
{
HOSTTRACE_DEBUG("\t%-30s\tcorrelation_id(%6lu) time_ns(%12lu:%12lu) "
"delta_ns(%12lu) device_id(%d) "
"stream_id(%lu)\n",
op_name, record->correlation_id, record->begin_ns,
record->end_ns, (record->end_ns - record->begin_ns),
record->device_id, record->queue_id);
}
auto _begin_ns = record->begin_ns;
auto _end_ns = record->end_ns;
auto _corr_id = record->correlation_id;
static auto _scope = []() {
auto _v = scope::config{};
if(get_roctracer_timeline_profile()) _v += scope::timeline{};
if(get_roctracer_flat_profile()) _v += scope::flat{};
return _v;
}();
auto& _keys = get_roctracer_key_data();
auto& _cids = get_roctracer_cid_data();
auto& _tids = get_roctracer_tid_data();
int16_t _depth = 0; // depth of kernel launch
int64_t _tid = 0; // thread id
uint64_t _cid = 0; // correlation id
uint64_t _pcid = 0; // parent corr_id
auto _laps = _indexes[_corr_id]++; // see note #1
const char* _name = nullptr;
bool _found = false;
bool _critical_trace = get_use_critical_trace();
{
tim::auto_lock_t _lk{ tim::type_mutex<key_data_mutex_t>() };
if(_tids.find(_corr_id) != _tids.end())
{
_found = true;
_tid = _tids.at(_corr_id);
auto itr = _keys.find(_corr_id);
if(itr != _keys.end()) _name = itr->second;
}
}
if(_critical_trace)
{
tim::auto_lock_t _lk{ tim::type_mutex<cid_data_mutex_t>() };
if(_cids.find(_corr_id) != _cids.end())
std::tie(_cid, _pcid, _depth) = _cids.at(_corr_id);
else
_critical_trace = false;
}
auto _func = [_critical_trace, _depth, _tid, _cid, _laps, _begin_ns, _end_ns,
_corr_id, _name]() {
// NOTE #1: we get two measurements for 1 kernel so we need to
// tweak the number of laps for the wall-clock component
if(_name != nullptr)
{
if(get_use_perfetto())
{
if(_kernel_names.find(_name) == _kernel_names.end())
_kernel_names.emplace(_name, tim::demangle(_name));
TRACE_EVENT_BEGIN(
"device",
perfetto::StaticString{ _kernel_names.at(_name).c_str() },
_begin_ns);
TRACE_EVENT_END("device", _end_ns);
}
if(get_use_timemory())
{
roctracer_bundle_t _bundle{ _name, _scope };
_bundle.start()
.store(std::plus<double>{},
static_cast<double>(_end_ns - _begin_ns))
.stop()
.get<comp::wall_clock>([&](comp::wall_clock* wc) {
wc->set_value(_end_ns - _begin_ns);
wc->set_accum(_end_ns - _begin_ns);
if(_laps % 2 == 1)
{
// below is a hack bc we get two measurements for 1 kernel
wc->set_laps(0);
auto itr = wc->get_iterator();
if(itr && itr->data().get_laps() == 0)
{
wc->set_is_invalid(true);
itr->data().set_is_invalid(true);
}
}
return wc;
});
_bundle.pop();
}
if(_critical_trace)
{
auto _hash = critical_trace::add_hash_id(_name);
uint16_t _prio = _laps + 1; // priority
add_critical_trace<Device::GPU, Phase::DELTA, false>(
_tid, _cid, _corr_id, _cid, _begin_ns, _end_ns, _hash, _depth + 1,
_prio);
}
}
};
if(_found)
{
auto& _async_ops = get_hip_activity_callbacks(_tid);
tim::auto_lock_t _lk{ get_hip_activity_mutex(_tid) };
_async_ops->emplace_back(std::move(_func));
}
ROCTRACER_CALL(roctracer_next_record(record, &record));
}
}
bool&
roctracer_is_setup()
{
static bool _v = false;
return _v;
}
using roctracer_functions_t = std::vector<std::pair<std::string, std::function<void()>>>;
roctracer_functions_t&
roctracer_setup_routines()
{
static auto _v = roctracer_functions_t{};
return _v;
}
roctracer_functions_t&
roctracer_tear_down_routines()
{
static auto _v = roctracer_functions_t{};
return _v;
}
@@ -0,0 +1,36 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "library/thread_data.hpp"
instrumentation_bundles::instance_array_t&
instrumentation_bundles::instances()
{
static auto _v = instance_array_t{};
return _v;
}
@@ -0,0 +1,31 @@
// Copyright (c) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// with the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the names of Advanced Micro Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this Software without specific prior written permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
#include "library/timemory.hpp"
TIMEMORY_INITIALIZE_STORAGE(comp::wall_clock, comp::user_global_bundle)
@@ -1,645 +0,0 @@
#include "roctracer.hpp"
#include "library.hpp"
#include <roctracer.h>
#include <roctracer_ext.h>
#include <roctracer_hcc.h>
#include <roctracer_hip.h>
#include <roctracer_kfd.h>
#define AMD_INTERNAL_BUILD 1
#include <ext/hsa_rt_utils.hpp>
#include <roctracer_hsa.h>
#include <atomic>
// Macro to check ROC-tracer calls status
#define ROCTRACER_CALL(call) \
do \
{ \
int err = call; \
if(err != 0) \
{ \
std::cerr << roctracer_error_string() << " in: " << #call << std::flush; \
} \
} while(0)
using roctracer_bundle_t = tim::component_tuple<comp::roctracer_data>;
namespace units = tim::units;
namespace
{
auto&
get_roctracer_kernels()
{
static auto _v = std::unordered_set<uint64_t>{};
return _v;
}
auto&
get_roctracer_hip_data()
{
static auto _v = std::unordered_map<uint64_t, roctracer_bundle_t>{};
return _v;
}
auto&
get_roctracer_key_data()
{
static auto _v = std::unordered_map<uint64_t, const char*>{};
return _v;
}
using data_type_mutex_t = std::decay_t<decltype(get_roctracer_hip_data())>;
using hsa_timer_t = hsa_rt_utils::Timer;
using timestamp_t = hsa_timer_t::timestamp_t;
auto&
get_hsa_timer()
{
static auto _v = std::unique_ptr<hsa_timer_t>{};
return _v;
}
// HSA API callback function
void
hsa_api_callback(uint32_t domain, uint32_t cid, const void* callback_data, void* arg)
{
if(get_state() != State::Active || !trait::runtime_enabled<comp::roctracer>::get())
return;
(void) arg;
static auto _scope = scope::config{} + scope::flat{};
const hsa_api_data_t* data = reinterpret_cast<const hsa_api_data_t*>(callback_data);
HOSTTRACE_DEBUG("<%-30s id(%u)\tcorrelation_id(%lu) %s>\n",
roctracer_op_string(domain, cid, 0), cid, data->correlation_id,
(data->phase == ACTIVITY_API_PHASE_ENTER) ? "on-enter" : "on-exit");
static thread_local timestamp_t hsa_begin_timestamp = 0;
static auto& timer = get_hsa_timer();
if(!timer) return;
switch(cid)
{
case HSA_API_ID_hsa_init:
case HSA_API_ID_hsa_shut_down:
case HSA_API_ID_hsa_agent_get_exception_policies:
case HSA_API_ID_hsa_agent_get_info:
case HSA_API_ID_hsa_amd_agent_iterate_memory_pools:
case HSA_API_ID_hsa_amd_agent_memory_pool_get_info:
case HSA_API_ID_hsa_amd_coherency_get_type:
case HSA_API_ID_hsa_amd_memory_pool_get_info:
case HSA_API_ID_hsa_amd_pointer_info:
case HSA_API_ID_hsa_amd_pointer_info_set_userdata:
case HSA_API_ID_hsa_amd_profiling_async_copy_enable:
case HSA_API_ID_hsa_amd_profiling_get_async_copy_time:
case HSA_API_ID_hsa_amd_profiling_get_dispatch_time:
case HSA_API_ID_hsa_amd_profiling_set_profiler_enabled:
case HSA_API_ID_hsa_cache_get_info:
case HSA_API_ID_hsa_code_object_get_info:
case HSA_API_ID_hsa_code_object_get_symbol:
case HSA_API_ID_hsa_code_object_get_symbol_from_name:
case HSA_API_ID_hsa_code_object_reader_create_from_memory:
case HSA_API_ID_hsa_code_symbol_get_info:
case HSA_API_ID_hsa_executable_create_alt:
case HSA_API_ID_hsa_executable_freeze:
case HSA_API_ID_hsa_executable_get_info:
case HSA_API_ID_hsa_executable_get_symbol:
case HSA_API_ID_hsa_executable_get_symbol_by_name:
case HSA_API_ID_hsa_executable_symbol_get_info:
case HSA_API_ID_hsa_extension_get_name:
case HSA_API_ID_hsa_ext_image_data_get_info:
case HSA_API_ID_hsa_ext_image_data_get_info_with_layout:
case HSA_API_ID_hsa_ext_image_get_capability:
case HSA_API_ID_hsa_ext_image_get_capability_with_layout:
case HSA_API_ID_hsa_isa_get_exception_policies:
case HSA_API_ID_hsa_isa_get_info:
case HSA_API_ID_hsa_isa_get_info_alt:
case HSA_API_ID_hsa_isa_get_round_method:
case HSA_API_ID_hsa_region_get_info:
case HSA_API_ID_hsa_system_extension_supported:
case HSA_API_ID_hsa_system_get_extension_table:
case HSA_API_ID_hsa_system_get_info:
case HSA_API_ID_hsa_system_get_major_extension_table:
case HSA_API_ID_hsa_wavefront_get_info: break;
default:
{
if(data->phase == ACTIVITY_API_PHASE_ENTER)
{
hsa_begin_timestamp = timer->timestamp_fn_ns();
}
else
{
auto _name = roctracer_op_string(domain, cid, 0);
const timestamp_t end_timestamp = (cid == HSA_API_ID_hsa_shut_down)
? hsa_begin_timestamp
: timer->timestamp_fn_ns();
if(get_use_perfetto())
{
TRACE_EVENT_BEGIN("device", perfetto::StaticString{ _name },
hsa_begin_timestamp);
TRACE_EVENT_END("device", end_timestamp);
}
/*if(get_use_timemory())
{
static auto _scope = scope::flat() + scope::timeline();
roctracer_bundle_t{ _name, _scope }
.start()
.store(end_timestamp - hsa_begin_timestamp)
.stop();
}*/
// timemory is disabled in this callback because collecting data in this
// thread causes strange segmentation faults
}
}
}
}
void
hsa_activity_callback(uint32_t op, activity_record_t* record, void* arg)
{
static const char* copy_op_name = "hsa_async_copy";
static const char* dispatch_op_name = "hsa_dispatch";
static const char* barrier_op_name = "hsa_barrier";
const char** _name = nullptr;
switch(op)
{
case HSA_OP_ID_DISPATCH: _name = &dispatch_op_name; break;
case HSA_OP_ID_COPY: _name = &copy_op_name; break;
case HSA_OP_ID_BARRIER: _name = &barrier_op_name; break;
default: break;
}
if(!_name) return;
if(get_use_perfetto())
{
TRACE_EVENT_BEGIN("device", perfetto::StaticString{ *_name }, record->begin_ns);
TRACE_EVENT_END("device", record->end_ns);
}
// timemory is disabled in this callback because collecting data in this thread
// causes strange segmentation faults
tim::consume_parameters(arg);
}
// HIP API callback function
void
hip_api_callback(uint32_t domain, uint32_t cid, const void* callback_data, void* arg)
{
if(get_state() != State::Active || !trait::runtime_enabled<comp::roctracer>::get())
return;
static auto _scope = scope::flat() + scope::timeline();
const hip_api_data_t* data = reinterpret_cast<const hip_api_data_t*>(callback_data);
HOSTTRACE_DEBUG("<%-30s id(%u)\tcorrelation_id(%lu) %s>\n",
roctracer_op_string(domain, cid, 0), cid, data->correlation_id,
(data->phase == ACTIVITY_API_PHASE_ENTER) ? "on-enter" : "on-exit");
if(data->phase == ACTIVITY_API_PHASE_ENTER)
{
switch(cid)
{
case HIP_API_ID___hipPushCallConfiguration:
case HIP_API_ID___hipPopCallConfiguration: break;
case HIP_API_ID_hipLaunchKernel:
{
const char* _name =
hipKernelNameRefByPtr(data->args.hipLaunchKernel.function_address,
data->args.hipLaunchKernel.stream);
tim::auto_lock_t _lk{ tim::type_mutex<data_type_mutex_t>() };
get_roctracer_kernels().emplace(data->correlation_id);
if(get_use_perfetto())
{
get_roctracer_key_data().emplace(data->correlation_id, _name);
}
if(get_use_timemory())
{
get_roctracer_hip_data().emplace(data->correlation_id,
roctracer_bundle_t{ _name, _scope });
}
break;
}
case HIP_API_ID_hipModuleLaunchKernel:
{
const char* _name = hipKernelNameRef(data->args.hipModuleLaunchKernel.f);
tim::auto_lock_t _lk{ tim::type_mutex<data_type_mutex_t>() };
get_roctracer_kernels().emplace(data->correlation_id);
if(get_use_perfetto())
{
get_roctracer_key_data().emplace(data->correlation_id, _name);
}
if(get_use_timemory())
{
get_roctracer_hip_data().emplace(data->correlation_id,
roctracer_bundle_t{ _name, _scope });
}
break;
}
default:
{
tim::auto_lock_t _lk{ tim::type_mutex<data_type_mutex_t>() };
const char* _name = roctracer_op_string(domain, cid, 0);
if(get_use_perfetto())
{
get_roctracer_key_data().emplace(data->correlation_id, _name);
}
if(get_use_timemory())
{
get_roctracer_hip_data().emplace(data->correlation_id,
roctracer_bundle_t{ _name, _scope });
}
break;
}
}
}
else if(data->phase == ACTIVITY_API_PHASE_EXIT)
{}
tim::consume_parameters(domain, arg);
}
// Activity tracing callback
void
hip_activity_callback(const char* begin, const char* end, void*)
{
if(!trait::runtime_enabled<comp::roctracer>::get()) return;
static auto _kernel_names = std::unordered_map<const char*, std::string>{};
const roctracer_record_t* record = reinterpret_cast<const roctracer_record_t*>(begin);
const roctracer_record_t* end_record =
reinterpret_cast<const roctracer_record_t*>(end);
std::unordered_set<uint64_t> _indexes{};
tim::auto_lock_t _lk{ tim::type_mutex<data_type_mutex_t>() };
auto& _data = get_roctracer_hip_data();
auto& _keys = get_roctracer_key_data();
auto& _kernels = get_roctracer_kernels();
HOSTTRACE_DEBUG("Activity records:\n");
while(record < end_record)
{
HOSTTRACE_DEBUG("\t%-30s\tcorrelation_id(%lu) time_ns(%lu:%lu) device_id(%d) "
"stream_id(%lu)\n",
roctracer_op_string(record->domain, record->correlation_id, 0),
record->correlation_id, record->begin_ns, record->end_ns,
record->device_id, record->queue_id);
auto _is_kernel = _kernels.find(record->correlation_id) != _kernels.end();
if(_is_kernel && record->device_id != 0 && record->queue_id != 0)
{
// these are overheads associated with the kernel launch, not kernel runtime
ROCTRACER_CALL(roctracer_next_record(record, &record));
continue;
}
auto kitr =
(get_use_perfetto()) ? _keys.find(record->correlation_id) : _keys.end();
if(kitr != _keys.end())
{
if(_kernel_names.find(kitr->second) == _kernel_names.end())
_kernel_names.emplace(kitr->second, tim::demangle(kitr->second));
TRACE_EVENT_BEGIN(
"device",
perfetto::StaticString{ _kernel_names.at(kitr->second).c_str() },
record->begin_ns);
TRACE_EVENT_END("device", record->end_ns);
_indexes.emplace(kitr->first);
}
auto itr =
(get_use_timemory()) ? _data.find(record->correlation_id) : _data.end();
if(itr != _data.end())
{
itr->second.start()
.store(std::plus<double>{},
static_cast<double>(record->end_ns - record->begin_ns))
.stop();
_indexes.emplace(itr->first);
}
// code
ROCTRACER_CALL(roctracer_next_record(record, &record));
}
if(get_use_perfetto())
{
for(auto& itr : _indexes)
_keys.erase(itr);
}
if(get_use_timemory())
{
for(auto& itr : _indexes)
_data.erase(itr);
}
HOSTTRACE_DEBUG("[%s] recorded %lu phases\n", __FUNCTION__,
(unsigned long) _indexes.size());
}
bool&
roctracer_is_setup()
{
static bool _v = false;
return _v;
}
using roctracer_functions_t = std::vector<std::pair<std::string, std::function<void()>>>;
auto&
roctracer_setup_routines()
{
static auto _v = roctracer_functions_t{};
return _v;
}
auto&
roctracer_tear_down_routines()
{
static auto _v = roctracer_functions_t{};
return _v;
}
} // namespace
#if !defined(HOSTTRACE_ROCTRACER_LIBKFDWRAPPER)
# define HOSTTRACE_ROCTRACER_LIBKFDWRAPPER "/opt/rocm/roctracer/lib/libkfdwrapper64.so"
#endif
struct dynamic_library
{
dynamic_library() = delete;
dynamic_library(const dynamic_library&) = delete;
dynamic_library(dynamic_library&&) noexcept = default;
dynamic_library& operator=(const dynamic_library&) = delete;
dynamic_library& operator=(dynamic_library&&) noexcept = default;
dynamic_library(const char* _env, const char* _fname,
int _flags = (RTLD_NOW | RTLD_GLOBAL), bool _store = false)
: envname{ _env }
, filename{ tim::get_env<std::string>(_env, _fname, _store) }
, flags{ _flags }
{
handle = dlopen(filename.c_str(), flags);
if(!handle) fprintf(stderr, "%s\n", dlerror());
dlerror(); // Clear any existing error
}
~dynamic_library()
{
if(handle) dlclose(handle);
}
std::string envname = {};
std::string filename = {};
int flags = 0;
void* handle = nullptr;
};
namespace tim
{
namespace component
{
void
roctracer::preinit()
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
roctracer_data::label() = "roctracer";
roctracer_data::description() = "ROCm tracer (activity API)";
}
bool
roctracer::is_setup()
{
return roctracer_is_setup();
}
void
roctracer::add_setup(const std::string& _lbl, std::function<void()>&& _func)
{
roctracer_setup_routines().emplace_back(_lbl, std::move(_func));
}
void
roctracer::add_tear_down(const std::string& _lbl, std::function<void()>&& _func)
{
roctracer_tear_down_routines().emplace_back(_lbl, std::move(_func));
}
void
roctracer::remove_setup(const std::string& _lbl)
{
auto& _data = roctracer_setup_routines();
for(auto itr = _data.begin(); itr != _data.end(); ++itr)
{
if(itr->first == _lbl)
{
_data.erase(itr);
break;
}
}
}
void
roctracer::remove_tear_down(const std::string& _lbl)
{
auto& _data = roctracer_setup_routines();
for(auto itr = _data.begin(); itr != _data.end(); ++itr)
{
if(itr->first == _lbl)
{
_data.erase(itr);
break;
}
}
}
void
roctracer::setup()
{
if(!get_use_timemory() && !get_use_perfetto()) return;
auto_lock_t _lk{ type_mutex<roctracer>() };
if(roctracer_is_setup()) return;
roctracer_is_setup() = true;
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
tim::set_env("HSA_TOOLS_LIB", "libhosttrace.so", 0);
auto _kfdwrapper = dynamic_library{ "HOSTTRACE_ROCTRACER_LIBKFDWRAPPER",
HOSTTRACE_ROCTRACER_LIBKFDWRAPPER };
ROCTRACER_CALL(roctracer_set_properties(ACTIVITY_DOMAIN_HIP_API, nullptr));
if(roctracer_default_pool() == nullptr)
{
// Allocating tracing pool
roctracer_properties_t properties{};
properties.buffer_size = 0x1000;
properties.buffer_callback_fun = hip_activity_callback;
ROCTRACER_CALL(roctracer_open_pool(&properties));
}
// Enable API callbacks, all domains
ROCTRACER_CALL(roctracer_enable_callback(hip_api_callback, nullptr));
// Enable activity tracing, all domains
ROCTRACER_CALL(roctracer_enable_activity());
// callback for HSA
for(auto& itr : roctracer_setup_routines())
itr.second();
}
void
roctracer::tear_down()
{
auto_lock_t _lk{ type_mutex<roctracer>() };
if(!roctracer_is_setup()) return;
roctracer_is_setup() = false;
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
// flush all the activity
if(roctracer_default_pool() != nullptr)
{
ROCTRACER_CALL(roctracer_flush_activity());
}
// flush all buffers
roctracer_flush_buf();
// callback for hsa
for(auto& itr : roctracer_tear_down_routines())
itr.second();
// Disable tracing and closing the pool
ROCTRACER_CALL(roctracer_disable_callback());
ROCTRACER_CALL(roctracer_disable_activity());
ROCTRACER_CALL(roctracer_close_pool());
}
void
roctracer::start()
{
if(tracker_type::start() == 0) setup();
}
void
roctracer::stop()
{
if(tracker_type::stop() == 0) tear_down();
}
} // namespace component
} // namespace tim
TIMEMORY_INSTANTIATE_EXTERN_COMPONENT(roctracer, false, void)
TIMEMORY_INSTANTIATE_EXTERN_COMPONENT(roctracer_data, true, double)
// HSA-runtime tool on-load method
extern "C"
{
bool OnLoad(HsaApiTable* table, uint64_t runtime_version, uint64_t failed_tool_count,
const char* const* failed_tool_names) TIMEMORY_VISIBILITY("default");
void OnUnload() TIMEMORY_VISIBILITY("default");
bool OnLoad(HsaApiTable* table, uint64_t runtime_version, uint64_t failed_tool_count,
const char* const* failed_tool_names)
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
tim::consume_parameters(table, runtime_version, failed_tool_count,
failed_tool_names);
// ONLOAD_TRACE_BEG();
// on_exit(exit_handler, nullptr);
auto _setup = [=]() {
get_hsa_timer() =
std::make_unique<hsa_timer_t>(table->core_->hsa_system_get_info_fn);
// const char* output_prefix = getenv("ROCP_OUTPUT_DIR");
const char* output_prefix = nullptr;
// App begin timestamp begin_ts_file.txt
// begin_ts_file_handle = open_output_file(output_prefix,
// "begin_ts_file.txt"); const timestamp_t app_start_time =
// timer->timestamp_fn_ns(); fprintf(begin_ts_file_handle, "%lu\n",
// app_start_time);
bool trace_hsa_api = tim::get_env("HOSTTRACE_ROCTRACER_HSA_API", true);
std::vector<std::string> hsa_api_vec = tim::delimit(
tim::get_env<std::string>("HOSTTRACE_ROCTRACER_HSA_API_TYPES", ""));
// Enable HSA API callbacks/activity
if(trace_hsa_api)
{
// hsa_api_file_handle = open_output_file(output_prefix,
// "hsa_api_trace.txt");
// initialize HSA tracing
roctracer_set_properties(ACTIVITY_DOMAIN_HSA_API, (void*) table);
HOSTTRACE_DEBUG(" HSA-trace(");
if(!hsa_api_vec.empty())
{
for(unsigned i = 0; i < hsa_api_vec.size(); ++i)
{
uint32_t cid = HSA_API_ID_NUMBER;
const char* api = hsa_api_vec[i].c_str();
ROCTRACER_CALL(roctracer_op_code(ACTIVITY_DOMAIN_HSA_API, api,
&cid, nullptr));
ROCTRACER_CALL(roctracer_enable_op_callback(
ACTIVITY_DOMAIN_HSA_API, cid, hsa_api_callback, nullptr));
HOSTTRACE_DEBUG(" %s", api);
}
}
else
{
ROCTRACER_CALL(roctracer_enable_domain_callback(
ACTIVITY_DOMAIN_HSA_API, hsa_api_callback, nullptr));
}
HOSTTRACE_DEBUG("\n");
}
bool trace_hsa_activity =
tim::get_env("HOSTTRACE_ROCTRACER_HSA_ACTIVITY", true);
// Enable HSA GPU activity
if(trace_hsa_activity)
{
// initialize HSA tracing
roctracer::hsa_ops_properties_t ops_properties{
table,
reinterpret_cast<activity_async_callback_t>(hsa_activity_callback),
nullptr, output_prefix
};
roctracer_set_properties(ACTIVITY_DOMAIN_HSA_OPS, &ops_properties);
HOSTTRACE_DEBUG(" HSA-activity-trace()\n");
ROCTRACER_CALL(roctracer_enable_op_activity(ACTIVITY_DOMAIN_HSA_OPS,
HSA_OP_ID_COPY));
}
};
auto _tear_down = []() {
ROCTRACER_CALL(roctracer_disable_domain_callback(ACTIVITY_DOMAIN_HSA_API));
ROCTRACER_CALL(
roctracer_disable_op_activity(ACTIVITY_DOMAIN_HSA_OPS, HSA_OP_ID_COPY));
};
if(comp::roctracer::is_setup()) _setup();
comp::roctracer::add_setup("hsa", std::move(_setup));
comp::roctracer::add_tear_down("hsa", std::move(_tear_down));
return true;
}
// HSA-runtime on-unload method
void OnUnload()
{
HOSTTRACE_DEBUG("[%s]\n", __FUNCTION__);
// ONLOAD_TRACE("");
}
}
@@ -3,6 +3,10 @@ if(NOT HOSTTRACE_DYNINST_API_RT_DIR AND HOSTTRACE_DYNINST_API_RT)
DIRECTORY)
endif()
if(NOT DEFINED NUM_PROCS)
set(NUM_PROCS 2)
endif()
if(HOSTTRACE_BUILD_DYNINST)
set(HOSTTRACE_DYNINST_API_RT_DIR
"${PROJECT_BINARY_DIR}/external/dyninst/dyninstAPI_RT:${PROJECT_BINARY_DIR}/external/dyninst/dyninstAPI"
@@ -16,8 +20,8 @@ set(_test_environment
)
if(TARGET transpose)
if(TRANSPOSE_USE_MPI)
set(COMMAND_PREFIX ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2)
if(TRANSPOSE_USE_MPI AND NUM_PROCS GREATER 0)
set(COMMAND_PREFIX ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} ${NUM_PROCS})
endif()
add_test(