- complete with ctest support
Этот коммит содержится в:
Jonathan R. Madsen
2021-08-06 13:08:57 -05:00
родитель 1df44258e6
Коммит 9ef3800986
69 изменённых файлов: 25144 добавлений и 0 удалений
+65
Просмотреть файл
@@ -0,0 +1,65 @@
# requires clang-tidy version 6.0+
---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: TopLevel
AlwaysBreakAfterReturnType: TopLevel
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BasedOnStyle: Mozilla
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: false
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: true
ColumnLimit: 90
CompactNamespaces: true
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 0
ContinuationIndentWidth: 4
FixNamespaceComments: true
IndentCaseLabels: true
IndentPPDirectives: AfterHash
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
PointerAlignment: Left
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Never
...
+48
Просмотреть файл
@@ -0,0 +1,48 @@
---
Checks: "-*,\
misc-*,\
-misc-incorrect-roundings,\
-misc-macro-parentheses,\
-misc-misplaced-widening-cast,\
-misc-static-assert,\
-misc-no-recursion,\
-misc-non-private-member-variables-in-classes,\
modernize-*,\
-modernize-deprecated-headers,\
-modernize-raw-string-literal,\
-modernize-return-braced-init-list,\
-modernize-use-transparent-functors,\
-modernize-use-trailing-return-type,\
-modernize-avoid-c-arrays,\
-modernize-redundant-void-arg,\
-modernize-use-using,\
-modernize-use-auto,\
-modernize-concat-nested-namespaces,\
performance-*,\
readability-*,\
-readability-function-size,\
-readability-identifier-naming,\
-readability-implicit-bool-cast,\
-readability-inconsistent-declaration-parameter-name,\
-readability-named-parameter,\
-readability-magic-numbers,\
-readability-redundant-declaration,\
-readability-redundant-member-init,\
-readability-simplify-boolean-expr,\
-readability-uppercase-literal-suffix,\
-readability-braces-around-statements,\
-readability-avoid-const-params-in-decls,\
-readability-else-after-return,\
-readability-isolate-declaration,\
-readability-redundant-string-cstr,\
-readability-static-accessed-through-instance,\
-readability-const-return-type,\
-readability-redundant-access-specifiers,\
-readability-function-cognitive-complexity,\
"
CheckOptions:
- key: readability-braces-around-statements.ShortStatementLines
value: '2'
- key: readability-implicit-bool-conversion.AllowPointerConditions
value: '1'
...
+1
Просмотреть файл
@@ -30,3 +30,4 @@
*.exe
*.out
*.app
/build*
+137
Просмотреть файл
@@ -0,0 +1,137 @@
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND
CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(MSG "")
message(STATUS "Warning! Building from the source directory is not recommended")
message(STATUS "If unintented, please remove 'CMakeCache.txt' and 'CMakeFiles'")
message(STATUS "and build from a separate directory")
message(AUTHOR_WARNING "In-source build")
endif()
project(
hosttrace
LANGUAGES CXX)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Build type" FORCE)
endif()
include(GNUInstallDirs) # install directories
include(MacroUtilities) # various functions and macros
include(Compilers) # compiler identification
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(HOSTTRACE_USE_CLANG_TIDY "Enable clang-tidy" OFF)
include(Packages) # finds third-party libraries
hosttrace_activate_clang_tidy()
#------------------------------------------------------------------------------#
#
# hosttrace-library target
#
#------------------------------------------------------------------------------#
add_library(hosttrace-library SHARED
${CMAKE_CURRENT_LIST_DIR}/src/library.cpp
${perfetto_DIR}/sdk/perfetto.cc)
target_include_directories(hosttrace-library PRIVATE
${CMAKE_CURRENT_LIST_DIR}/include)
target_include_directories(hosttrace-library SYSTEM PRIVATE
${perfetto_DIR}/sdk)
target_link_libraries(hosttrace-library PRIVATE
hosttrace::hosttrace-threading
$<IF:$<BOOL:${hosttrace_USE_SANITIZER}>,hosttrace::hosttrace-sanitizer,>)
set_target_properties(hosttrace-library PROPERTIES
OUTPUT_NAME hosttrace)
install(
TARGETS hosttrace-library
DESTINATION ${CMAKE_INSTALL_LIBDIR}
OPTIONAL)
#------------------------------------------------------------------------------#
#
# hosttrace-exe target
#
#------------------------------------------------------------------------------#
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)
target_link_libraries(hosttrace-exe PRIVATE
hosttrace::hosttrace-dyninst
hosttrace::hosttrace-compile-options)
set_target_properties(hosttrace-exe PROPERTIES
OUTPUT_NAME hosttrace
INSTALL_RPATH_USE_LINK_PATH ON)
install(
TARGETS hosttrace-exe
DESTINATION ${CMAKE_INSTALL_BINDIR}
OPTIONAL)
#------------------------------------------------------------------------------#
#
# clang-format target
#
#------------------------------------------------------------------------------#
find_program(CLANG_FORMAT_EXE
NAMES
clang-format-12
clang-format-11
clang-format-10
clang-format-9
clang-format)
if(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
${CLANG_FORMAT_EXE} -i ${sources} ${headers} ${examples}
COMMENT "Running ${CLANG_FORMAT_EXE}...")
else()
message(AUTHOR_WARNING "clang-format could not be found. format build target not available.")
endif()
#------------------------------------------------------------------------------#
#
# examples
#
#------------------------------------------------------------------------------#
add_subdirectory(examples)
#------------------------------------------------------------------------------#
#
# tests
#
#------------------------------------------------------------------------------#
include(CTest)
enable_testing()
add_subdirectory(tests)
+288
Просмотреть файл
@@ -0,0 +1,288 @@
# include guard
include_guard(DIRECTORY)
##########################################################################################
#
# Handles the build settings
#
##########################################################################################
include(GNUInstallDirs)
include(Compilers)
include(FindPackageHandleStandardArgs)
include(MacroUtilities)
option(hosttrace_BUILD_DEVELOPER "Extra build flags for development like -Werror" OFF)
option(hosttrace_BUILD_EXTRA_OPTIMIZATIONS "Extra optimization flags" OFF)
option(hosttrace_BUILD_LTO "Build with link-time optimization" OFF)
option(hosttrace_USE_COMPILE_TIMING "" OFF)
option(hosttrace_USE_COVERAGE "" OFF)
option(hosttrace_USE_SANITIZER "" OFF)
target_compile_definitions(hosttrace-compile-options INTERFACE $<$<CONFIG:DEBUG>:DEBUG>)
set(hosttrace_SANITIZER_TYPE "leak" CACHE STRING "Sanitizer type")
#----------------------------------------------------------------------------------------#
# dynamic linking and runtime libraries
#
if(CMAKE_DL_LIBS AND NOT "${CMAKE_DL_LIBS}" STREQUAL "dl")
# if cmake provides dl library, use that
set(dl_LIBRARY ${CMAKE_DL_LIBS} CACHE FILEPATH "dynamic linking system library")
endif()
foreach(_TYPE dl rt dw)
if(NOT ${_TYPE}_LIBRARY)
find_library(${_TYPE}_LIBRARY NAMES ${_TYPE})
endif()
endforeach()
find_package_handle_standard_args(dl-library REQUIRED_VARS dl_LIBRARY)
find_package_handle_standard_args(rt-library REQUIRED_VARS rt_LIBRARY)
# find_package_handle_standard_args(dw-library REQUIRED_VARS dw_LIBRARY)
if(dl_LIBRARY)
target_link_libraries(hosttrace-compile-options INTERFACE ${dl_LIBRARY})
endif()
#----------------------------------------------------------------------------------------#
# set the compiler flags
#
add_flag_if_avail(
"-W"
"-Wall"
"-Wno-unknown-pragmas"
"-Wno-unused-function"
"-Wno-ignored-attributes"
"-Wno-attributes"
"-Wno-missing-field-initializers")
if(WIN32)
# suggested by MSVC for spectre mitigation in rapidjson implementation
add_cxx_flag_if_avail("/Qspectre")
endif()
if(CMAKE_CXX_COMPILER_IS_CLANG)
add_cxx_flag_if_avail(
"-Wno-mismatched-tags")
endif()
#----------------------------------------------------------------------------------------#
# extra flags for debug information in debug or optimized binaries
#
add_interface_library(hosttrace-compile-debuginfo
"Attempts to set best flags for more expressive profiling information in debug or optimized binaries")
add_target_flag_if_avail(hosttrace-compile-debuginfo
"-g"
"-fno-omit-frame-pointer"
"-fno-optimize-sibling-calls")
if(CMAKE_CUDA_COMPILER_IS_NVIDIA)
add_target_cuda_flag(hosttrace-compile-debuginfo "-lineinfo")
endif()
target_compile_options(hosttrace-compile-debuginfo INTERFACE
$<$<COMPILE_LANGUAGE:C>:$<$<C_COMPILER_ID:GNU>:-rdynamic>>
$<$<COMPILE_LANGUAGE:CXX>:$<$<CXX_COMPILER_ID:GNU>:-rdynamic>>)
if(NOT APPLE)
target_link_options(hosttrace-compile-debuginfo INTERFACE
$<$<CXX_COMPILER_ID:GNU>:-rdynamic>)
endif()
if(CMAKE_CUDA_COMPILER_IS_NVIDIA)
target_compile_options(hosttrace-compile-debuginfo INTERFACE
$<$<COMPILE_LANGUAGE:CUDA>:$<$<CXX_COMPILER_ID:GNU>:-Xcompiler=-rdynamic>>)
endif()
if(dl_LIBRARY)
target_link_libraries(hosttrace-compile-debuginfo INTERFACE ${dl_LIBRARY})
endif()
if(rt_LIBRARY)
target_link_libraries(hosttrace-compile-debuginfo INTERFACE ${rt_LIBRARY})
endif()
#----------------------------------------------------------------------------------------#
# non-debug optimizations
#
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"
"-ftree-loop-optimize"
"-ftree-loop-vectorize")
endif()
if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" AND hosttrace_BUILD_EXTRA_OPTIMIZATIONS)
target_link_libraries(hosttrace-compile-options INTERFACE
$<BUILD_INTERFACE:hosttrace-compile-extra>)
add_flag_if_avail(
"-fno-signaling-nans"
"-fno-trapping-math"
"-fno-signed-zeros"
"-ffinite-math-only"
"-fno-math-errno"
"-fpredictive-commoning"
"-fvariable-expansion-in-unroller")
# add_flag_if_avail("-freciprocal-math" "-fno-signed-zeros" "-mfast-fp")
endif()
#----------------------------------------------------------------------------------------#
# debug-safe optimizations
#
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")
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)
else()
target_link_options(hosttrace-lto INTERFACE -flto)
endif()
else()
target_link_options(hosttrace-lto INTERFACE -flto=thin)
endif()
if(hosttrace_BUILD_LTO)
target_link_libraries(hosttrace-compile-options INTERFACE hosttrace::hosttrace-lto)
endif()
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")
if(CMAKE_CXX_COMPILER_IS_CLANG)
add_target_flag_if_avail(hosttrace-compile-timing "-ftime-trace")
if(NOT cxx_hosttrace_compile_timing_ftime_trace)
add_target_flag_if_avail(hosttrace-compile-timing "-ftime-report")
endif()
else()
add_target_flag_if_avail(hosttrace-compile-timing "-ftime-report")
endif()
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")
if(hosttrace_BUILD_DEVELOPER)
add_target_flag_if_avail(hosttrace-develop-options
# "-Wabi"
"-Wdouble-promotion"
"-Wshadow"
"-Wextra"
"-Wpedantic"
"-Werror"
"/showIncludes")
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")
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
#
if(dl_LIBRARY)
# This instructs the linker to add all symbols, not only used ones, to the dynamic
# symbol table. This option is needed for some uses of dlopen or to allow obtaining
# backtraces from within a program.
add_flag_if_avail("-rdynamic")
endif()
#----------------------------------------------------------------------------------------#
# sanitizer
#
set(hosttrace_SANITIZER_TYPES address memory thread leak undefined unreachable null bounds 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-sanitizer
"Adds compiler flags to enable ${hosttrace_SANITIZER_TYPE} sanitizer (-fsanitizer=${hosttrace_SANITIZER_TYPE})")
set(COMMON_SANITIZER_FLAGS "-fno-optimize-sibling-calls" "-fno-omit-frame-pointer" "-fno-inline-functions")
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})")
add_target_flag(hosttrace-${_TYPE}-sanitizer ${_FLAG})
target_link_libraries(hosttrace-${_TYPE}-sanitizer INTERFACE
hosttrace-sanitizer-compile-options)
set_property(TARGET hosttrace-${_TYPE}-sanitizer PROPERTY
INTERFACE_LINK_OPTIONS ${_FLAG} ${COMMON_SANITIZER_FLAGS})
endforeach()
unset(_FLAG)
unset(COMMON_SANITIZER_FLAGS)
if(hosttrace_USE_SANITIZER)
foreach(_TYPE ${hosttrace_SANITIZER_TYPE})
if(TARGET hosttrace-${_TYPE}-sanitizer)
target_link_libraries(hosttrace-sanitizer INTERFACE hosttrace-${_TYPE}-sanitizer)
else()
message(FATAL_ERROR "Error! Target 'hosttrace-${_TYPE}-sanitizer' does not exist!")
endif()
endforeach()
else()
set(hosttrace_USE_SANITIZER OFF)
inform_empty_interface(hosttrace-sanitizer "${hosttrace_SANITIZER_TYPE} sanitizer")
endif()
if (MSVC)
# VTune is much more helpful when debug information is included in the
# generated release code.
add_flag_if_avail("/Zi")
add_flag_if_avail("/DEBUG")
endif()
#----------------------------------------------------------------------------------------#
# user customization
#
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
if(NOT APPLE OR "$ENV{CONDA_PYTHON_EXE}" STREQUAL "")
add_user_flags(hosttrace-compile-options "CXX")
endif()
+594
Просмотреть файл
@@ -0,0 +1,594 @@
# include guard
include_guard(DIRECTORY)
##########################################################################################
#
# Compilers
#
##########################################################################################
#
# sets (cached):
#
# CMAKE_C_COMPILER_IS_<TYPE>
# CMAKE_CXX_COMPILER_IS_<TYPE>
#
# where TYPE is:
# - GNU
# - CLANG
# - INTEL
# - INTEL_ICC
# - INTEL_ICPC
# - PGI
# - XLC
# - HP_ACC
# - MIPS
# - MSVC
#
include(CheckCCompilerFlag)
include(CheckCSourceCompiles)
include(CheckCSourceRuns)
include(CheckCXXCompilerFlag)
include(CheckCXXSourceCompiles)
include(CheckCXXSourceRuns)
include(CMakeParseArguments)
include(MacroUtilities)
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")
#----------------------------------------------------------------------------------------#
# macro converting string to list
#----------------------------------------------------------------------------------------#
macro(to_list _VAR _STR)
STRING(REPLACE " " " " ${_VAR} "${_STR}")
STRING(REPLACE " " ";" ${_VAR} "${_STR}")
endmacro(to_list _VAR _STR)
#----------------------------------------------------------------------------------------#
# macro converting string to list
#----------------------------------------------------------------------------------------#
macro(to_string _VAR _STR)
STRING(REPLACE ";" " " ${_VAR} "${_STR}")
endmacro(to_string _VAR _STR)
#----------------------------------------------------------------------------------------#
# Macro to add to string
#----------------------------------------------------------------------------------------#
macro(add _VAR _FLAG)
if(NOT "${_FLAG}" STREQUAL "")
if("${${_VAR}}" STREQUAL "")
set(${_VAR} "${_FLAG}")
else()
set(${_VAR} "${${_VAR}} ${_FLAG}")
endif()
endif()
endmacro()
#----------------------------------------------------------------------------------------#
# macro to remove duplicates from string
#----------------------------------------------------------------------------------------#
macro(set_no_duplicates _VAR)
if(NOT "${ARGN}" STREQUAL "")
set(${_VAR} "${ARGN}")
endif()
# remove the duplicates
if(NOT "${${_VAR}}" STREQUAL "")
# create list of flags
to_list(_VAR_LIST "${${_VAR}}")
list(REMOVE_DUPLICATES _VAR_LIST)
to_string(${_VAR} "${_VAR_LIST}")
endif(NOT "${${_VAR}}" STREQUAL "")
endmacro(set_no_duplicates _VAR)
#----------------------------------------------------------------------------------------#
# call before running check_{c,cxx}_compiler_flag
#----------------------------------------------------------------------------------------#
macro(timemory_begin_flag_check)
if(TIMEMORY_QUIET_CONFIG)
if(NOT DEFINED CMAKE_REQUIRED_QUIET)
set(CMAKE_REQUIRED_QUIET OFF)
endif()
timemory_save_variables(FLAG_CHECK
VARIABLES CMAKE_REQUIRED_QUIET)
set(CMAKE_REQUIRED_QUIET ON)
endif()
endmacro()
#----------------------------------------------------------------------------------------#
# call after running check_{c,cxx}_compiler_flag
#----------------------------------------------------------------------------------------#
macro(timemory_end_flag_check)
if(TIMEMORY_QUIET_CONFIG)
timemory_restore_variables(FLAG_CHECK
VARIABLES CMAKE_REQUIRED_QUIET)
endif()
endmacro()
##########################################################################################
#
# C compiler flags
#
##########################################################################################
#----------------------------------------------------------------------------------------#
# add C flag to target
#----------------------------------------------------------------------------------------#
macro(ADD_TARGET_C_FLAG _TARG)
string(REPLACE "-" "_" _MAKE_TARG "${_TARG}")
list(APPEND TIMEMORY_MAKE_TARGETS ${_MAKE_TARG})
target_compile_options(${_TARG} INTERFACE $<$<COMPILE_LANGUAGE:C>:${ARGN}>)
list(APPEND ${_MAKE_TARG}_C_FLAGS ${ARGN})
endmacro()
#----------------------------------------------------------------------------------------#
# add C flag w/o check
#----------------------------------------------------------------------------------------#
macro(ADD_C_FLAG FLAG)
set(_TARG )
set(_LTARG )
if(NOT "${ARGN}" STREQUAL "")
set(_TARG ${ARGN})
string(TOLOWER "_${ARGN}" _LTARG)
endif()
if(NOT "${FLAG}" STREQUAL "")
if("${_LTARG}" STREQUAL "")
list(APPEND ${PROJECT_NAME}_C_FLAGS "${FLAG}")
list(APPEND ${PROJECT_NAME}_C_COMPILE_OPTIONS "${FLAG}")
add_target_c_flag(${LIBNAME}-compile-options ${FLAG})
else()
add_target_c_flag(${_TARG} ${FLAG})
endif()
endif()
unset(_TARG)
unset(_LTARG)
endmacro()
#----------------------------------------------------------------------------------------#
# check C flag
#----------------------------------------------------------------------------------------#
macro(ADD_C_FLAG_IF_AVAIL FLAG)
set(_ENABLE ON)
if(DEFINED TIMEMORY_BUILD_C AND NOT TIMEMORY_BUILD_C)
set(_ENABLE OFF)
endif()
set(_TARG )
set(_LTARG )
if(NOT "${ARGN}" STREQUAL "")
set(_TARG ${ARGN})
string(TOLOWER "_${ARGN}" _LTARG)
endif()
if(NOT "${FLAG}" STREQUAL "")
string(REGEX REPLACE "^/" "c${_LTARG}_" FLAG_NAME "${FLAG}")
string(REGEX REPLACE "^-" "c${_LTARG}_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE "-" "_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE " " "_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE "=" "_" FLAG_NAME "${FLAG_NAME}")
if(NOT TIMEMORY_BUILD_C)
set(${FLAG_NAME} ON)
else()
timemory_begin_flag_check()
check_c_compiler_flag("-Werror" c_werror)
if(c_werror)
check_c_compiler_flag("${FLAG} -Werror" ${FLAG_NAME})
else()
check_c_compiler_flag("${FLAG}" ${FLAG_NAME})
endif()
timemory_end_flag_check()
if(${FLAG_NAME})
if("${_LTARG}" STREQUAL "")
list(APPEND ${PROJECT_NAME}_C_FLAGS "${FLAG}")
list(APPEND ${PROJECT_NAME}_C_COMPILE_OPTIONS "${FLAG}")
add_target_c_flag(${LIBNAME}-compile-options ${FLAG})
else()
add_target_c_flag(${_TARG} ${FLAG})
endif()
endif()
endif()
endif()
unset(_TARG)
unset(_LTARG)
endmacro()
#----------------------------------------------------------------------------------------#
# add C flag to target
#----------------------------------------------------------------------------------------#
macro(ADD_TARGET_C_FLAG_IF_AVAIL _TARG)
foreach(_FLAG ${ARGN})
add_c_flag_if_avail(${_FLAG} ${_TARG})
endforeach()
endmacro()
##########################################################################################
#
# CXX compiler flags
#
##########################################################################################
#----------------------------------------------------------------------------------------#
# add CXX flag to target
#----------------------------------------------------------------------------------------#
macro(ADD_TARGET_CXX_FLAG _TARG)
string(REPLACE "-" "_" _MAKE_TARG "${_TARG}")
list(APPEND TIMEMORY_MAKE_TARGETS ${_MAKE_TARG})
target_compile_options(${_TARG} INTERFACE $<$<COMPILE_LANGUAGE:CXX>:${ARGN}>)
list(APPEND ${_MAKE_TARG}_CXX_FLAGS ${ARGN})
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
if(CMAKE_CUDA_COMPILER_IS_NVIDIA)
target_compile_options(${_TARG} INTERFACE $<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=${ARGN}>)
list(APPEND ${_MAKE_TARG}_CUDA_FLAGS -Xcompiler=${ARGN})
elseif(CMAKE_CUDA_COMPILER_IS_CLANG)
target_compile_options(${_TARG} INTERFACE $<$<COMPILE_LANGUAGE:CUDA>:${ARGN}>)
list(APPEND ${_MAKE_TARG}_CUDA_FLAGS ${ARGN})
endif()
endmacro()
#----------------------------------------------------------------------------------------#
# add CXX flag w/o check
#----------------------------------------------------------------------------------------#
macro(ADD_CXX_FLAG FLAG)
set(_TARG )
set(_LTARG )
if(NOT "${ARGN}" STREQUAL "")
set(_TARG ${ARGN})
string(TOLOWER "_${ARGN}" _LTARG)
endif()
if(NOT "${FLAG}" STREQUAL "")
if("${_LTARG}" STREQUAL "")
list(APPEND ${PROJECT_NAME}_CXX_FLAGS "${FLAG}")
list(APPEND ${PROJECT_NAME}_CXX_COMPILE_OPTIONS "${FLAG}")
add_target_cxx_flag(${LIBNAME}-compile-options ${FLAG})
else()
add_target_cxx_flag(${_TARG} ${FLAG})
endif()
endif()
unset(_TARG)
unset(_LTARG)
endmacro()
#----------------------------------------------------------------------------------------#
# check CXX flag
#----------------------------------------------------------------------------------------#
macro(ADD_CXX_FLAG_IF_AVAIL FLAG)
set(_TARG )
set(_LTARG )
if(NOT "${ARGN}" STREQUAL "")
set(_TARG ${ARGN})
string(TOLOWER "_${ARGN}" _LTARG)
endif()
if(NOT "${FLAG}" STREQUAL "")
string(REGEX REPLACE "^/" "cxx${_LTARG}_" FLAG_NAME "${FLAG}")
string(REGEX REPLACE "^-" "cxx${_LTARG}_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE "-" "_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE " " "_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE "=" "_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE "/" "_" FLAG_NAME "${FLAG_NAME}")
timemory_begin_flag_check()
check_cxx_compiler_flag("-Werror" cxx_werror)
if(cxx_werror)
check_cxx_compiler_flag("${FLAG} -Werror" ${FLAG_NAME})
else()
check_cxx_compiler_flag("${FLAG}" ${FLAG_NAME})
endif()
timemory_end_flag_check()
if(${FLAG_NAME})
if("${_LTARG}" STREQUAL "")
list(APPEND ${PROJECT_NAME}_CXX_FLAGS "${FLAG}")
list(APPEND ${PROJECT_NAME}_CXX_COMPILE_OPTIONS "${FLAG}")
add_target_cxx_flag(${LIBNAME}-compile-options ${FLAG})
else()
add_target_cxx_flag(${_TARG} ${FLAG})
endif()
endif()
endif()
unset(_TARG)
unset(_LTARG)
endmacro()
#----------------------------------------------------------------------------------------#
# add CXX flag to target
#----------------------------------------------------------------------------------------#
macro(ADD_TARGET_CXX_FLAG_IF_AVAIL _TARG)
foreach(_FLAG ${ARGN})
add_cxx_flag_if_avail(${_FLAG} ${_TARG})
endforeach()
endmacro()
##########################################################################################
#
# Common
#
##########################################################################################
#----------------------------------------------------------------------------------------#
# check C and CXX flag to compile-options w/o checking
#----------------------------------------------------------------------------------------#
macro(ADD_FLAG)
foreach(_ARG ${ARGN})
ADD_C_FLAG("${_ARG}")
ADD_CXX_FLAG("${_ARG}")
endforeach()
endmacro()
#----------------------------------------------------------------------------------------#
# add C and CXX flag w/o checking
#----------------------------------------------------------------------------------------#
macro(ADD_TARGET_FLAG _TARG)
foreach(_ARG ${ARGN})
ADD_TARGET_C_FLAG(${_TARG} ${_ARG})
ADD_TARGET_CXX_FLAG(${_TARG} ${_ARG})
endforeach()
endmacro()
#----------------------------------------------------------------------------------------#
# check C and CXX flag
#----------------------------------------------------------------------------------------#
macro(ADD_FLAG_IF_AVAIL)
foreach(_ARG ${ARGN})
ADD_C_FLAG_IF_AVAIL("${_ARG}")
ADD_CXX_FLAG_IF_AVAIL("${_ARG}")
endforeach()
endmacro()
#----------------------------------------------------------------------------------------#
# check C and CXX flag
#----------------------------------------------------------------------------------------#
macro(ADD_TARGET_FLAG_IF_AVAIL _TARG)
foreach(_ARG ${ARGN})
ADD_TARGET_C_FLAG_IF_AVAIL(${_TARG} ${_ARG})
ADD_TARGET_CXX_FLAG_IF_AVAIL(${_TARG} ${_ARG})
endforeach()
endmacro()
#----------------------------------------------------------------------------------------#
# check flag
#----------------------------------------------------------------------------------------#
function(TIMEMORY_TARGET_FLAG _TARG_TARGET)
cmake_parse_arguments(_TARG "IF_AVAIL" "MODE" "FLAGS;LANGUAGES" ${ARGN})
if(NOT _TARG_MODE)
set(_TARG_MODE INTERFACE)
endif()
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
if(NOT _TARG_LANGUAGES)
get_property(_TARG_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
endif()
string(TOLOWER "_${_TARG_TARGET}" _LTARG)
foreach(_FLAG ${_TARG_FLAGS})
foreach(_LANG ${_TARG_LANGUAGES})
if(NOT _TARG_IF_AVAIL)
target_compile_options(${_TARG_TARGET} ${_TARG_MODE} $<$<COMPILE_LANGUAGE:${_LANG}>:${_FLAG}>)
continue()
endif()
if("${_LANG}" STREQUAL "C")
string(REGEX REPLACE "^/" "c${_LTARG}_" FLAG_NAME "${_FLAG}")
string(REGEX REPLACE "^-" "c${_LTARG}_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE "-" "_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE " " "_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE "=" "_" FLAG_NAME "${FLAG_NAME}")
timemory_begin_flag_check()
check_c_compiler_flag("-Werror" c_werror)
if(c_werror)
check_c_compiler_flag("${FLAG} -Werror" ${FLAG_NAME})
else()
check_c_compiler_flag("${FLAG}" ${FLAG_NAME})
endif()
timemory_end_flag_check()
if(${FLAG_NAME})
target_compile_options(${_TARG_TARGET} ${_TARG_MODE}
$<$<COMPILE_LANGUAGE:${_LANG}>:${_FLAG}>)
endif()
elseif("${_LANG}" STREQUAL "CXX")
string(REGEX REPLACE "^/" "cxx${_LTARG}_" FLAG_NAME "${_FLAG}")
string(REGEX REPLACE "^-" "cxx${_LTARG}_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE "-" "_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE " " "_" FLAG_NAME "${FLAG_NAME}")
string(REPLACE "=" "_" FLAG_NAME "${FLAG_NAME}")
timemory_begin_flag_check()
check_cxx_compiler_flag("-Werror" cxx_werror)
if(cxx_werror)
check_cxx_compiler_flag("${FLAG} -Werror" ${FLAG_NAME})
else()
check_cxx_compiler_flag("${FLAG}" ${FLAG_NAME})
endif()
timemory_end_flag_check()
if(${FLAG_NAME})
target_compile_options(${_TARG_TARGET} ${_TARG_MODE}
$<$<COMPILE_LANGUAGE:${_LANG}>:${_FLAG}>)
if(CMAKE_CUDA_COMPILER_IS_NVIDIA)
target_compile_options(${_TARG_TARGET} ${_TARG_MODE}
$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=${_FLAG}>)
elseif(CMAKE_CUDA_COMPILER_IS_CLANG)
target_compile_options(${_TARG_TARGET} ${_TARG_MODE}
$<$<COMPILE_LANGUAGE:CUDA>:${_FLAG}>)
endif()
endif()
endif()
endforeach()
endforeach()
endfunction()
#----------------------------------------------------------------------------------------#
# add CUDA flag to target
#----------------------------------------------------------------------------------------#
macro(ADD_TARGET_CUDA_FLAG _TARG)
string(REPLACE "-" "_" _MAKE_TARG "${_TARG}")
list(APPEND TIMEMORY_MAKE_TARGETS ${_MAKE_TARG})
target_compile_options(${_TARG} INTERFACE $<$<COMPILE_LANGUAGE:CUDA>:${ARGN}>)
list(APPEND ${_MAKE_TARG}_CUDA_FLAGS ${ARGN})
endmacro()
#----------------------------------------------------------------------------------------#
# add to any language
#----------------------------------------------------------------------------------------#
function(ADD_USER_FLAGS _TARGET _LANGUAGE)
set(_FLAGS ${${_LANGUAGE}FLAGS} $ENV{${_LANGUAGE}FLAGS}
${${_LANGUAGE}_FLAGS} $ENV{${_LANGUAGE}_FLAGS})
string(REPLACE " " ";" _FLAGS "${_FLAGS}")
set(${PROJECT_NAME}_${_LANGUAGE}_FLAGS
${${PROJECT_NAME}_${_LANGUAGE}_FLAGS} ${_FLAGS} PARENT_SCOPE)
set(${PROJECT_NAME}_${_LANGUAGE}_COMPILE_OPTIONS
${${PROJECT_NAME}_${_LANGUAGE}_COMPILE_OPTIONS} ${_FLAGS} PARENT_SCOPE)
target_compile_options(${_TARGET} INTERFACE
$<$<COMPILE_LANGUAGE:${_LANGUAGE}>:${_FLAGS}>)
endfunction()
#----------------------------------------------------------------------------------------#
# add compiler definition
#----------------------------------------------------------------------------------------#
function(TIMEMORY_TARGET_COMPILE_DEFINITIONS _TARG _VIS)
foreach(_DEF ${ARGN})
target_compile_definitions(${_TARG} ${_VIS}
$<$<COMPILE_LANGUAGE:CXX>:${_DEF}>)
if(CMAKE_CUDA_COMPILER_IS_NVIDIA)
target_compile_definitions(${_TARG} ${_VIS}
$<$<COMPILE_LANGUAGE:CUDA>:${_DEF}>)
elseif(CMAKE_CUDA_COMPILER_IS_CLANG)
target_compile_definitions(${_TARG} ${_VIS}
$<$<COMPILE_LANGUAGE:CUDA>:${_DEF}>)
endif()
endforeach()
endfunction()
#----------------------------------------------------------------------------------------#
# determine compiler types for each language
#----------------------------------------------------------------------------------------#
get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
foreach(LANG C CXX CUDA)
if(NOT DEFINED CMAKE_${LANG}_COMPILER)
set(CMAKE_${LANG}_COMPILER "")
endif()
if(NOT DEFINED CMAKE_${LANG}_COMPILER_ID)
set(CMAKE_${LANG}_COMPILER_ID "")
endif()
function(SET_COMPILER_VAR VAR _BOOL)
set(CMAKE_${LANG}_COMPILER_IS_${VAR} ${_BOOL} CACHE INTERNAL
"CMake ${LANG} compiler identification (${VAR})" FORCE)
mark_as_advanced(CMAKE_${LANG}_COMPILER_IS_${VAR})
endfunction()
if(("${LANG}" STREQUAL "C" AND CMAKE_COMPILER_IS_GNUCC)
OR
("${LANG}" STREQUAL "CXX" AND CMAKE_COMPILER_IS_GNUCXX))
# GNU compiler
SET_COMPILER_VAR( GNU 1)
elseif(CMAKE_${LANG}_COMPILER MATCHES "icc.*")
# Intel icc compiler
SET_COMPILER_VAR( INTEL 1)
SET_COMPILER_VAR( INTEL_ICC 1)
elseif(CMAKE_${LANG}_COMPILER MATCHES "icpc.*")
# Intel icpc compiler
SET_COMPILER_VAR( INTEL 1)
SET_COMPILER_VAR( INTEL_ICPC 1)
elseif(CMAKE_${LANG}_COMPILER_ID MATCHES "AppleClang")
# Clang/LLVM compiler
SET_COMPILER_VAR( CLANG 1)
SET_COMPILER_VAR( APPLE_CLANG 1)
elseif(CMAKE_${LANG}_COMPILER_ID MATCHES "Clang")
# Clang/LLVM compiler
SET_COMPILER_VAR( CLANG 1)
elseif(CMAKE_${LANG}_COMPILER_ID MATCHES "PGI")
# PGI compiler
SET_COMPILER_VAR( PGI 1)
elseif(CMAKE_${LANG}_COMPILER MATCHES "xlC" AND UNIX)
# IBM xlC compiler
SET_COMPILER_VAR( XLC 1)
elseif(CMAKE_${LANG}_COMPILER MATCHES "aCC" AND UNIX)
# HP aC++ compiler
SET_COMPILER_VAR( HP_ACC 1)
elseif(CMAKE_${LANG}_COMPILER MATCHES "CC" AND
CMAKE_SYSTEM_NAME MATCHES "IRIX" AND UNIX)
# IRIX MIPSpro CC Compiler
SET_COMPILER_VAR( MIPS 1)
elseif(CMAKE_${LANG}_COMPILER_ID MATCHES "Intel")
SET_COMPILER_VAR( INTEL 1)
set(CTYPE ICC)
if("${LANG}" STREQUAL "CXX")
set(CTYPE ICPC)
endif()
SET_COMPILER_VAR( INTEL_${CTYPE} 1)
elseif(CMAKE_${LANG}_COMPILER MATCHES "MSVC")
# Windows Visual Studio compiler
SET_COMPILER_VAR( MSVC 1)
elseif(CMAKE_${LANG}_COMPILER_ID MATCHES "NVIDIA")
# NVCC
SET_COMPILER_VAR( NVIDIA 1)
endif()
# set other to no
foreach(TYPE GNU INTEL INTEL_ICC INTEL_ICPC APPLE_CLANG CLANG PGI XLC HP_ACC MIPS MSVC NVIDIA)
if(NOT DEFINED CMAKE_${LANG}_COMPILER_IS_${TYPE})
SET_COMPILER_VAR(${TYPE} 0)
endif()
endforeach()
endforeach()
Разница между файлами не показана из-за своего большого размера Загрузить разницу
+159
Просмотреть файл
@@ -0,0 +1,159 @@
# include guard
include_guard(DIRECTORY)
##########################################################################################
#
# External Packages are found here
#
##########################################################################################
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-dyninst
"Provides flags and libraries for Dyninst (dynamic instrumentation")
# include threading because of rooflines
target_link_libraries(hosttrace-headers INTERFACE hosttrace-threading)
#----------------------------------------------------------------------------------------#
#
# Threading
#
#----------------------------------------------------------------------------------------#
if(NOT WIN32)
set(CMAKE_THREAD_PREFER_PTHREAD ON)
set(THREADS_PREFER_PTHREAD_FLAG OFF)
endif()
find_library(pthread_LIBRARY NAMES pthread pthreads)
find_package_handle_standard_args(pthread-library REQUIRED_VARS pthread_LIBRARY)
find_package(Threads ${hosttrace_FIND_QUIETLY} ${hosttrace_FIND_REQUIREMENT})
if(Threads_FOUND)
target_link_libraries(hosttrace-threading INTERFACE ${CMAKE_THREAD_LIBS_INIT})
endif()
if(pthread_LIBRARY AND NOT WIN32)
target_link_libraries(hosttrace-threading INTERFACE ${pthread_LIBRARY})
endif()
#----------------------------------------------------------------------------------------#
#
# Dyninst
#
#----------------------------------------------------------------------------------------#
find_package(Dyninst ${hosttrace_FIND_QUIETLY} REQUIRED)
set(_BOOST_COMPONENTS atomic system thread date_time)
set(hosttrace_BOOST_COMPONENTS "${_BOOST_COMPONENTS}" CACHE STRING
"Boost components used by Dyninst in hosttrace")
set(Boost_NO_BOOST_CMAKE ON)
find_package(Boost QUIET REQUIRED
COMPONENTS ${hosttrace_BOOST_COMPONENTS})
# some installs of dyninst don't set this properly
if(EXISTS "${DYNINST_INCLUDE_DIR}" AND NOT DYNINST_HEADER_DIR)
get_filename_component(DYNINST_HEADER_DIR "${DYNINST_INCLUDE_DIR}" REALPATH CACHE)
else()
find_path(DYNINST_HEADER_DIR
NAMES BPatch.h dyninstAPI_RT.h
HINTS ${Dyninst_ROOT_DIR} ${Dyninst_DIR} ${Dyninst_DIR}/../../..
PATHS ${Dyninst_ROOT_DIR} ${Dyninst_DIR} ${Dyninst_DIR}/../../..
PATH_SUFFIXES include)
endif()
# useful for defining the location of the runtime API
find_library(DYNINST_API_RT dyninstAPI_RT
HINTS ${Dyninst_ROOT_DIR} ${Dyninst_DIR}
PATHS ${Dyninst_ROOT_DIR} ${Dyninst_DIR}
PATH_SUFFIXES lib)
find_path(TBB_INCLUDE_DIR
NAMES tbb/tbb.h
PATH_SUFFIXES include)
if(TBB_INCLUDE_DIR)
set(TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR})
endif()
if(DYNINST_API_RT)
target_compile_definitions(hosttrace-dyninst INTERFACE
DYNINST_API_RT="${DYNINST_API_RT}")
endif()
if(Boost_DIR)
get_filename_component(Boost_RPATH_DIR "${Boost_DIR}" DIRECTORY)
get_filename_component(Boost_RPATH_DIR "${Boost_RPATH_DIR}" DIRECTORY)
if(EXISTS "${Boost_RPATH_DIR}" AND IS_DIRECTORY "${Boost_RPATH_DIR}")
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:${Boost_RPATH_DIR}")
endif()
endif()
add_rpath(${DYNINST_LIBRARIES} ${Boost_LIBRARIES})
target_link_libraries(hosttrace-dyninst INTERFACE
${DYNINST_LIBRARIES} ${Boost_LIBRARIES})
foreach(_TARG Dyninst::dyninst Boost::headers Boost::atomic
Boost::system Boost::thread Boost::date_time)
if(TARGET ${_TARG})
target_link_libraries(hosttrace-dyninst INTERFACE ${_TARG})
endif()
endforeach()
target_include_directories(hosttrace-dyninst SYSTEM INTERFACE
${TBB_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${DYNINST_HEADER_DIR})
target_compile_definitions(hosttrace-dyninst INTERFACE hosttrace_USE_DYNINST)
if(DYNINST_API_RT)
add_cmake_defines(DYNINST_API_RT VALUE QUOTE DEFAULT)
else()
add_cmake_defines(DYNINST_API_RT VALUE QUOTE)
endif()
#----------------------------------------------------------------------------------------#
#
# Perfetto
#
#----------------------------------------------------------------------------------------#
set(perfetto_DIR ${PROJECT_BINARY_DIR}/stuff/hosttrace-dyninst/perfetto)
if(NOT EXISTS "${perfetto_DIR}/.git")
find_package(Git REQUIRED)
execute_process(COMMAND
${GIT_EXECUTABLE} clone -b v17.0 https://android.googlesource.com/platform/external/perfetto/ ${perfetto_DIR})
endif()
#----------------------------------------------------------------------------------------#
#
# Clang Tidy
#
#----------------------------------------------------------------------------------------#
# 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()
+6
Просмотреть файл
@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
project(hosttrace-dyninst-examples
LANGUAGES CXX)
add_subdirectory(transpose)
+59
Просмотреть файл
@@ -0,0 +1,59 @@
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
# uses make to avoid CMAKE_CXX_COMPILER issues
project(transpose
LANGUAGES CXX)
find_program(MAKE_EXECUTABLE NAMES make gmake)
find_program(HIPCC_EXECUTABLE NAMES hipcc)
if(NOT MAKE_EXECUTABLE)
message(AUTHOR_WARNING "make/gmake could not be found. Cannot build transpose target")
return()
endif()
if(NOT HIPCC_EXECUTABLE)
message(AUTHOR_WARNING "hipcc could not be found. Cannot build transpose target")
return()
endif()
string(TOUPPER "${CMAKE_BUILD_TYPE}" BUILD_TYPE)
set(transpose_CXX_FLAGS "-W -Wall ${CMAKE_CXX_FLAGS_${BUILD_TYPE}} ${CMAKE_CXX_FLAGS}")
if(CMAKE_CXX_COMPILER_IS_CLANG AND TARGET hosttrace::hosttrace-compile-options)
set(transpose_CXX_FLAGS "${transpose_CXX_FLAGS} ${hosttrace_CXX_FLAGS}")
get_target_property(COMPILE_OPTS hosttrace::hosttrace-compile-options INTERFACE_COMPILE_OPTIONS)
set(transpose_CXX_FLAGS "${transpose_CXX_FLAGS} ${COMPILE_OPTS}")
endif()
# remove generator expressions
string(REPLACE "$<" "" transpose_CXX_FLAGS "${transpose_CXX_FLAGS}")
string(REPLACE ">:" ":" transpose_CXX_FLAGS "${transpose_CXX_FLAGS}")
string(REPLACE ">" "" transpose_CXX_FLAGS "${transpose_CXX_FLAGS}")
string(REPLACE "COMPILE_LANGUAGE:CXX:" "" transpose_CXX_FLAGS "${transpose_CXX_FLAGS}")
# remove double spaces
string(REPLACE " " " " transpose_CXX_FLAGS "${transpose_CXX_FLAGS}")
# convert to list
string(REPLACE " " ";" transpose_CXX_FLAGS "${transpose_CXX_FLAGS}")
# remove duplicate args
list(REMOVE_DUPLICATES transpose_CXX_FLAGS)
# make single string
string(REPLACE ";" " " transpose_CXX_FLAGS "${transpose_CXX_FLAGS}")
# configure files in build directory
configure_file(${PROJECT_SOURCE_DIR}/transpose.cpp
${CMAKE_BINARY_DIR}/transpose/transpose.cpp COPYONLY)
configure_file(${PROJECT_SOURCE_DIR}/Makefile.in
${CMAKE_BINARY_DIR}/transpose/Makefile @ONLY)
# touch the file when cmake re-runs to ensure rebuilt
execute_process(COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/transpose/transpose.cpp)
# target for adding a dependency to libpytimemory target
add_custom_target(transpose ALL
COMMAND ${MAKE_EXECUTABLE}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/transpose
BYPRODUCTS ${CMAKE_BINARY_DIR}/transpose/transpose
SOURCES ${CMAKE_BINARY_DIR}/transpose/transpose.cpp)
+38
Просмотреть файл
@@ -0,0 +1,38 @@
CXXFLAGS += -std=c++17 -O3 -Wno-unused-result -g
all: transpose
debug: CXXFLAGS += -ggdb -g
debug: transpose
transpose: transpose.cpp
hipcc ${CXXFLAGS} -o $@ $^
.PHONY: clean
run:
./transpose
run.verbose:
AMD_LOG_LEVEL=3, AMD_LOG_MASK=128 ./transpose
rd:
rocgdb --args ./transpose
prof.trace:
rocprof --hip-trace --stats ./transpose
prof:
rocprof --obj-tracking on -i profile.txt ./transpose
prof.full:
rocprof --obj-tracking on -i profile.txt -m custom_metric.xml ./transpose
callgrind:
valgrind --tool=callgrind ./transpose
callgrind.ann:
callgrind_annotate --inclusive=yes --tree=both callgrind.out.* > callgrind.out
clean:
rm -f transpose *.o results.*
+37
Просмотреть файл
@@ -0,0 +1,37 @@
CXXFLAGS += -std=c++@CMAKE_CXX_STANDARD@ @transpose_CXX_FLAGS@
all: transpose
debug: CXXFLAGS += -ggdb -g
debug: transpose
transpose: transpose.cpp
hipcc ${CXXFLAGS} -o $@ $^
.PHONY: clean
run:
./transpose
run.verbose:
AMD_LOG_LEVEL=3, AMD_LOG_MASK=128 ./transpose
rd:
rocgdb --args ./transpose
prof.trace:
rocprof --hip-trace --stats ./transpose
prof:
rocprof --obj-tracking on -i profile.txt ./transpose
prof.full:
rocprof --obj-tracking on -i profile.txt -m custom_metric.xml ./transpose
callgrind:
valgrind --tool=callgrind ./transpose
callgrind.ann:
callgrind_annotate --inclusive=yes --tree=both callgrind.out.* > callgrind.out
clean:
rm -f transpose *.o results.*
+156
Просмотреть файл
@@ -0,0 +1,156 @@
/*
Copyright (c) 2015-2020 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
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.
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
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.
*/
#include "hip/hip_runtime.h"
#include <cfloat>
#include <chrono>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <vector>
#define HIP_API_CALL(CALL) \
{ \
hipError_t error_ = (CALL); \
if(error_ != hipSuccess) \
{ \
fprintf(stderr, "%s:%d :: HIP error : %s\n", __FILE__, __LINE__, \
hipGetErrorString(error_)); \
exit(EXIT_FAILURE); \
} \
}
void
check_hip_error(void)
{
hipError_t err = hipGetLastError();
if(err != hipSuccess)
{
std::cerr << "Error: " << hipGetErrorString(err) << std::endl;
exit(err);
}
}
void
verify(int* in, int* out, int M, int N)
{
for(int i = 0; i < 10; i++)
{
int row = rand() % M;
int col = rand() % N;
if(in[row * N + col] != out[col * M + row])
{
std::cout << "mismatch: " << row << ", " << col << " : " << in[row * N + col]
<< " | " << out[col * M + row] << "\n";
}
}
}
const unsigned TILE_DIM = 32;
__global__ void
transpose_a(int* in, int* out, int M, int N)
{
__shared__ int tile[TILE_DIM][TILE_DIM];
int idx = (blockIdx.y * blockDim.y + threadIdx.y) * M + blockIdx.x * blockDim.x +
threadIdx.x;
tile[threadIdx.y][threadIdx.x] = in[idx];
__syncthreads();
idx = (blockIdx.x * blockDim.x + threadIdx.y) * N + blockIdx.y * blockDim.y +
threadIdx.x;
out[idx] = tile[threadIdx.x][threadIdx.y];
}
void
run(int argc, char** argv)
{
(void) argc;
(void) argv;
unsigned int M = 4960;
unsigned int N = 4960;
std::cout << "M: " << M << " N: " << N << std::endl;
size_t size = sizeof(int) * M * N;
int* matrix = (int*) malloc(size);
for(size_t i = 0; i < M * N; i++)
matrix[i] = rand() % 1002;
int *in, *out;
std::chrono::high_resolution_clock::time_point t1, t2;
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();
HIP_API_CALL(hipDeviceSynchronize());
}
t2 = std::chrono::high_resolution_clock::now();
double time =
std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1).count();
float GB = (float) size * times * 2 / (1 << 30);
std::cout << "The average performance of transpose is " << GB / time << " GBytes/sec"
<< std::endl;
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);
}
int
main(int argc, char** argv)
{
run(argc, argv);
return 0;
}
+219
Просмотреть файл
@@ -0,0 +1,219 @@
/*
Copyright (c) 2015-2020 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
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.
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
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.
*/
#include "hip/hip_runtime.h"
#include <cfloat>
#include <chrono>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <vector>
void
check_hip_error(void)
{
hipError_t err = hipGetLastError();
if(err != hipSuccess)
{
std::cerr << "Error: " << hipGetErrorString(err) << std::endl;
exit(err);
}
}
__global__ void
transpose_naive(int* in, int* out, int M, int N)
{
int idx = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x;
for(int i = idx; i < M * N; i += hipBlockDim_x * hipGridDim_x)
{
int row = i / N;
int col = i % N;
out[col * M + row] = in[row * N + col];
}
}
void
cpu_transpose(int* in, int* out, int M, int N)
{
for(int i = 0; i < M; i++)
for(int j = 0; j < N; j++)
out[j * M + i] = in[i * N + j];
}
void
verify(int* in, int* out, int M, int N)
{
for(int i = 0; i < 10; i++)
{
int row = rand() % M;
int col = rand() % N;
if(in[row * N + col] != out[col * M + row])
{
std::cout << "mismatch: " << row << ", " << col << " : " << in[row * N + col]
<< " | " << out[col * M + row] << "\n";
}
}
}
const unsigned TILE_DIM = 32;
__global__ void
transpose_a(int* in, int* out, int M, int N)
{
int iidx = (blockIdx.x * blockDim.x + threadIdx.x) * N + blockIdx.y * blockDim.y +
threadIdx.y;
int oidx =
(blockIdx.y * blockDim.y + threadIdx.y) * +blockIdx.x * blockDim.x + threadIdx.x;
out[oidx] = in[iidx];
}
const int NUM_ITEM = 8;
__global__ void
transpose_e(int* A, int* B, int n1, int n2)
{
__shared__ int Cs[64][64 + 1];
int index;
index = (blockIdx.y * blockDim.y * NUM_ITEM + threadIdx.y) * n1 +
blockIdx.x * blockDim.x + threadIdx.x;
for(int i = 0; i < NUM_ITEM; ++i)
{
Cs[threadIdx.y + i * NUM_ITEM][threadIdx.x] = A[index + i * NUM_ITEM * n1];
}
__syncthreads();
index = (blockIdx.x * blockDim.x + threadIdx.y) * n2 +
blockIdx.y * blockDim.y * NUM_ITEM + threadIdx.x;
for(int i = 0; i < NUM_ITEM; ++i)
{
B[index + i * NUM_ITEM * n2] = Cs[threadIdx.x][threadIdx.y + i * NUM_ITEM];
}
}
__global__ void
transpose_s(int* out, int* in, int n1, int n2)
{
int x = hipBlockDim_x * hipBlockIdx_x + hipThreadIdx_x;
int val = in[x];
for(int i = 0; i < n1; i++)
{
for(int j = 0; j < n2; j++)
out[i * n2 + j] = __shfl(val, j * n2 + i);
}
}
int
main(int argc, char** argv)
{
int nx = 32;
int ny = 32;
if(argc > 1)
nx = atoi(argv[1]);
if(argc > 2)
ny = atoi(argv[2]);
unsigned int M = 4960;
unsigned int N = 4960;
if(argc > 3)
M = atoi(argv[3]);
if(argc > 4)
N = atoi(argv[4]);
std::cout << "M: " << M << " N: " << N << std::endl;
size_t size = sizeof(int) * M * N;
int* matrix = (int*) malloc(size);
for(int i = 0; i < M * N; i++)
matrix[i] = rand() % 1002;
int *in, *out;
std::chrono::high_resolution_clock::time_point t1, t2;
hipMalloc(&in, size);
hipMalloc(&out, size);
hipMemset(in, 0, size);
hipMemset(out, 0, size);
check_hip_error();
hipMemcpy(in, matrix, size, hipMemcpyHostToDevice);
hipDeviceSynchronize();
check_hip_error();
hipDeviceProp_t props;
hipGetDeviceProperties(&props, 0);
dim3 grid(M / nx, N / ny, 1);
dim3 block(nx, ny, 1); // transpose_a
// dim3 grid(M/64, N/64, 1); dim3 block(64, 8, 1); // transpose_e
#define TRANSPOSE_KERNEL transpose_a
// warmup
hipLaunchKernelGGL(TRANSPOSE_KERNEL, grid, block, 0, 0, in, out, M, N);
check_hip_error();
t1 = std::chrono::high_resolution_clock::now();
const unsigned times = 10000;
for(int i = 0; i < times; i++)
{
hipLaunchKernelGGL(TRANSPOSE_KERNEL, grid, block, 0, 0, in, out, M, N);
check_hip_error();
hipDeviceSynchronize();
check_hip_error();
}
t2 = std::chrono::high_resolution_clock::now();
double time =
std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1).count();
float GB = (float) size * times * 2 / (1 << 30);
std::cout << "The average performance of transpose is " << GB / time << " GBytes/sec"
<< std::endl;
int* out_matrix = (int*) malloc(size);
hipMemcpy(out_matrix, out, size, hipMemcpyDeviceToHost);
check_hip_error();
// cpu_transpose(matrix, out_matrix, M, N);
verify(matrix, out_matrix, M, N);
hipFree(in);
hipFree(out);
check_hip_error();
free(matrix);
free(out_matrix);
return 0;
}
/*
dim3 threads(256,1,1); //3D dimensions of a block of threads
dim3 blocks((N+256-1)/256,1,1); //3D dimensions the grid of blocks
hipLaunchKernelGGL(myKernel, //Kernel name (__global__ void function)
blocks, //Grid dimensions
threads, //Block dimensions
0, //Bytes of dynamic LDS space (see extra slides)
0, //Stream (0=NULL stream)
N, a); //Kernel arguments
*/
+682
Просмотреть файл
@@ -0,0 +1,682 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
//
#pragma once
#include "timemory/backends/process.hpp"
#include "timemory/environment.hpp"
#include "timemory/mpl/apply.hpp"
#include "timemory/utility/argparse.hpp"
#include "timemory/utility/macros.hpp"
#include "timemory/utility/popen.hpp"
#include "timemory/variadic/macros.hpp"
#include "BPatch.h"
#include "BPatch_Vector.h"
#include "BPatch_addressSpace.h"
#include "BPatch_basicBlockLoop.h"
#include "BPatch_callbacks.h"
#include "BPatch_function.h"
#include "BPatch_point.h"
#include "BPatch_process.h"
#include "BPatch_snippet.h"
#include "BPatch_statement.h"
#include <cstring>
#include <limits>
#include <numeric>
#include <regex>
#include <set>
#include <string>
#include <vector>
//
#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <unistd.h>
#define MUTNAMELEN 1024
#define FUNCNAMELEN 32 * 1024
#define NO_ERROR -1
#define TIMEMORY_BIN_DIR "bin"
#if !defined(PATH_MAX)
# define PATH_MAX std::numeric_limits<int>::max();
#endif
struct function_signature;
struct module_function;
template <typename Tp>
using bpvector_t = BPatch_Vector<Tp>;
using string_t = std::string;
using stringstream_t = std::stringstream;
using strvec_t = std::vector<string_t>;
using strset_t = std::set<string_t>;
using regexvec_t = std::vector<std::regex>;
using fmodset_t = std::set<module_function>;
using exec_callback_t = BPatchExecCallback;
using exit_callback_t = BPatchExitCallback;
using fork_callback_t = BPatchForkCallback;
using patch_t = BPatch;
using process_t = BPatch_process;
using thread_t = BPatch_thread;
using binary_edit_t = BPatch_binaryEdit;
using image_t = BPatch_image;
using module_t = BPatch_module;
using procedure_t = BPatch_function;
using snippet_t = BPatch_snippet;
using call_expr_t = BPatch_funcCallExpr;
using address_space_t = BPatch_addressSpace;
using flow_graph_t = BPatch_flowGraph;
using basic_loop_t = BPatch_basicBlockLoop;
using procedure_loc_t = BPatch_procedureLocation;
using point_t = BPatch_point;
using local_var_t = BPatch_localVar;
using const_expr_t = BPatch_constExpr;
using error_level_t = BPatchErrorLevel;
using patch_pointer_t = std::shared_ptr<patch_t>;
using snippet_pointer_t = std::shared_ptr<snippet_t>;
using call_expr_pointer_t = std::shared_ptr<call_expr_t>;
using snippet_vec_t = bpvector_t<snippet_t*>;
using procedure_vec_t = bpvector_t<procedure_t*>;
using basic_loop_vec_t = bpvector_t<basic_loop_t*>;
using snippet_pointer_vec_t = std::vector<snippet_pointer_t>;
void
hosttrace_prefork_callback(thread_t* parent, thread_t* child);
//======================================================================================//
//
// Global Variables
//
//======================================================================================//
//
// boolean settings
//
static bool binary_rewrite = 0;
static bool loop_level_instr = false;
static bool werror = false;
static bool stl_func_instr = false;
static bool cstd_func_instr = false;
static bool use_mpi = false;
static bool is_static_exe = false;
static bool use_return_info = false;
static bool use_args_info = false;
static bool use_file_info = false;
static bool use_line_info = false;
//
// integral settings
//
static bool debug_print = false;
static int expect_error = NO_ERROR;
static int error_print = 0;
static int verbose_level = tim::get_env<int>("TIMEMORY_RUN_VERBOSE", 0);
//
// string settings
//
static string_t main_fname = "main";
static string_t argv0 = "";
static string_t cmdv0 = "";
static string_t default_components = "wall_clock";
static string_t prefer_library = "";
//
// global variables
//
static patch_pointer_t bpatch;
static call_expr_t* initialize_expr = nullptr;
static call_expr_t* terminate_expr = nullptr;
static snippet_vec_t init_names;
static snippet_vec_t fini_names;
static fmodset_t available_module_functions;
static fmodset_t instrumented_module_functions;
static regexvec_t func_include;
static regexvec_t func_exclude;
static regexvec_t file_include;
static regexvec_t file_exclude;
static auto regex_opts = std::regex_constants::egrep | std::regex_constants::optimize;
//
//======================================================================================//
// control debug printf statements
#define dprintf(...) \
if(debug_print || verbose_level > 0) \
fprintf(stderr, __VA_ARGS__); \
fflush(stderr);
// control verbose printf statements
#define verbprintf(LEVEL, ...) \
if(verbose_level >= LEVEL) \
fprintf(stdout, __VA_ARGS__); \
fflush(stdout);
//======================================================================================//
template <typename... T>
void
consume_parameters(T&&...)
{}
//======================================================================================//
extern "C"
{
bool are_file_include_exclude_lists_empty();
bool process_file_for_instrumentation(const string_t& file_name);
bool instrument_entity(const string_t& function_name);
bool module_constraint(char* fname);
bool routine_constraint(const char* fname);
}
//======================================================================================//
function_signature
get_func_file_line_info(module_t* mutatee_module, procedure_t* f);
function_signature
get_loop_file_line_info(module_t* mutatee_module, procedure_t* f, flow_graph_t* cfGraph,
basic_loop_t* loopToInstrument);
template <typename Tp>
void
insert_instr(address_space_t* mutatee, procedure_t* funcToInstr, Tp traceFunc,
procedure_loc_t traceLoc, flow_graph_t* cfGraph = nullptr,
basic_loop_t* loopToInstrument = nullptr);
void
errorFunc(error_level_t level, int num, const char** params);
procedure_t*
find_function(image_t* appImage, const string_t& functionName, strset_t = {});
void
error_func_real(error_level_t level, int num, const char* const* params);
void
error_func_fake(error_level_t level, int num, const char* const* params);
bool
find_func_or_calls(std::vector<const char*> names, bpvector_t<point_t*>& points,
image_t* appImage, procedure_loc_t loc = BPatch_locEntry);
bool
find_func_or_calls(const char* name, bpvector_t<point_t*>& points, image_t* image,
procedure_loc_t loc = BPatch_locEntry);
bool
load_dependent_libraries(address_space_t* bedit, char* bindings);
bool
c_stdlib_module_constraint(const string_t& file);
bool
c_stdlib_function_constraint(const string_t& func);
//======================================================================================//
inline string_t
get_absolute_path(const char* fname)
{
char path_save[PATH_MAX];
char abs_exe_path[PATH_MAX];
char* p = nullptr;
if(!(p = strrchr((char*) fname, '/')))
{
auto ret = getcwd(abs_exe_path, sizeof(abs_exe_path));
consume_parameters(ret);
}
else
{
auto rets = getcwd(path_save, sizeof(path_save));
auto retf = chdir(fname);
auto reta = getcwd(abs_exe_path, sizeof(abs_exe_path));
auto retp = chdir(path_save);
consume_parameters(rets, retf, reta, retp);
}
return string_t(abs_exe_path);
}
//======================================================================================//
inline string_t
to_lower(string_t s)
{
for(auto& itr : s)
itr = tolower(itr);
return s;
}
//
//======================================================================================//
//
struct function_signature
{
using location_t = std::pair<unsigned long, unsigned long>;
bool m_loop = false;
bool m_info_beg = false;
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_name = "";
string_t m_params = "()";
string_t m_file = "";
mutable string_t m_signature = "";
TIMEMORY_DEFAULT_OBJECT(function_signature)
function_signature(string_t _ret, string_t _name, string_t _file,
location_t _row = { 0, 0 }, location_t _col = { 0, 0 },
bool _loop = false, bool _info_beg = false, bool _info_end = false)
: m_loop(_loop)
, m_info_beg(_info_beg)
, m_info_end(_info_end)
, m_row(_row)
, m_col(_col)
, m_return(_ret)
, m_name(tim::demangle(_name))
, m_file(_file)
{
if(m_file.find('/') != string_t::npos)
m_file = m_file.substr(m_file.find_last_of('/') + 1);
}
function_signature(string_t _ret, string_t _name, string_t _file,
std::vector<string_t> _params, location_t _row = { 0, 0 },
location_t _col = { 0, 0 }, bool _loop = false,
bool _info_beg = false, bool _info_end = false)
: function_signature(_ret, _name, _file, _row, _col, _loop, _info_beg, _info_end)
{
std::stringstream ss;
ss << "(";
for(auto& itr : _params)
ss << itr << ", ";
m_params = ss.str();
m_params = m_params.substr(0, m_params.length() - 2);
m_params += ")";
}
static auto get(function_signature& sig) { return sig.get(); }
string_t get() const
{
std::stringstream ss;
if(use_return_info)
ss << m_return << " ";
ss << m_name;
if(use_args_info)
ss << m_params;
if(m_loop && m_info_beg)
{
if(m_info_end)
{
ss << '/' << "[{" << m_row.first << "," << m_col.first << "}-{"
<< m_row.second << "," << m_col.second << "}]";
}
else
{
ss << "[{" << m_row.first << "," << m_col.first << "}]";
}
}
else
{
if(use_file_info && m_file.length() > 0)
ss << '/' << m_file;
if(use_line_info && m_row.first > 0)
ss << ":" << m_row.first;
}
m_signature = ss.str();
return m_signature;
}
};
//
//======================================================================================//
//
struct module_function
{
using width_t = std::array<size_t, 3>;
static auto& get_width()
{
static width_t _instance = []() {
width_t _tmp;
_tmp.fill(0);
return _tmp;
}();
return _instance;
}
static void reset_width() { get_width().fill(0); }
static void update_width(const module_function& rhs)
{
get_width()[0] = std::max<size_t>(get_width()[0], rhs.module.length());
get_width()[1] = std::max<size_t>(get_width()[1], rhs.function.length());
get_width()[2] = std::max<size_t>(get_width()[2], rhs.signature.get().length());
}
module_function(const string_t& _module, const string_t& _func,
const function_signature& _sign)
: module(_module)
, function(_func)
, signature(_sign)
{}
module_function(module_t* mod, procedure_t* proc)
{
char modname[FUNCNAMELEN];
char fname[FUNCNAMELEN];
mod->getName(modname, FUNCNAMELEN);
proc->getName(fname, FUNCNAMELEN);
module = modname;
function = fname;
signature = get_func_file_line_info(mod, proc);
}
friend bool operator<(const module_function& lhs, const module_function& rhs)
{
return (lhs.module == rhs.module)
? ((lhs.function == rhs.function)
? (lhs.signature.get() < rhs.signature.get())
: (lhs.function < rhs.function))
: (lhs.module < rhs.module);
}
friend std::ostream& operator<<(std::ostream& os, const module_function& rhs)
{
std::stringstream ss;
static size_t absolute_max = 80;
auto w0 = std::min<size_t>(get_width()[0], absolute_max);
auto w1 = std::min<size_t>(get_width()[1], absolute_max);
auto w2 = std::min<size_t>(get_width()[2], absolute_max);
auto _get_str = [](const std::string& _inc) {
if(_inc.length() > absolute_max)
return _inc.substr(0, absolute_max - 3) + "...";
return _inc;
};
ss << std::setw(w0 + 8) << std::left << _get_str(rhs.module) << " "
<< std::setw(w1 + 8) << std::left << _get_str(rhs.function) << " "
<< std::setw(w2 + 8) << std::left << _get_str(rhs.signature.get());
os << ss.str();
return os;
}
string_t module = "";
string_t function = "";
function_signature signature;
};
//
//======================================================================================//
//
static inline void
dump_info(const string_t& _oname, const fmodset_t& _data, int level)
{
if(!debug_print && verbose_level < level)
return;
module_function::reset_width();
for(const auto& itr : _data)
module_function::update_width(itr);
std::ofstream ofs(_oname);
if(ofs)
{
verbprintf(level, "Dumping '%s'... ", _oname.c_str());
for(const auto& itr : _data)
ofs << itr << '\n';
verbprintf(level, "Done\n");
}
ofs.close();
module_function::reset_width();
}
//
//======================================================================================//
//
template <typename Tp>
snippet_pointer_t
get_snippet(Tp arg)
{
return snippet_pointer_t(new const_expr_t(arg));
}
//
//======================================================================================//
//
inline snippet_pointer_t
get_snippet(string_t arg)
{
return snippet_pointer_t(new const_expr_t(arg.c_str()));
}
//
//======================================================================================//
//
template <typename... Args>
snippet_pointer_vec_t
get_snippets(Args&&... args)
{
snippet_pointer_vec_t _tmp;
TIMEMORY_FOLD_EXPRESSION(_tmp.push_back(get_snippet(std::forward<Args>(args))));
return _tmp;
}
//
//======================================================================================//
//
struct hosttrace_call_expr
{
using snippet_pointer_t = std::shared_ptr<snippet_t>;
template <typename... Args>
hosttrace_call_expr(Args&&... args)
: m_params(get_snippets(std::forward<Args>(args)...))
{}
snippet_vec_t get_params()
{
snippet_vec_t _ret;
for(auto& itr : m_params)
_ret.push_back(itr.get());
return _ret;
}
inline call_expr_pointer_t get(procedure_t* func)
{
return call_expr_pointer_t((func) ? new call_expr_t(*func, get_params())
: nullptr);
}
private:
snippet_pointer_vec_t m_params;
};
//
//======================================================================================//
//
struct hosttrace_snippet_vec
{
using entry_type = std::vector<hosttrace_call_expr>;
using value_type = std::vector<call_expr_pointer_t>;
template <typename... Args>
void generate(procedure_t* func, Args&&... args)
{
auto _expr = hosttrace_call_expr(std::forward<Args>(args)...);
auto _call = _expr.get(func);
if(_call)
{
m_entries.push_back(_expr);
m_data.push_back(_call);
// m_data.push_back(entry_type{ _call, _expr });
}
}
void append(snippet_vec_t& _obj)
{
for(auto& itr : m_data)
_obj.push_back(itr.get());
}
private:
entry_type m_entries;
value_type m_data;
};
//
//======================================================================================//
//
static inline address_space_t*
hosttrace_get_address_space(patch_pointer_t _bpatch, int _cmdc, char** _cmdv,
bool _rewrite, int _pid = -1, string_t _name = "")
{
address_space_t* mutatee = nullptr;
if(_rewrite)
{
verbprintf(1, "Opening '%s' for binary rewrite... ", _name.c_str());
fflush(stderr);
if(!_name.empty())
mutatee = _bpatch->openBinary(_name.c_str(), false);
if(!mutatee)
{
fprintf(stderr, "[hosttrace]> Failed to open binary '%s'\n", _name.c_str());
throw std::runtime_error("Failed to open binary");
}
verbprintf(1, "Done\n");
}
else if(_pid >= 0)
{
verbprintf(1, "Attaching to process %i... ", _pid);
fflush(stderr);
char* _cmdv0 = (_cmdc > 0) ? _cmdv[0] : nullptr;
mutatee = _bpatch->processAttach(_cmdv0, _pid);
if(!mutatee)
{
fprintf(stderr, "[hosttrace]> Failed to connect to process %i\n", (int) _pid);
throw std::runtime_error("Failed to attach to process");
}
verbprintf(1, "Done\n");
}
else
{
verbprintf(1, "Creating process '%s'... ", _cmdv[0]);
fflush(stderr);
mutatee = _bpatch->processCreate(_cmdv[0], (const char**) _cmdv, nullptr);
if(!mutatee)
{
std::stringstream ss;
for(int i = 0; i < _cmdc; ++i)
{
if(!_cmdv[i])
continue;
ss << _cmdv[i] << " ";
}
fprintf(stderr, "[hosttrace]> Failed to create process: '%s'\n",
ss.str().c_str());
throw std::runtime_error("Failed to create process");
}
verbprintf(1, "Done\n");
}
return mutatee;
}
//
//======================================================================================//
//
TIMEMORY_NOINLINE inline void
hosttrace_thread_exit(thread_t* thread, BPatch_exitType exit_type)
{
if(!thread)
return;
BPatch_process* app = thread->getProcess();
if(!terminate_expr)
{
fprintf(stderr, "[hosttrace]> continuing execution\n");
app->continueExecution();
return;
}
switch(exit_type)
{
case ExitedNormally: {
fprintf(stderr, "[hosttrace]> Thread exited normally\n");
break;
}
case ExitedViaSignal: {
fprintf(stderr, "[hosttrace]> Thread terminated unexpectedly\n");
break;
}
case NoExit:
default: {
fprintf(stderr, "[hosttrace]> %s invoked with NoExit\n", __FUNCTION__);
break;
}
}
// terminate_expr = nullptr;
thread->oneTimeCode(*terminate_expr);
fprintf(stderr, "[hosttrace]> continuing execution\n");
app->continueExecution();
}
//
//======================================================================================//
//
TIMEMORY_NOINLINE inline void
hosttrace_fork_callback(thread_t* parent, thread_t* child)
{
if(child)
{
auto* app = child->getProcess();
if(app)
{
verbprintf(4, "Stopping execution and detaching child fork...\n");
app->stopExecution();
app->detach(true);
// app->terminateExecution();
// app->continueExecution();
}
}
if(parent)
{
auto app = parent->getProcess();
if(app)
{
verbprintf(4, "Continuing execution on parent after fork callback...\n");
app->continueExecution();
}
}
}
//
//======================================================================================//
//
+65
Просмотреть файл
@@ -0,0 +1,65 @@
# requires clang-tidy version 6.0+
---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: true
AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: TopLevel
AlwaysBreakAfterReturnType: TopLevel
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BasedOnStyle: Mozilla
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: false
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: true
ColumnLimit: 90
CompactNamespaces: true
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 0
ContinuationIndentWidth: 4
FixNamespaceComments: true
IndentCaseLabels: true
IndentPPDirectives: AfterHash
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: false
Language: Cpp
PointerAlignment: Left
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Never
...
+221
Просмотреть файл
@@ -0,0 +1,221 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/api/macros.hpp"
#include "timemory/macros/os.hpp"
#include "timemory/mpl/concepts.hpp"
#include <type_traits>
//
// General APIs
//
TIMEMORY_DEFINE_NS_API(project, none) // dummy type
TIMEMORY_DEFINE_NS_API(project, timemory) // provided by timemory API exclusively
TIMEMORY_DEFINE_NS_API(project, python) // provided by timemory python interface
TIMEMORY_DEFINE_NS_API(project, kokkosp) // kokkos profiling API
//
// Device APIs
//
TIMEMORY_DECLARE_NS_API(device, cpu) // collects data on CPU
TIMEMORY_DECLARE_NS_API(device, gpu) // collects data on GPU
//
// Category APIs
//
TIMEMORY_DEFINE_NS_API(category, debugger) // provided debugging utilities
TIMEMORY_DEFINE_NS_API(category, decorator) // decorates external profiler
TIMEMORY_DEFINE_NS_API(category, external) // relies on external package
TIMEMORY_DEFINE_NS_API(category, io) // collects I/O data
TIMEMORY_DEFINE_NS_API(category, logger) // logs generic data or messages
TIMEMORY_DEFINE_NS_API(category, hardware_counter) // collects HW counter data
TIMEMORY_DEFINE_NS_API(category, memory) // collects memory data
TIMEMORY_DEFINE_NS_API(category, resource_usage) // collects resource usage data
TIMEMORY_DEFINE_NS_API(category, timing) // collects timing data
TIMEMORY_DEFINE_NS_API(category, visualization) // related to viz (currently unused)
//
// External Third-party library APIs
//
TIMEMORY_DEFINE_NS_API(tpls, allinea)
TIMEMORY_DEFINE_NS_API(tpls, caliper)
TIMEMORY_DEFINE_NS_API(tpls, craypat)
TIMEMORY_DEFINE_NS_API(tpls, gotcha)
TIMEMORY_DEFINE_NS_API(tpls, gperftools)
TIMEMORY_DEFINE_NS_API(tpls, intel)
TIMEMORY_DEFINE_NS_API(tpls, likwid)
TIMEMORY_DEFINE_NS_API(tpls, nvidia)
TIMEMORY_DEFINE_NS_API(tpls, openmp)
TIMEMORY_DEFINE_NS_API(tpls, rocm)
TIMEMORY_DEFINE_NS_API(tpls, papi)
TIMEMORY_DEFINE_NS_API(tpls, tau)
//
// OS-specific APIs
//
TIMEMORY_DEFINE_NS_API(os, agnostic)
TIMEMORY_DEFINE_NS_API(os, supports_unix)
TIMEMORY_DEFINE_NS_API(os, supports_linux)
TIMEMORY_DEFINE_NS_API(os, supports_darwin)
TIMEMORY_DEFINE_NS_API(os, supports_windows)
//
//--------------------------------------------------------------------------------------//
//
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, project::timemory, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, project::python, true_type)
//
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, category::debugger, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, category::decorator, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, category::external, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, category::io, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, category::logger, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, category::hardware_counter,
true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, category::resource_usage,
true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, category::timing, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, category::visualization,
true_type)
//
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, tpls::allinea, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, tpls::caliper, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, tpls::craypat, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, tpls::gotcha, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, tpls::gperftools, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, tpls::intel, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, tpls::likwid, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, tpls::nvidia, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, tpls::openmp, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, tpls::papi, true_type)
TIMEMORY_DEFINE_CONCRETE_CONCEPT(is_runtime_configurable, tpls::tau, true_type)
//
namespace tim
{
namespace api
{
using native_tag = project::timemory;
}
//
namespace trait
{
//
#if !defined(TIMEMORY_UNIX)
template <>
struct is_available<os::supports_unix> : false_type
{};
#endif
//
#if !defined(TIMEMORY_LINUX)
template <>
struct is_available<os::supports_linux> : false_type
{};
#endif
//
#if !defined(TIMEMORY_MACOS)
template <>
struct is_available<os::supports_darwin> : false_type
{};
#endif
//
#if !defined(TIMEMORY_WINDOWS)
template <>
struct is_available<os::supports_windows> : false_type
{};
#endif
//
} // namespace trait
//
} // namespace tim
//
//--------------------------------------------------------------------------------------//
//
namespace tim
{
namespace cereal
{
class JSONInputArchive;
class XMLInputArchive;
class XMLOutputArchive;
} // namespace cereal
} // namespace tim
//
//--------------------------------------------------------------------------------------//
//
// Default pre-processor settings
//
//--------------------------------------------------------------------------------------//
//
#if !defined(TIMEMORY_DEFAULT_API)
# define TIMEMORY_DEFAULT_API ::tim::project::timemory
#endif
#if !defined(TIMEMORY_API)
# define TIMEMORY_API TIMEMORY_DEFAULT_API
#endif
#if defined(DISABLE_TIMEMORY) || defined(TIMEMORY_DISABLED)
# if !defined(TIMEMORY_DEFAULT_AVAILABLE)
# define TIMEMORY_DEFAULT_AVAILABLE false_type
# endif
#else
# if !defined(TIMEMORY_DEFAULT_AVAILABLE)
# define TIMEMORY_DEFAULT_AVAILABLE true_type
# endif
#endif
#if !defined(TIMEMORY_DEFAULT_STATISTICS_TYPE)
# if defined(TIMEMORY_USE_STATISTICS)
# define TIMEMORY_DEFAULT_STATISTICS_TYPE true_type
# else
# define TIMEMORY_DEFAULT_STATISTICS_TYPE false_type
# endif
#endif
#if !defined(TIMEMORY_DEFAULT_PLOTTING)
# define TIMEMORY_DEFAULT_PLOTTING false
#endif
#if !defined(TIMEMORY_DEFAULT_ENABLED)
# define TIMEMORY_DEFAULT_ENABLED true
#endif
#if !defined(TIMEMORY_PYTHON_PLOTTER)
# define TIMEMORY_PYTHON_PLOTTER "python"
#endif
#if !defined(TIMEMORY_DEFAULT_INPUT_ARCHIVE)
# define TIMEMORY_DEFAULT_INPUT_ARCHIVE cereal::JSONInputArchive
#endif
#if !defined(TIMEMORY_DEFAULT_OUTPUT_ARCHIVE)
# define TIMEMORY_DEFAULT_OUTPUT_ARCHIVE ::tim::type_list<>
#endif
#if !defined(TIMEMORY_INPUT_ARCHIVE)
# define TIMEMORY_INPUT_ARCHIVE TIMEMORY_DEFAULT_INPUT_ARCHIVE
#endif
#if !defined(TIMEMORY_OUTPUT_ARCHIVE)
# define TIMEMORY_OUTPUT_ARCHIVE TIMEMORY_DEFAULT_OUTPUT_ARCHIVE
#endif
+76
Просмотреть файл
@@ -0,0 +1,76 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/mpl/concepts.hpp"
/// \macro TIMEMORY_DECLARE_NS_API(NS, NAME)
/// \brief Declare an API category. APIs are used to designate
/// different project implementations, different external library tools, etc.
///
#if !defined(TIMEMORY_DECLARE_NS_API)
# define TIMEMORY_DECLARE_NS_API(NS, NAME) \
namespace tim \
{ \
namespace NS \
{ \
struct NAME; \
} \
}
#endif
#if !defined(TIMEMORY_DECLARE_API)
# define TIMEMORY_DECLARE_API(NAME) TIMEMORY_DECLARE_NS_API(api, NAME)
#endif
//
/// \macro TIMEMORY_DEFINE_NS_API(NS, NAME)
/// \param NS sub-namespace within tim::
/// \param NAME the name of the API
///
/// \brief Define an API category within a namespace
///
#if !defined(TIMEMORY_DEFINE_NS_API)
# define TIMEMORY_DEFINE_NS_API(NS, NAME) \
namespace tim \
{ \
namespace NS \
{ \
struct NAME : public concepts::api \
{}; \
} \
}
#endif
///
/// \macro TIMEMORY_DEFINE_API
/// \brief Define an API category. APIs are used to designate
/// different project implementations, different external library tools, etc.
/// Note: this macro inherits from \ref concepts::api instead of specializing
/// is_api<...>, thus allowing specialization from tools downstream
///
#if !defined(TIMEMORY_DEFINE_API)
# define TIMEMORY_DEFINE_API(NAME) TIMEMORY_DEFINE_NS_API(api, NAME)
#endif
+110
Просмотреть файл
@@ -0,0 +1,110 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
/** \file backends/process.hpp
* \headerfile backends/process.hpp "timemory/backends/process.hpp"
* Defines process backend functions
*
*/
#pragma once
#include "timemory/macros/os.hpp"
#include "timemory/utility/macros.hpp"
#include <cstdint>
#include <cstdio>
#if defined(TIMEMORY_UNIX)
# include <sys/resource.h>
# include <unistd.h>
# if defined(TIMEMORY_MACOS)
# include <libproc.h>
# include <mach/mach.h>
# endif
#elif defined(TIMEMORY_WINDOWS)
# if !defined(NOMINMAX)
# define NOMINMAX
# endif
# if !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
#endif
namespace tim
{
namespace process
{
//
//--------------------------------------------------------------------------------------//
//
#if defined(TIMEMORY_UNIX)
using id_t = pid_t;
#elif defined(TIMEMORY_WINDOWS)
using id_t = DWORD;
#else
using id_t = int;
#endif
//
//--------------------------------------------------------------------------------------//
//
/// \fn pid_t tim::process::get_id()
/// \brief get the process id of this process
///
inline id_t
get_id()
{
#if defined(TIMEMORY_WINDOWS)
static auto instance = GetCurrentProcessId();
#elif defined(TIMEMORY_UNIX)
static auto instance = getpid();
#else
static auto instance = 0;
#endif
return instance;
}
//
//--------------------------------------------------------------------------------------//
//
/// \fn pid_t& tim::process::get_target_id()
/// \brief get the target process id of this process (may differ from process::get_id)
///
inline id_t&
get_target_id()
{
#if defined(TIMEMORY_WINDOWS)
static auto instance = GetCurrentProcessId();
#elif defined(TIMEMORY_UNIX)
static auto instance = getpid();
#else
static auto instance = 0;
#endif
return instance;
}
//
//--------------------------------------------------------------------------------------//
//
} // namespace process
} // namespace tim
+289
Просмотреть файл
@@ -0,0 +1,289 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#define _TIM_STRINGIZE(X) _TIM_STRINGIZE2(X)
#define _TIM_STRINGIZE2(X) #X
#define _TIM_VAR_NAME_COMBINE(X, Y) X##Y
#define _TIM_VARIABLE(Y) _TIM_VAR_NAME_COMBINE(timemory_variable_, Y)
#define _TIM_SCOPE_DTOR(Y) _TIM_VAR_NAME_COMBINE(timemory_scoped_dtor_, Y)
#define _TIM_TYPEDEF(Y) _TIM_VAR_NAME_COMBINE(timemory_typedef_, Y)
#define _TIM_STORAGE_INIT(Y) _TIM_VAR_NAME_COMBINE(timemory_storage_initializer_, Y)
#define _TIM_LINESTR _TIM_STRINGIZE(__LINE__)
#if defined(TIMEMORY_PRETTY_FUNCTION) && !defined(_WINDOWS)
# define _TIM_FUNC __PRETTY_FUNCTION__
#elif defined(TIMEMORY_PRETTY_FUNCTION) && defined(_WINDOWS)
# define _TIM_FUNC __FUNCSIG__
#else
# define _TIM_FUNC __FUNCTION__
#endif
#if defined(DISABLE_TIMEMORY) || defined(TIMEMORY_DISABLED)
# if !defined(TIMEMORY_SPRINTF)
# define TIMEMORY_SPRINTF(...)
# endif
#else
# if !defined(TIMEMORY_SPRINTF)
# define TIMEMORY_SPRINTF(VAR, LEN, FMT, ...) \
char VAR[LEN]; \
snprintf(VAR, LEN, FMT, __VA_ARGS__);
# endif
#endif
#if !defined(TIMEMORY_CODE)
# if defined(DISABLE_TIMEMORY) || defined(TIMEMORY_DISABLED)
# define TIMEMORY_CODE(...)
# else
# define TIMEMORY_CODE(...) __VA_ARGS__
# endif
#endif
//======================================================================================//
//
// Operating System
//
//======================================================================================//
#if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64)
# if !defined(_WINDOWS)
# define _WINDOWS 1
# endif
#elif defined(__APPLE__) || defined(__MACH__)
# if !defined(_MACOS)
# define _MACOS 1
# endif
# if !defined(_UNIX)
# define _UNIX 1
# endif
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
# if !defined(_LINUX)
# define _LINUX 1
# endif
# if !defined(_UNIX)
# define _UNIX 1
# endif
#elif defined(__unix__) || defined(__unix) || defined(unix)
# if !defined(_UNIX)
# define _UNIX 1
# endif
#endif
#if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64)
# if !defined(TIMEMORY_WINDOWS)
# define TIMEMORY_WINDOWS 1
# endif
#elif defined(__APPLE__) || defined(__MACH__)
# if !defined(TIMEMORY_MACOS)
# define TIMEMORY_MACOS 1
# endif
# if !defined(TIMEMORY_UNIX)
# define TIMEMORY_UNIX 1
# endif
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
# if !defined(TIMEMORY_LINUX)
# define TIMEMORY_LINUX 1
# endif
# if !defined(TIMEMORY_UNIX)
# define TIMEMORY_UNIX 1
# endif
#elif defined(__unix__) || defined(__unix) || defined(unix)
# if !defined(TIMEMORY_UNIX)
# define TIMEMORY_UNIX 1
# endif
#endif
//======================================================================================//
//
// General attribute
//
//======================================================================================//
#if !defined(TIMEMORY_ATTRIBUTE)
# if !defined(_MSC_VER)
# define TIMEMORY_ATTRIBUTE(attr) __attribute__((attr))
# else
# define TIMEMORY_ATTRIBUTE(attr) __declspec(attr)
# endif
#endif
//======================================================================================//
//
// Windows DLL settings
//
//======================================================================================//
#if !defined(TIMEMORY_CDLL)
# if defined(_WINDOWS)
# if defined(TIMEMORY_CDLL_EXPORT)
# define TIMEMORY_CDLL __declspec(dllexport)
# elif defined(TIMEMORY_CDLL_IMPORT)
# define TIMEMORY_CDLL __declspec(dllimport)
# else
# define TIMEMORY_CDLL
# endif
# else
# define TIMEMORY_CDLL
# endif
#endif
#if !defined(TIMEMORY_DLL)
# if defined(_WINDOWS)
# if defined(TIMEMORY_DLL_EXPORT)
# define TIMEMORY_DLL __declspec(dllexport)
# elif defined(TIMEMORY_DLL_IMPORT)
# define TIMEMORY_DLL __declspec(dllimport)
# else
# define TIMEMORY_DLL
# endif
# else
# define TIMEMORY_DLL
# endif
#endif
//======================================================================================//
//
// Visibility
//
//======================================================================================//
#if !defined(TIMEMORY_VISIBILITY)
# if !defined(_MSC_VER)
# define TIMEMORY_VISIBILITY(mode) TIMEMORY_ATTRIBUTE(visibility(mode))
# else
# define TIMEMORY_VISIBILITY(mode)
# endif
#endif
#if !defined(TIMEMORY_VISIBLE)
# define TIMEMORY_VISIBLE TIMEMORY_VISIBILITY("default")
#endif
#if !defined(TIMEMORY_HIDDEN)
# define TIMEMORY_HIDDEN TIMEMORY_VISIBILITY("hidden")
#endif
//======================================================================================//
//
// Instrumentation
//
//======================================================================================//
#if !defined(_WINDOWS)
# if !defined(TIMEMORY_NEVER_INSTRUMENT)
# if defined(__clang__)
# define TIMEMORY_NEVER_INSTRUMENT \
TIMEMORY_ATTRIBUTE(no_instrument_function) \
TIMEMORY_ATTRIBUTE(xray_never_instrument)
# else
# define TIMEMORY_NEVER_INSTRUMENT TIMEMORY_ATTRIBUTE(no_instrument_function)
# endif
# endif
//
# if !defined(TIMEMORY_INSTRUMENT)
# define TIMEMORY_INSTRUMENT TIMEMORY_ATTRIBUTE(xray_always_instrument)
# endif
#else
# if !defined(TIMEMORY_NEVER_INSTRUMENT)
# define TIMEMORY_NEVER_INSTRUMENT
# endif
//
# if !defined(TIMEMORY_INSTRUMENT)
# define TIMEMORY_INSTRUMENT
# endif
#endif
//======================================================================================//
//
// Symbol override
//
//======================================================================================//
#if !defined(TIMEMORY_WEAK_PREFIX)
# if !defined(_MSC_VER)
# if defined(__clang__) && defined(__APPLE__)
# define TIMEMORY_WEAK_PREFIX
# else
# define TIMEMORY_WEAK_PREFIX TIMEMORY_ATTRIBUTE(weak)
# endif
# else
# define TIMEMORY_WEAK_PREFIX
# endif
#endif
#if !defined(TIMEMORY_WEAK_POSTFIX)
# if !defined(_MSC_VER)
# if defined(__clang__) && defined(__APPLE__)
# define TIMEMORY_WEAK_POSTFIX TIMEMORY_ATTRIBUTE(weak_import)
# else
# define TIMEMORY_WEAK_POSTFIX
# endif
# else
# define TIMEMORY_WEAK_POSTFIX
# endif
#endif
//======================================================================================//
//
// Library Constructor/Destructor
//
//======================================================================================//
#if !defined(TIMEMORY_CTOR)
# if !defined(_WINDOWS)
# define TIMEMORY_CTOR TIMEMORY_ATTRIBUTE(constructor)
# else
# define TIMEMORY_CTOR
# endif
#endif
//
//--------------------------------------------------------------------------------------//
//
#if !defined(TIMEMORY_DTOR)
# if !defined(_WINDOWS)
# define TIMEMORY_DTOR TIMEMORY_ATTRIBUTE(destructor)
# else
# define TIMEMORY_DTOR
# endif
#endif
//======================================================================================//
//
// WINDOWS WARNINGS (apply to C code)
//
//======================================================================================//
// MSVC compiler
#if defined(_MSC_VER) && _MSC_VER > 0 && !defined(TIMEMORY_MSVC_COMPILER)
# define TIMEMORY_MSVC_COMPILER
#endif
#if defined(TIMEMORY_MSVC_COMPILER) && !defined(TIMEMORY_MSVC_WARNINGS)
# pragma warning(disable : 4996) // function may be unsafe
# pragma warning(disable : 5105) // macro produce 'defined' has undefined behavior
#endif
+33
Просмотреть файл
@@ -0,0 +1,33 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/environment/declaration.hpp"
#include "timemory/environment/macros.hpp"
#include "timemory/environment/types.hpp"
#if !defined(TIMEMORY_USE_ENVIRONMENT_EXTERN)
# include "timemory/environment/definition.hpp"
#endif
+268
Просмотреть файл
@@ -0,0 +1,268 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/environment/macros.hpp"
#include "timemory/environment/types.hpp"
#include "timemory/macros/compiler.hpp"
#include "timemory/macros/os.hpp"
#include "timemory/tpls/cereal/cereal.hpp"
#include "timemory/utility/macros.hpp"
#include "timemory/utility/utility.hpp"
#include <cstdlib>
#include <iosfwd>
#include <map>
#include <mutex>
#include <string>
#include <utility>
#include <vector>
namespace tim
{
//
//--------------------------------------------------------------------------------------//
//
// environment
//
//--------------------------------------------------------------------------------------//
//
class env_settings
{
public:
using string_t = std::string;
using env_map_t = std::map<string_t, string_t>;
using env_uomap_t = std::map<string_t, string_t>;
using env_pair_t = std::pair<string_t, string_t>;
using iterator = typename env_map_t::iterator;
using const_iterator = typename env_map_t::const_iterator;
public:
static env_settings* instance();
private:
// if passed a global, insert m_env into it's array
env_settings(env_settings* _global = nullptr, int _id = 0);
// only the zero id deletes
~env_settings();
public:
template <typename Tp>
void insert(const std::string& env_id, Tp val);
env_map_t get() const;
iterator get(const string_t& _entry) { return m_env->find(_entry); }
const_iterator get(const string_t& _entry) const { return m_env->find(_entry); }
iterator begin() { return m_env->begin(); }
iterator end() { return m_env->end(); }
const_iterator begin() const { return m_env->begin(); }
const_iterator end() const { return m_env->end(); }
void print(std::ostream&) const;
friend std::ostream& operator<<(std::ostream& os, const env_settings& env)
{
env.print(os);
return os;
}
//----------------------------------------------------------------------------------//
// serialization
//
template <typename Archive>
void serialize(Archive& ar, unsigned int);
template <typename Archive>
static void serialize_environment(Archive& ar)
{
if(instance())
instance()->serialize(ar, TIMEMORY_GET_CLASS_VERSION(tim::env_settings));
}
private:
static std::atomic_bool& lock_flag()
{
static std::atomic_bool _instance(false);
return _instance;
}
void collapse();
private:
int m_id = 0;
env_uomap_t* m_env = new env_uomap_t{};
std::vector<env_uomap_t*> m_env_other;
};
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp>
void
env_settings::insert(const std::string& env_id, Tp val)
{
#if !defined(TIMEMORY_DISABLE_STORE_ENVIRONMENT)
std::stringstream ss;
ss << std::boolalpha << val;
auto_lock_t lk(type_mutex<env_settings>(), std::defer_lock);
if(lock_flag().load() && !lk.owns_lock())
lk.lock();
if(m_env &&
(m_env->find(env_id) == m_env->end() || m_env->find(env_id)->second != ss.str()))
(*m_env)[env_id] = ss.str();
#else
consume_parameters(env_id, val);
#endif
}
//
//--------------------------------------------------------------------------------------//
//
template <typename Archive>
void
env_settings::serialize(Archive& ar, const unsigned int)
{
auto _tmp = env_uomap_t{};
if(!m_env)
m_env = &_tmp;
collapse();
auto_lock_t lk(type_mutex<env_settings>(), std::defer_lock);
lock_flag().store(true);
if(!lk.owns_lock())
lk.lock();
ar(cereal::make_nvp("environment", *m_env));
if(m_env == &_tmp)
m_env = nullptr;
lock_flag().store(false);
}
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp>
Tp
get_env(const std::string& env_id, Tp _default, bool _store)
{
if(env_id.empty())
return _default;
auto* _env_settings = env_settings::instance();
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string str_var = std::string(env_var);
std::stringstream iss{ str_var };
auto var = Tp{};
iss >> var;
if(_env_settings && _store)
_env_settings->insert<Tp>(env_id, var);
return var;
}
// record default value
if(_env_settings && _store)
_env_settings->insert<Tp>(env_id, _default);
// return default if not specified in environment
return _default;
}
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp>
Tp
get_env_choice(const std::string& env_id, Tp _default, std::set<Tp> _choices)
{
assert(!_choices.empty());
auto _choice = get_env<Tp>(env_id, _default);
// check that the choice is valid
if(_choices.find(_choice) == _choices.end())
{
std::ostringstream _msg{};
_msg << "Error! Invalid value \"" << _choice << "\" for " << env_id
<< ". Valid choices are: ";
std::ostringstream _opts{};
for(const auto& itr : _choices)
_opts << ", \"" << itr << "\"";
_msg << _opts.str().substr(2);
throw std::runtime_error(_msg.str());
}
return _choice;
}
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp>
Tp
load_env(const std::string& env_id, Tp _default)
{
if(env_id.empty())
return _default;
auto* _env_settings = env_settings::instance();
if(!_env_settings)
return _default;
auto itr = _env_settings->get(env_id);
if(itr != _env_settings->end())
{
std::stringstream iss{ itr->second };
auto var = Tp{};
iss >> var;
return var;
}
// return default if not specified in environment
return _default;
}
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp>
void
set_env(const std::string& env_var, const Tp& _val, int override)
{
std::stringstream ss_val;
ss_val << _val;
#if defined(TIMEMORY_MACOS) || (defined(TIMEMORY_LINUX) && (_POSIX_C_SOURCE >= 200112L))
setenv(env_var.c_str(), ss_val.str().c_str(), override);
#elif defined(TIMEMORY_WINDOWS)
auto _curr = get_env<std::string>(env_var, "");
if(_curr.empty() || override > 0)
_putenv_s(env_var.c_str(), ss_val.str().c_str());
#else
consume_parameters(env_var, _val, override, ss_val);
#endif
}
//
//--------------------------------------------------------------------------------------//
//
} // namespace tim
+362
Просмотреть файл
@@ -0,0 +1,362 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
/**
* \file timemory/environment/definition.hpp
* \brief The definitions for the types in environment
*/
#pragma once
#include "timemory/environment/declaration.hpp"
#include "timemory/environment/macros.hpp"
#include "timemory/environment/types.hpp"
#include "timemory/utility/transient_function.hpp"
#include "timemory/utility/utility.hpp"
#include <atomic>
#include <iosfwd>
#include <mutex>
#include <regex>
#include <sstream>
#include <string>
namespace tim
{
//
//--------------------------------------------------------------------------------------//
//
namespace regex_const = std::regex_constants;
//
//--------------------------------------------------------------------------------------//
//
#if !defined(TIMEMORY_USE_ENVIRONMENT_EXTERN)
//
//--------------------------------------------------------------------------------------//
//
// environment
//
//--------------------------------------------------------------------------------------//
//
// if passed a global, insert m_env into it's array
//
TIMEMORY_ENVIRONMENT_LINKAGE(env_settings::env_settings)
(env_settings* _global, int _id)
: m_id(_id)
, m_env(new env_uomap_t)
{
if(_global && _id != 0)
{
auto_lock_t lk(type_mutex<env_settings>(), std::defer_lock);
lock_flag().store(true);
if(!lk.owns_lock())
lk.lock();
_global->m_env_other.emplace_back(m_env);
lock_flag().store(false);
}
}
//
//--------------------------------------------------------------------------------------//
//
// only the zero id deletes
//
TIMEMORY_ENVIRONMENT_LINKAGE(env_settings::~env_settings())
{
if(m_id == 0)
{
delete m_env;
for(auto& itr : m_env_other)
delete itr;
}
}
//
//--------------------------------------------------------------------------------------//
//
TIMEMORY_ENVIRONMENT_LINKAGE(env_settings::env_map_t)
env_settings::get() const
{
auto_lock_t lk(type_mutex<env_settings>(), std::defer_lock);
lock_flag().store(true);
if(!lk.owns_lock())
lk.lock();
auto _tmp = *m_env;
env_map_t _ret;
for(const auto& itr : _tmp)
_ret[itr.first] = itr.second;
lock_flag().store(false);
return _ret;
}
//
//--------------------------------------------------------------------------------------//
//
TIMEMORY_ENVIRONMENT_LINKAGE(void)
env_settings::print(std::ostream& os) const
{
if(m_id == 0)
const_cast<env_settings&>(*this).collapse();
auto _data = get();
size_t _w = 35;
for(const auto& itr : _data)
_w = std::max<size_t>(itr.first.length(), _w);
std::stringstream filler;
filler.fill('-');
filler << '#';
filler << std::setw(88) << "";
filler << '#';
std::stringstream ss;
ss << filler.str() << '\n';
ss << "# Environment settings:\n";
for(const auto& itr : _data)
{
ss << "# " << std::setw(_w) << std::right << itr.first << "\t = \t" << std::left
<< itr.second << '\n';
}
ss << filler.str();
os << ss.str() << '\n';
}
//
//--------------------------------------------------------------------------------------//
//
// NOLINTNEXTLINE
TIMEMORY_ENVIRONMENT_LINKAGE(void)
env_settings::collapse()
{
if(m_id != 0)
return;
auto_lock_t lk(type_mutex<env_settings>(), std::defer_lock);
if(!lk.owns_lock())
lk.lock();
lock_flag().store(true);
// insert all the other maps into this map
for(size_t i = 0; i < m_env_other.size(); ++i)
{
// get the map instance
auto* itr = m_env_other[i];
if(itr)
{
// loop over entries
for(const auto& mitr : *m_env_other[i])
{
auto key = mitr.first;
if(m_env->find(key) != m_env->end())
{
// if the key already exists and if the entries differ,
// create a new unique entry for the index
if(m_env->find(key)->second != mitr.second)
{
key += string_t("[@") + std::to_string(i + 1) + string_t("]");
(*m_env)[key] = mitr.second;
}
}
else
{
// if a new entry, insert without unique tag to avoid duplication
// when thread count is very high
(*m_env)[key] = mitr.second;
}
}
}
}
lock_flag().store(false);
}
//
//--------------------------------------------------------------------------------------//
//
// specialization for string since the above will have issues if string includes spaces
//
template <>
TIMEMORY_ENVIRONMENT_LINKAGE(std::string)
get_env(const std::string& env_id, std::string _default, bool _store)
{
if(env_id.empty())
return _default;
auto* _env_settings = env_settings::instance();
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::stringstream ss;
ss << env_var;
if(_env_settings && _store)
_env_settings->insert(env_id, ss.str());
return ss.str();
}
// record default value
if(_env_settings && _store)
_env_settings->insert(env_id, _default);
// return default if not specified in environment
return _default;
}
//
//--------------------------------------------------------------------------------------//
//
// overload for boolean
//
template <>
TIMEMORY_ENVIRONMENT_LINKAGE(bool)
get_env(const std::string& env_id, bool _default, bool _store)
{
if(env_id.empty())
return _default;
auto* _env_settings = env_settings::instance();
char* env_var = std::getenv(env_id.c_str());
if(env_var)
{
std::string var = std::string(env_var);
bool val = true;
if(var.find_first_not_of("0123456789") == std::string::npos)
{
val = (bool) atoi(var.c_str());
}
else
{
for(auto& itr : var)
itr = tolower(itr);
for(const auto& itr : { "off", "false", "no", "n", "f", "0" })
{
if(var == itr)
{
if(_env_settings && _store)
_env_settings->insert<bool>(env_id, false);
return false;
}
}
}
if(_env_settings && _store)
_env_settings->insert<bool>(env_id, val);
return val;
}
// record default value
if(_env_settings && _store)
_env_settings->insert<bool>(env_id, _default);
// return default if not specified in environment
return _default;
}
//
//--------------------------------------------------------------------------------------//
//
// specialization for string since the above will have issues if string includes spaces
//
template <>
TIMEMORY_ENVIRONMENT_LINKAGE(std::string)
load_env(const std::string& env_id, std::string _default)
{
if(env_id.empty())
return _default;
auto* _env_settings = env_settings::instance();
auto itr = _env_settings->get(env_id);
if(itr != _env_settings->end())
return itr->second;
// return default if not specified in environment
return _default;
}
//
//--------------------------------------------------------------------------------------//
//
// overload for boolean
//
template <>
TIMEMORY_ENVIRONMENT_LINKAGE(bool)
load_env(const std::string& env_id, bool _default)
{
if(env_id.empty())
return _default;
auto* _env_settings = env_settings::instance();
auto itr = _env_settings->get(env_id);
if(itr != _env_settings->end())
{
auto val = itr->second;
const auto regex_constants = regex_const::egrep | regex_const::icase;
const std::string pattern = "^(off|false|no|n|f|0)$";
bool _match = false;
try
{
_match = std::regex_match(val, std::regex(pattern, regex_constants));
} catch(std::bad_cast&)
{
for(auto& vitr : val)
vitr = tolower(vitr);
for(const auto& vitr : { "off", "false", "no", "n", "f", "0" })
{
if(val == vitr)
{
_match = true;
break;
}
}
}
return (_match) ? false : true;
}
// return default if not specified in environment
return _default;
}
//
//--------------------------------------------------------------------------------------//
//
TIMEMORY_ENVIRONMENT_LINKAGE(void)
print_env(std::ostream& os) { os << (*env_settings::instance()); }
//
//--------------------------------------------------------------------------------------//
//
TIMEMORY_ENVIRONMENT_LINKAGE(tim::env_settings*)
env_settings::instance()
{
static std::atomic<int> _count{ 0 };
static env_settings _instance{};
static thread_local int _id = _count++;
static thread_local env_settings* _local =
(_id == 0) ? (&_instance) : new env_settings{ &_instance, _id };
static thread_local auto _ldtor = scope::destructor{ []() {
if(_local == &_instance || _id == 0)
return;
delete _local;
_local = nullptr;
} };
return _local;
(void) _ldtor;
}
//
//--------------------------------------------------------------------------------------//
//
#endif // !defined(TIMEMORY_USE_ENVIRONMENT_EXTERN)
//
//--------------------------------------------------------------------------------------//
//
} // namespace tim
+69
Просмотреть файл
@@ -0,0 +1,69 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/utility/macros.hpp"
#if defined(TIMEMORY_CORE_SOURCE)
# define TIMEMORY_ENVIRONMENT_SOURCE
#elif defined(TIMEMORY_USE_CORE_EXTERN)
# define TIMEMORY_USE_ENVIRONMENT_EXTERN
#endif
//
#if defined(TIMEMORY_USE_EXTERN) && !defined(TIMEMORY_USE_ENVIRONMENT_EXTERN)
# define TIMEMORY_USE_ENVIRONMENT_EXTERN
#endif
#if defined(TIMEMORY_ENVIRONMENT_SOURCE)
# define TIMEMORY_ENVIRONMENT_LINKAGE(...) __VA_ARGS__
#elif defined(TIMEMORY_USE_ENVIRONMENT_EXTERN)
# define TIMEMORY_ENVIRONMENT_LINKAGE(...) extern __VA_ARGS__
#else
# define TIMEMORY_ENVIRONMENT_LINKAGE(...) inline __VA_ARGS__
#endif
//
//--------------------------------------------------------------------------------------//
//
#if !defined(TIMEMORY_ENVIRONMENT_EXTERN_TEMPLATE)
# if defined(TIMEMORY_ENVIRONMENT_SOURCE)
# define TIMEMORY_ENVIRONMENT_EXTERN_TEMPLATE(TYPE) \
namespace tim \
{ \
template TYPE get_env<TYPE>(const std::string&, TYPE); \
template void set_env<TYPE>(const std::string&, const TYPE&, int); \
}
# elif defined(TIMEMORY_USE_ENVIRONMENT_EXTERN)
# define TIMEMORY_ENVIRONMENT_EXTERN_TEMPLATE(TYPE) \
namespace tim \
{ \
extern template TYPE get_env<TYPE>(const std::string&, TYPE); \
extern template void set_env<TYPE>(const std::string&, const TYPE&, int); \
}
# endif
#else
# define TIMEMORY_ENVIRONMENT_EXTERN_TEMPLATE(...)
#endif
//
//======================================================================================//
+103
Просмотреть файл
@@ -0,0 +1,103 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/environment/macros.hpp"
#include "timemory/utility/types.hpp"
#include <iosfwd>
#include <iostream>
#include <set>
#include <string>
namespace tim
{
//
//--------------------------------------------------------------------------------------//
//
// environment
//
//--------------------------------------------------------------------------------------//
//
class env_settings;
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp>
Tp
get_env(const std::string& env_id, Tp _default = Tp{}, bool _store = true);
//
//--------------------------------------------------------------------------------------//
//
template <>
std::string
get_env(const std::string& env_id, std::string _default, bool _store);
//
//--------------------------------------------------------------------------------------//
//
template <>
bool
get_env(const std::string& env_id, bool _default, bool _store);
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp>
Tp
get_env_choice(const std::string& env_id, Tp _default, std::set<Tp> _choices);
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp>
Tp
load_env(const std::string& env_id, Tp _default = Tp{});
//
//--------------------------------------------------------------------------------------//
//
template <>
std::string
load_env(const std::string& env_id, std::string _default);
//
//--------------------------------------------------------------------------------------//
//
template <>
bool
load_env(const std::string& env_id, bool _default);
//
//--------------------------------------------------------------------------------------//
//
void
print_env(std::ostream& os = std::cout);
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp>
void
set_env(const std::string& env_var, const Tp& _val, int override = 0);
//
//--------------------------------------------------------------------------------------//
//
} // namespace tim
TIMEMORY_SET_CLASS_VERSION(0, tim::env_settings)
+366
Просмотреть файл
@@ -0,0 +1,366 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/general/types.hpp"
#include "timemory/hash/declaration.hpp"
#include "timemory/mpl/apply.hpp"
#include <array>
#include <cstring>
#include <ostream>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
namespace tim
{
namespace impl
{
template <typename... Tp>
struct source_location_constant_char;
template <>
struct source_location_constant_char<>
{
static constexpr bool value = true;
};
template <>
struct source_location_constant_char<const char*>
{
static constexpr bool value = true;
};
template <typename Tp>
struct source_location_constant_char<Tp>
{
static constexpr bool value = std::is_same<Tp, const char*>::value;
};
template <typename Tp, typename Up, typename... Tail>
struct source_location_constant_char<Tp, Up, Tail...>
{
static constexpr bool value = source_location_constant_char<Tp>::value &&
source_location_constant_char<Up>::value &&
source_location_constant_char<Tail...>::value;
};
} // namespace impl
/// \class tim::source_location
/// \brief Provides source location information and variadic joining of source location
/// tags
class source_location
{
public:
using join_type = mpl::apply<std::string>;
using result_type = std::tuple<std::string, size_t>;
private:
template <typename... Tp>
static constexpr bool is_constant_char()
{
return impl::source_location_constant_char<decay_t<Tp>...>::value;
}
public:
//
// Public types
//
//==================================================================================//
//
enum class mode : short
{
blank = 0,
basic = 1,
full = 2,
complete = 3
};
//==================================================================================//
//
struct captured
{
public:
const result_type& get() const { return m_result; }
const std::string& get_id() const { return std::get<0>(m_result); }
const hash_value_t& get_hash() const { return std::get<1>(m_result); }
explicit captured(result_type _result)
: m_result(std::move(_result))
{}
TIMEMORY_DEFAULT_OBJECT(captured)
private:
friend class source_location;
result_type m_result = result_type("", 0);
template <typename... ArgsT, enable_if_t<(sizeof...(ArgsT) > 0), int> = 0>
captured& set(const source_location& obj, ArgsT&&... _args)
{
switch(obj.m_mode)
{
case mode::blank:
{
auto&& _tmp = join_type::join("", std::forward<ArgsT>(_args)...);
m_result = result_type(_tmp, add_hash_id(_tmp));
break;
}
case mode::basic:
case mode::full:
case mode::complete:
{
auto&& _suffix = join_type::join("", std::forward<ArgsT>(_args)...);
if(_suffix.empty())
{
m_result = result_type(obj.m_prefix, add_hash_id(obj.m_prefix));
}
else
{
auto _tmp = join_type::join('/', obj.m_prefix.c_str(), _suffix);
m_result = result_type(_tmp, add_hash_id(_tmp));
}
break;
}
}
return *this;
}
template <typename... ArgsT, enable_if_t<sizeof...(ArgsT) == 0, int> = 0>
captured& set(const source_location& obj, ArgsT&&... _args)
{
tim::consume_parameters(std::forward<ArgsT>(_args)...);
m_result = result_type(obj.m_prefix, add_hash_id(obj.m_prefix));
return *this;
}
};
public:
//
// Static functions
//
//==================================================================================//
//
template <typename... ArgsT>
static captured get_captured_inline(const mode& _mode, const char* _func, int _line,
const char* _fname, ArgsT&&... _args)
{
source_location _loc{ _mode, _func, _line, _fname,
std::forward<ArgsT>(_args)... };
return _loc.get_captured(std::forward<ArgsT>(_args)...);
}
public:
//
// Constructors, destructors, etc.
//
//----------------------------------------------------------------------------------//
//
template <typename... ArgsT, enable_if_t<!is_constant_char<ArgsT...>(), int> = 0>
source_location(const mode& _mode, const char* _func, int _line, const char* _fname,
ArgsT&&...)
: m_mode(_mode)
{
switch(m_mode)
{
case mode::blank: break;
case mode::basic: compute_data(_func); break;
case mode::complete:
case mode::full:
compute_data(_func, _line, _fname, m_mode == mode::full);
break;
}
}
//----------------------------------------------------------------------------------//
// if a const char* is passed, assume it is constant
//
template <typename... ArgsT, enable_if_t<is_constant_char<ArgsT...>(), int> = 0>
source_location(const mode& _mode, const char* _func, int _line, const char* _fname,
ArgsT&&... _args)
: m_mode(_mode)
{
auto _arg = join_type::join("", _args...);
switch(m_mode)
{
case mode::blank:
{
// label and hash
auto&& _label = _arg;
auto&& _hash = add_hash_id(_label);
m_captured = captured(result_type{ _label, _hash });
break;
}
case mode::basic:
{
compute_data(_func);
auto&& _label = _join(_arg.c_str());
auto&& _hash = add_hash_id(_label);
m_captured = captured(result_type{ _label, _hash });
break;
}
case mode::full:
case mode::complete:
{
compute_data(_func, _line, _fname, m_mode == mode::full);
// label and hash
auto&& _label = _join(_arg.c_str());
auto&& _hash = add_hash_id(_label);
m_captured = captured(result_type{ _label, _hash });
break;
}
}
}
//----------------------------------------------------------------------------------//
//
source_location() = delete;
~source_location() = default;
source_location(const source_location&) = delete;
source_location(source_location&&) = default;
source_location& operator=(const source_location&) = delete;
source_location& operator=(source_location&&) = default;
protected:
//----------------------------------------------------------------------------------//
//
void compute_data(const char* _func) { m_prefix = _func; }
//----------------------------------------------------------------------------------//
//
void compute_data(const char* _func, int _line, const char* _fname, bool shorten)
{
#if defined(TIMEMORY_WINDOWS)
static const char delim = '\\';
#else
static const char delim = '/';
#endif
std::string _filename(_fname);
if(shorten)
{
if(_filename.find(delim) != std::string::npos)
_filename = _filename.substr(_filename.find_last_of(delim) + 1);
}
if(_line < 0)
{
if(_filename.length() > 0)
{
m_prefix = join_type::join("", _func, '@', _filename);
}
else
{
m_prefix = _func;
}
}
else
{
if(_filename.length() > 0)
{
m_prefix = join_type::join("", _func, '@', _filename, ':', _line);
}
else
{
m_prefix = join_type::join("", _func, ':', _line);
}
}
}
public:
//----------------------------------------------------------------------------------//
//
template <
typename... ArgsT,
enable_if_t<(sizeof...(ArgsT) > 0) && !is_constant_char<ArgsT...>(), int> = 0>
const captured& get_captured(ArgsT&&... _args)
{
return m_captured.set(*this, std::forward<ArgsT>(_args)...);
}
//----------------------------------------------------------------------------------//
//
const captured& get_captured() const { return m_captured; }
//----------------------------------------------------------------------------------//
//
template <
typename... ArgsT,
enable_if_t<(sizeof...(ArgsT) > 0) && is_constant_char<ArgsT...>(), int> = 0>
const captured& get_captured(ArgsT&&...)
{
return m_captured;
}
private:
mode m_mode;
std::string m_prefix = {};
captured m_captured;
private:
std::string _join(const char* _arg)
{
return (strcmp(_arg, "") == 0) ? m_prefix
: join_type::join('/', m_prefix.c_str(), _arg);
}
};
//
namespace internal
{
namespace
{
// anonymous namespace to make sure the static instance is local to each .cpp
// making it static also helps ensure this
template <size_t, size_t, typename... Args>
static inline auto&
get_static_source_location(Args&&... args)
{
static source_location _instance{ std::forward<Args>(args)... };
consume_parameters(std::forward<Args>(args)...);
return _instance;
}
} // namespace
} // namespace internal
//
// static function should be local to each .cpp
//
// LineN should be '__LINE__': this ensures that each use in a source file is unique
// CountN should be '__COUNTER__': this ensures that each source file has unique integer
template <size_t LineN, size_t CountN, typename... Args>
static inline auto&
get_static_source_location(Args&&... args)
{
return internal::get_static_source_location<LineN, CountN>(
std::forward<Args>(args)...);
consume_parameters(std::forward<Args>(args)...);
}
//
} // namespace tim
+68
Просмотреть файл
@@ -0,0 +1,68 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
/** \headerfile "timemory/general/types.hpp"
*/
#pragma once
#include <cstddef>
namespace tim
{
//
//--------------------------------------------------------------------------------------//
//
class source_location;
//
template <size_t, size_t, typename... Args>
static inline auto&
get_static_source_location(Args&&... args);
//
//--------------------------------------------------------------------------------------//
//
} // namespace tim
#if !defined(TIMEMORY_SOURCE_LOCATION)
# define _AUTO_LOCATION_COMBINE(X, Y) X##Y
# define _AUTO_LOCATION(Y) _AUTO_LOCATION_COMBINE(timemory_source_location_, Y)
# define TIMEMORY_SOURCE_LOCATION(MODE, ...) \
::tim::source_location(MODE, __FUNCTION__, __LINE__, __FILE__, __VA_ARGS__)
# define TIMEMORY_CAPTURE_MODE(MODE_TYPE) ::tim::source_location::mode::MODE_TYPE
# define TIMEMORY_CAPTURE_ARGS(...) _AUTO_LOCATION(__LINE__).get_captured(__VA_ARGS__)
# define TIMEMORY_INLINE_SOURCE_LOCATION(MODE, ...) \
::tim::get_static_source_location<__LINE__, __COUNTER__>( \
TIMEMORY_CAPTURE_MODE(MODE), __FUNCTION__, __LINE__, __FILE__, __VA_ARGS__) \
.get_captured(__VA_ARGS__)
# define _TIM_STATIC_SRC_LOCATION(MODE, ...) \
static thread_local auto _AUTO_LOCATION(__LINE__) = \
TIMEMORY_SOURCE_LOCATION(TIMEMORY_CAPTURE_MODE(MODE), __VA_ARGS__)
#endif
+85
Просмотреть файл
@@ -0,0 +1,85 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/hash/macros.hpp"
#include "timemory/hash/types.hpp"
#include "timemory/utility/macros.hpp"
#include <atomic>
#include <memory>
#include <utility>
namespace tim
{
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp, typename Tag, typename PtrT, typename PairT>
PairT&
get_shared_ptr_pair()
{
static auto _master = std::make_shared<Tp>();
static std::atomic<int64_t> _count{ 0 };
static thread_local auto _inst =
PairT{ _master, PtrT{ (_count++ == 0) ? nullptr : new Tp{} } };
return _inst;
}
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp, typename Tag, typename PtrT, typename PairT>
PtrT
get_shared_ptr_pair_instance()
{
static thread_local auto& _pinst = get_shared_ptr_pair<Tp, Tag>();
static thread_local auto& _inst = _pinst.second ? _pinst.second : _pinst.first;
return _inst;
}
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp, typename Tag, typename PtrT, typename PairT>
PtrT
get_shared_ptr_pair_main_instance()
{
static auto& _pinst = get_shared_ptr_pair<Tp, Tag>();
static auto _inst = _pinst.first;
return _inst;
}
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp, typename Tag, typename PtrT>
PtrT
get_shared_ptr_lone_instance()
{
static auto _instance = std::make_shared<Tp>();
return _instance;
}
//
//--------------------------------------------------------------------------------------//
//
} // namespace tim
+43
Просмотреть файл
@@ -0,0 +1,43 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#if defined(TIMEMORY_CORE_SOURCE)
# define TIMEMORY_HASH_SOURCE
#elif defined(TIMEMORY_USE_CORE_EXTERN)
# define TIMEMORY_USE_HASH_EXTERN
#endif
//
#if defined(TIMEMORY_USE_EXTERN) && !defined(TIMEMORY_USE_HASH_EXTERN)
# define TIMEMORY_USE_HASH_EXTERN
#endif
//
#if defined(TIMEMORY_HASH_SOURCE)
# define TIMEMORY_HASH_LINKAGE(...) __VA_ARGS__
#elif defined(TIMEMORY_USE_HASH_EXTERN)
# define TIMEMORY_HASH_LINKAGE(...) extern __VA_ARGS__
#else
# define TIMEMORY_HASH_LINKAGE(...) inline __VA_ARGS__
#endif
+290
Просмотреть файл
@@ -0,0 +1,290 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/api.hpp"
#include "timemory/hash/macros.hpp"
#include "timemory/macros/attributes.hpp"
#include "timemory/macros/language.hpp"
#include "timemory/mpl/concepts.hpp"
#include <functional>
#include <memory>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
namespace tim
{
//
//--------------------------------------------------------------------------------------//
//
// GENERAL PURPOSE TLS DATA
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp, typename Tag = TIMEMORY_API, typename PtrT = std::shared_ptr<Tp>,
typename PairT = std::pair<PtrT, PtrT>>
PairT&
get_shared_ptr_pair();
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp, typename Tag = TIMEMORY_API, typename PtrT = std::shared_ptr<Tp>,
typename PairT = std::pair<PtrT, PtrT>>
PtrT
get_shared_ptr_pair_instance();
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp, typename Tag = TIMEMORY_API, typename PtrT = std::shared_ptr<Tp>,
typename PairT = std::pair<PtrT, PtrT>>
PtrT
get_shared_ptr_pair_main_instance();
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp, typename Tag = TIMEMORY_API, typename PtrT = std::shared_ptr<Tp>>
PtrT
get_shared_ptr_lone_instance();
//
//--------------------------------------------------------------------------------------//
//
// HASH ALIASES
//
//--------------------------------------------------------------------------------------//
//
using hash_value_t = size_t;
using hash_map_t = std::unordered_map<hash_value_t, std::string>;
using hash_alias_map_t = std::unordered_map<hash_value_t, hash_value_t>;
using hash_map_ptr_t = std::shared_ptr<hash_map_t>;
using hash_map_ptr_pair_t = std::pair<hash_map_ptr_t, hash_map_ptr_t>;
using hash_alias_ptr_t = std::shared_ptr<hash_alias_map_t>;
using hash_resolver_t = std::function<bool(hash_value_t, std::string&)>;
using hash_resolver_vec_t = std::vector<hash_resolver_t>;
//
//--------------------------------------------------------------------------------------//
//
// HASH DATA STRUCTURES
//
//--------------------------------------------------------------------------------------//
//
hash_map_ptr_t&
get_hash_ids() TIMEMORY_HOT;
//
//--------------------------------------------------------------------------------------//
//
hash_alias_ptr_t&
get_hash_aliases() TIMEMORY_HOT;
//
//--------------------------------------------------------------------------------------//
//
std::shared_ptr<hash_resolver_vec_t>&
get_hash_resolvers() TIMEMORY_HOT;
//
//--------------------------------------------------------------------------------------//
//
// STRING -> HASH CONVERSION
//
//--------------------------------------------------------------------------------------//
//
// declarations
//
template <typename Tp,
std::enable_if_t<concepts::is_string_type<std::decay_t<Tp>>::value, int> = 0>
TIMEMORY_INLINE hash_value_t
get_hash_id(Tp&& _prefix);
//
template <typename Tp,
std::enable_if_t<!concepts::is_string_type<std::decay_t<Tp>>::value, int> = 0>
TIMEMORY_INLINE hash_value_t
get_hash_id(Tp&& _prefix);
//
TIMEMORY_INLINE hash_value_t
get_combined_hash_id(hash_value_t _lhs, hash_value_t _rhs);
//
template <typename Tp,
std::enable_if_t<!std::is_integral<std::decay_t<Tp>>::value, int> = 0>
TIMEMORY_INLINE hash_value_t
get_combined_hash_id(hash_value_t _lhs, Tp&& _rhs);
//
// get hash of a string type
//
template <typename Tp,
std::enable_if_t<concepts::is_string_type<std::decay_t<Tp>>::value, int>>
hash_value_t
get_hash_id(Tp&& _prefix)
{
return std::hash<string_view_t>{}(std::forward<Tp>(_prefix));
}
//
// get hash of a non-string type
//
template <typename Tp,
std::enable_if_t<!concepts::is_string_type<std::decay_t<Tp>>::value, int>>
hash_value_t
get_hash_id(Tp&& _prefix)
{
return std::hash<std::decay_t<Tp>>{}(std::forward<Tp>(_prefix));
}
//
// combine two existing hashes
//
hash_value_t
get_combined_hash_id(hash_value_t _lhs, hash_value_t _rhs)
{
return (_lhs ^= _rhs + 0x9e3779b9 + (_lhs << 6) + (_lhs >> 2));
}
//
// compute the hash and combine it with an existing hash
//
template <typename Tp, std::enable_if_t<!std::is_integral<std::decay_t<Tp>>::value, int>>
hash_value_t
get_combined_hash_id(hash_value_t _lhs, Tp&& _rhs)
{
return get_combined_hash_id(_lhs, get_hash_id(std::forward<Tp>(_rhs)));
}
//
//--------------------------------------------------------------------------------------//
//
hash_value_t
get_hash_id(const hash_alias_ptr_t& _hash_alias, hash_value_t _hash_id) TIMEMORY_HOT;
//
//--------------------------------------------------------------------------------------//
//
/// \fn hash_value_t add_hash_id(hash_map_ptr_t&, const string_view_t&)
/// \brief add an string to the given hash-map (if it doesn't already exist) and return
/// the hash
///
hash_value_t
add_hash_id(hash_map_ptr_t& _hash_map, const string_view_t& _prefix) TIMEMORY_HOT;
//
inline hash_value_t
add_hash_id(hash_map_ptr_t& _hash_map, const string_view_t& _prefix)
{
hash_value_t _hash_id = get_hash_id(_prefix);
if(_hash_map && _hash_map->find(_hash_id) == _hash_map->end())
{
(*_hash_map)[_hash_id] = std::string{ _prefix };
}
return _hash_id;
}
//
//--------------------------------------------------------------------------------------//
//
/// \fn hash_value_t add_hash_id(const string_view_t&)
/// \brief add an string to the default hash-map (if it doesn't already exist) and return
/// the hash
///
hash_value_t
add_hash_id(const string_view_t& _prefix) TIMEMORY_HOT;
//
inline hash_value_t
add_hash_id(const string_view_t& _prefix)
{
return add_hash_id(get_hash_ids(), _prefix);
}
//
//--------------------------------------------------------------------------------------//
//
void
add_hash_id(const hash_map_ptr_t& _hash_map, const hash_alias_ptr_t& _hash_alias,
hash_value_t _hash_id, hash_value_t _alias_hash_id) TIMEMORY_HOT;
//
//--------------------------------------------------------------------------------------//
//
void
add_hash_id(hash_value_t _hash_id, hash_value_t _alias_hash_id) TIMEMORY_HOT;
//
//--------------------------------------------------------------------------------------//
//
// HASH -> STRING CONVERSION
//
//--------------------------------------------------------------------------------------//
//
/// \fn string_view_t get_hash_identifier_fast(hash_value_t)
/// \brief this does not check other threads or aliases. Only call this function when
/// you know that the hash exists on the thread and is not an alias
//
string_view_t
get_hash_identifier_fast(hash_value_t _hash) TIMEMORY_HOT;
//
inline string_view_t
get_hash_identifier_fast(hash_value_t _hash)
{
auto& _hash_ids = get_hash_ids();
auto itr = _hash_ids->find(_hash);
if(itr != _hash_ids->end())
return itr->second;
return "";
}
//
//--------------------------------------------------------------------------------------//
//
std::string
get_hash_identifier(const hash_map_ptr_t& _hash_map, const hash_alias_ptr_t& _hash_alias,
hash_value_t _hash_id);
//
//--------------------------------------------------------------------------------------//
//
std::string
get_hash_identifier(hash_value_t _hash_id);
//
//--------------------------------------------------------------------------------------//
//
template <typename FuncT>
size_t
add_hash_resolver(FuncT&& _func)
{
auto _resolvers = get_hash_resolvers();
if(!_resolvers)
return 0;
_resolvers->emplace_back(std::forward<FuncT>(_func));
return _resolvers->size();
}
//
//--------------------------------------------------------------------------------------//
//
// HASH STRING DEMANGLING
//
//--------------------------------------------------------------------------------------//
//
std::string
demangle_hash_identifier(std::string, char bdelim = '[', char edelim = ']');
//
//--------------------------------------------------------------------------------------//
//
template <typename... Args>
auto
get_demangled_hash_identifier(Args&&... _args)
{
return demangle_hash_identifier(get_hash_identifier(std::forward<Args>(_args)...));
}
//
//--------------------------------------------------------------------------------------//
//
} // namespace tim
+193
Просмотреть файл
@@ -0,0 +1,193 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/macros/compiler.hpp"
#include "timemory/macros/language.hpp"
#include "timemory/macros/os.hpp"
//======================================================================================//
//
#if !defined(TIMEMORY_ATTRIBUTE)
# if defined(TIMEMORY_MSVC_COMPILER)
# define TIMEMORY_ATTRIBUTE(...) __declspec(__VA_ARGS__)
# else
# define TIMEMORY_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
# endif
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_ALWAYS_INLINE)
# if defined(TIMEMORY_MSVC_COMPILER)
# define TIMEMORY_ALWAYS_INLINE __forceinline
# else
# define TIMEMORY_ALWAYS_INLINE TIMEMORY_ATTRIBUTE(always_inline) inline
# endif
#endif
#if !defined(TIMEMORY_INLINE)
# define TIMEMORY_INLINE TIMEMORY_ALWAYS_INLINE
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_NODISCARD)
# if defined(CXX17)
# define TIMEMORY_NODISCARD [[nodiscard]]
# else
# define TIMEMORY_NODISCARD
# endif
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_FLATTEN)
# if !defined(TIMEMORY_MSVC_COMPILER)
# define TIMEMORY_FLATTEN [[gnu::flatten]]
# else
# define TIMEMORY_FLATTEN
# endif
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_HOT)
# if !defined(TIMEMORY_MSVC_COMPILER)
# define TIMEMORY_HOT TIMEMORY_ATTRIBUTE(hot)
# else
# define TIMEMORY_HOT
# endif
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_COLD)
# if !defined(TIMEMORY_MSVC_COMPILER)
# define TIMEMORY_COLD TIMEMORY_ATTRIBUTE(cold)
# else
# define TIMEMORY_COLD
# endif
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_CONST)
# define TIMEMORY_CONST [[gnu::const]]
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_DEPRECATED)
# define TIMEMORY_DEPRECATED(...) [[gnu::deprecated(__VA_ARGS__)]]
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_EXTERN_VISIBLE)
# define TIMEMORY_EXTERN_VISIBLE [[gnu::externally_visible]]
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_HIDDEN)
# if !defined(TIMEMORY_MSVC_COMPILER)
# define TIMEMORY_HIDDEN TIMEMORY_ATTRIBUTE(visibility("hidden"))
# else
# define TIMEMORY_HIDDEN
# endif
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_ALIAS)
# define TIMEMORY_ALIAS(...) [[gnu::alias(__VA_ARGS__)]]
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_NOINLINE)
# define TIMEMORY_NOINLINE TIMEMORY_ATTRIBUTE(noinline)
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_NOCLONE)
# if defined(TIMEMORY_GNU_COMPILER)
# define TIMEMORY_NOCLONE TIMEMORY_ATTRIBUTE(noclone)
# else
# define TIMEMORY_NOCLONE
# endif
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_HOT_INLINE)
# define TIMEMORY_HOT_INLINE TIMEMORY_HOT TIMEMORY_INLINE
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_DATA_ALIGNMENT)
# define TIMEMORY_DATA_ALIGNMENT 8
#endif
#if !defined(TIMEMORY_PACKED_ALIGNMENT)
# if defined(_WIN32) // Windows 32- and 64-bit
# define TIMEMORY_PACKED_ALIGNMENT __declspec(align(TIMEMORY_DATA_ALIGNMENT))
# elif defined(__GNUC__) // GCC
# define TIMEMORY_PACKED_ALIGNMENT \
__attribute__((__packed__)) __attribute__((aligned(TIMEMORY_DATA_ALIGNMENT)))
# else // all other compilers
# define TIMEMORY_PACKED_ALIGNMENT
# endif
#endif
//======================================================================================//
// device decorators
//
#if defined(__CUDACC__) || defined(__HIPCC__)
# define TIMEMORY_LAMBDA __host__ __device__
# define TIMEMORY_HOST_LAMBDA __host__
# define TIMEMORY_HOST_FUNCTION __host__
# define TIMEMORY_DEVICE_LAMBDA __device__
# define TIMEMORY_DEVICE_FUNCTION __device__
# define TIMEMORY_GLOBAL_FUNCTION __global__
# define TIMEMORY_HOST_DEVICE_FUNCTION __host__ __device__
# define TIMEMORY_DEVICE_INLINE __device__ __inline__
# define TIMEMORY_GLOBAL_INLINE __global__ __inline__
# define TIMEMORY_HOST_DEVICE_INLINE __host__ __device__ __inline__
#else
# define TIMEMORY_LAMBDA
# define TIMEMORY_HOST_LAMBDA
# define TIMEMORY_HOST_FUNCTION
# define TIMEMORY_DEVICE_LAMBDA
# define TIMEMORY_DEVICE_FUNCTION
# define TIMEMORY_GLOBAL_FUNCTION
# define TIMEMORY_HOST_DEVICE_FUNCTION
# define TIMEMORY_DEVICE_INLINE inline
# define TIMEMORY_GLOBAL_INLINE inline
# define TIMEMORY_HOST_DEVICE_INLINE inline
#endif
+205
Просмотреть файл
@@ -0,0 +1,205 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/macros/os.hpp"
//======================================================================================//
//
// Compiler
//
//======================================================================================//
// clang compiler
#if defined(__clang__) && !defined(TIMEMORY_CLANG_COMPILER)
# define TIMEMORY_CLANG_COMPILER 1
#endif
//--------------------------------------------------------------------------------------//
// GNU compiler
#if defined(__GNUC__) && !defined(TIMEMORY_CLANG_COMPILER) && \
!defined(TIMEMORY_GNU_COMPILER)
# if(__GNUC__ <= 4 && __GNUC_MINOR__ < 9)
# warning "GCC compilers < 4.9 have been known to have compiler errors"
# define TIMEMORY_GNU_COMPILER 1
# elif(__GNUC__ >= 4 && __GNUC_MINOR__ >= 9) || __GNUC__ >= 5
# define TIMEMORY_GNU_COMPILER
# endif
#endif
//--------------------------------------------------------------------------------------//
// Intel compiler
#if defined(__INTEL_COMPILER) && !defined(TIMEMORY_INTEL_COMPILER)
# define TIMEMORY_INTEL_COMPILER 1
# if __INTEL_COMPILER < 1500
# warning "Intel compilers < 1500 have been known to have compiler errors"
# endif
#endif
//--------------------------------------------------------------------------------------//
// nvcc compiler
#if defined(__NVCC__) && !defined(TIMEMORY_NVCC_COMPILER)
# define TIMEMORY_NVCC_COMPILER 1
#endif
//--------------------------------------------------------------------------------------//
// cuda compilation mode
#if defined(__CUDACC__) && !defined(TIMEMORY_CUDACC)
# define TIMEMORY_CUDACC 1
#endif
//--------------------------------------------------------------------------------------//
// hcc or hip-clang compiler
#if(defined(__HCC__) || (defined(__clang__) && defined(__HIP__))) && \
!defined(TIMEMORY_HIP_COMPILER)
# define TIMEMORY_HIP_COMPILER 1
#endif
//--------------------------------------------------------------------------------------//
// hip compilation mode
#if defined(__HIPCC__) && !defined(TIMEMORY_HIPCC)
# define TIMEMORY_HIPCC 1
#endif
//--------------------------------------------------------------------------------------//
// gpu compilation mode (may be host or device code)
#if(defined(__CUDACC__) || defined(__HIPCC__)) && !defined(TIMEMORY_GPUCC)
# define TIMEMORY_GPUCC 1
#endif
//--------------------------------------------------------------------------------------//
// cuda compilation - device code
#if defined(__CUDA_ARCH__) && !defined(TIMEMORY_CUDA_DEVICE_COMPILE)
# define TIMEMORY_CUDA_DEVICE_COMPILE 1
#endif
//--------------------------------------------------------------------------------------//
// hip compilation - device code
#if defined(__HIP_DEVICE_COMPILE__) && !defined(TIMEMORY_HIP_DEVICE_COMPILE)
# define TIMEMORY_HIP_DEVICE_COMPILE 1
#endif
//--------------------------------------------------------------------------------------//
// gpu compiler - device code
#if(defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__)) && \
!defined(TIMEMORY_GPU_DEVICE_COMPILE)
# define TIMEMORY_GPU_DEVICE_COMPILE 1
#endif
//--------------------------------------------------------------------------------------//
// assume openmp target is enabled
// #if defined(TIMEMORY_CUDACC) && defined(_OPENMP) && !defined(TIMEMORY_OPENMP_TARGET)
// # define TIMEMORY_OPENMP_TARGET 1
// #endif
//--------------------------------------------------------------------------------------//
// MSVC compiler
#if defined(_MSC_VER) && _MSC_VER > 0 && !defined(TIMEMORY_MSVC_COMPILER)
# define TIMEMORY_MSVC_COMPILER 1
#endif
//======================================================================================//
//
// Demangling
//
//======================================================================================//
#if(defined(TIMEMORY_GNU_COMPILER) || defined(TIMEMORY_CLANG_COMPILER) || \
defined(TIMEMORY_INTEL_COMPILER) || defined(TIMEMORY_NVCC_COMPILER) || \
defined(TIMEMORY_HIP_COMPILER)) && \
defined(TIMEMORY_UNIX)
# if !defined(TIMEMORY_ENABLE_DEMANGLE)
# define TIMEMORY_ENABLE_DEMANGLE 1
# endif
#endif
//======================================================================================//
//
// WINDOWS WARNINGS
//
//======================================================================================//
#if defined(TIMEMORY_MSVC_COMPILER) && !defined(TIMEMORY_MSVC_WARNINGS)
# pragma warning(disable : 4003) // not enough actual params
# pragma warning(disable : 4061) // enum in switch of enum not explicitly handled
# pragma warning(disable : 4068) // unknown pragma
# pragma warning(disable : 4127) // conditional expr is constant
# pragma warning(disable : 4129) // unrecognized char escape
# pragma warning(disable : 4146) // unsigned
# pragma warning(disable : 4217) // locally defined symbol
# pragma warning(disable : 4244) // possible loss of data
# pragma warning(disable : 4251) // needs to have dll-interface to be used
# pragma warning(disable : 4242) // possible loss of data (assignment)
# pragma warning(disable : 4244) // conversion from 'double' to 'LONGLONG'
# pragma warning(disable : 4245) // signed/unsigned mismatch (init conversion)
# pragma warning(disable : 4267) // possible loss of data (implicit conversion)
# pragma warning(disable : 4305) // truncation from 'double' to 'float'
# pragma warning(disable : 4355) // this used in base member init list
# pragma warning(disable : 4365) // signed/unsigned mismatch
# pragma warning(disable : 4464) // relative include path contains '..'
# pragma warning(disable : 4522) // multiple assignment operators specified
# pragma warning(disable : 4625) // copy ctor implicitly defined as deleted
# pragma warning(disable : 4626) // copy assign implicitly defined as deleted
# pragma warning(disable : 4661) // no suitable definition for template inst
# pragma warning(disable : 4700) // uninitialized local variable used
# pragma warning(disable : 4710) // function not inlined
# pragma warning(disable : 4711) // function selected for auto inline expansion
# pragma warning(disable : 4786) // ID truncated to '255' char in debug info
# pragma warning(disable : 4820) // bytes padded after data member
# pragma warning(disable : 4834) // discarding return value with 'nodiscard'
# pragma warning(disable : 4996) // function may be unsafe
# pragma warning(disable : 5219) // implicit conversion; possible loss of data
# pragma warning(disable : 5026) // move ctor implicitly defined as deleted
# pragma warning(disable : 5027) // move assign implicitly defined as deleted
# pragma warning(disable : 26495) // Always initialize member variable
#endif
//======================================================================================//
//
// DISABLE WINDOWS MIN/MAX macros
//
//======================================================================================//
#if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64)
# if !defined(NOMINMAX)
# define NOMINMAX
# endif
#endif
+105
Просмотреть файл
@@ -0,0 +1,105 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
//======================================================================================//
//
// LANGUAGE
//
//======================================================================================//
// Define C++20
#if !defined(CXX20)
# if __cplusplus > 201703L // C++20
# define CXX20
# endif
#endif
//--------------------------------------------------------------------------------------//
// Define C++17
#if !defined(CXX17)
# if __cplusplus > 201402L // C++17
# define CXX17
# endif
#endif
//--------------------------------------------------------------------------------------//
// Define C++14
#if !defined(CXX14)
# if __cplusplus > 201103L // C++14
# define CXX14
# endif
#endif
//--------------------------------------------------------------------------------------//
#if !defined(CXX14)
# if !defined(TIMEMORY_WINDOWS)
# error "timemory requires __cplusplus > 201103L (C++14)"
# endif
#endif
//--------------------------------------------------------------------------------------//
#if !defined(IF_CONSTEXPR)
# if defined(CXX17)
# define IF_CONSTEXPR(...) if constexpr(__VA_ARGS__)
# else
# define IF_CONSTEXPR(...) if(__VA_ARGS__)
# endif
#endif
//--------------------------------------------------------------------------------------//
#if defined(CXX17)
# include <string_view>
//
# if !defined(TIMEMORY_STRING_VIEW)
# define TIMEMORY_STRING_VIEW 1
# endif
//
namespace tim
{
using string_view_t = std::string_view;
}
//
#else
//
# include <string>
//
# if !defined(TIMEMORY_STRING_VIEW)
# define TIMEMORY_STRING_VIEW 0
# endif
//
namespace tim
{
using string_view_t = std::string;
}
//
#endif
//--------------------------------------------------------------------------------------//
+118
Просмотреть файл
@@ -0,0 +1,118 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
//======================================================================================//
//
// Operating System
//
//======================================================================================//
#if defined(__x86_64__)
# if !defined(TIMEMORY_64BIT)
# define TIMEMORY_64BIT 1
# endif
#else
# if !defined(TIMEMORY_32BIT)
# define TIMEMORY_32BIT 1
# endif
#endif
//--------------------------------------------------------------------------------------//
// timemory prefixed os preprocessor definitions
//
#if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64)
# if !defined(TIMEMORY_WINDOWS)
# define TIMEMORY_WINDOWS 1
# endif
#elif defined(__APPLE__) || defined(__MACH__)
# if !defined(TIMEMORY_MACOS)
# define TIMEMORY_MACOS 1
# endif
# if !defined(TIMEMORY_UNIX)
# define TIMEMORY_UNIX 1
# endif
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
# if !defined(TIMEMORY_LINUX)
# define TIMEMORY_LINUX 1
# endif
# if !defined(TIMEMORY_UNIX)
# define TIMEMORY_UNIX 1
# endif
#elif defined(__unix__) || defined(__unix) || defined(unix)
# if !defined(TIMEMORY_UNIX)
# define TIMEMORY_UNIX 1
# endif
#endif
//--------------------------------------------------------------------------------------//
// non-timemory prefixed os preprocessor definitions (deprecated)
//
#if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64)
# if !defined(_WINDOWS)
# define _WINDOWS 1
# endif
#elif defined(__APPLE__) || defined(__MACH__)
# if !defined(_MACOS)
# define _MACOS 1
# endif
# if !defined(_UNIX)
# define _UNIX 1
# endif
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
# if !defined(_LINUX)
# define _LINUX 1
# endif
# if !defined(_UNIX)
# define _UNIX 1
# endif
#elif defined(__unix__) || defined(__unix) || defined(unix)
# if !defined(_UNIX)
# define _UNIX 1
# endif
#endif
//--------------------------------------------------------------------------------------//
// this ensures that winnt.h never causes a 64-bit build to fail
// also solves issue with ws2def.h and winsock2.h:
// https://www.zachburlingame.com/2011/05/
// resolving-redefinition-errors-betwen-ws2def-h-and-winsock-h/
#if defined(_WINDOWS)
# if !defined(NOMINMAX)
# define NOMINMAX
# endif
# if !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# endif
# if !defined(WIN32)
# define WIN32
# endif
# if defined(TIMEMORY_USE_WINSOCK)
# include <WinSock2.h>
# endif
# include <Windows.h>
#endif
//--------------------------------------------------------------------------------------//
+684
Просмотреть файл
@@ -0,0 +1,684 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/macros/attributes.hpp"
#include "timemory/mpl/math.hpp"
#include "timemory/mpl/stl.hpp"
#include <functional>
#include <initializer_list>
#include <iomanip>
#include <sstream>
#include <string>
#include <tuple>
#include <type_traits>
//======================================================================================//
namespace tim
{
// clang-format off
namespace device { struct cpu; struct gpu; } // namespace device
// clang-format on
namespace internal
{
template <typename Ret>
struct apply
{
//----------------------------------------------------------------------------------//
// invoke a function with a tuple
//
template <typename Fn, typename Tuple, size_t... Idx>
static TIMEMORY_HOT_INLINE Ret invoke(Fn&& __f, Tuple&& __t, index_sequence<Idx...>)
{
return __f(std::get<Idx>(std::forward<Tuple>(__t))...);
}
//----------------------------------------------------------------------------------//
// prefix with _sep
//
template <typename SepT, typename Arg,
enable_if_t<std::is_same<Ret, std::string>::value, char> = 0>
static TIMEMORY_HOT_INLINE Ret join_tail(std::stringstream& _ss, const SepT& _sep,
Arg&& _arg)
{
_ss << _sep << std::forward<Arg>(_arg);
return _ss.str();
}
//----------------------------------------------------------------------------------//
// prefix with _sep
//
template <typename SepT, typename Arg, typename... Args,
enable_if_t<std::is_same<Ret, std::string>::value, char> = 0>
static TIMEMORY_HOT_INLINE Ret join_tail(std::stringstream& _ss, const SepT& _sep,
Arg&& _arg, Args&&... __args)
{
_ss << _sep << std::forward<Arg>(_arg);
return join_tail<SepT, Args...>(_ss, _sep, std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
// don't prefix
//
template <typename SepT, typename Arg,
enable_if_t<std::is_same<Ret, std::string>::value, char> = 0>
static TIMEMORY_HOT_INLINE Ret join(std::stringstream& _ss, const SepT&, Arg&& _arg)
{
_ss << std::forward<Arg>(_arg);
return _ss.str();
}
//----------------------------------------------------------------------------------//
// don't prefix
//
template <typename SepT, typename Arg, typename... Args,
enable_if_t<std::is_same<Ret, std::string>::value, char> = 0,
enable_if_t<(sizeof...(Args) > 0), int> = 0>
static TIMEMORY_HOT_INLINE Ret join(std::stringstream& _ss, const SepT& _sep,
Arg&& _arg, Args&&... __args)
{
_ss << std::forward<Arg>(_arg);
return join_tail<SepT, Args...>(_ss, _sep, std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
};
//======================================================================================//
template <>
struct apply<void>
{
using Ret = void;
//----------------------------------------------------------------------------------//
template <typename Tp, typename Tail>
struct get_index_of;
template <typename Tp, typename... Tail>
struct get_index_of<Tp, std::tuple<Tp, Tail...>>
{
static constexpr int value = 0;
};
template <typename Tp, typename... Tail>
struct get_index_of<Tp, std::tuple<Tp*, Tail...>>
{
static constexpr int value = 0;
};
template <typename Tp, typename... Tail>
struct get_index_of<Tp, std::tuple<Tp&, Tail...>>
{
static constexpr int value = 0;
};
template <typename Tp, typename Head, typename... Tail>
struct get_index_of<Tp, std::tuple<Head, Tail...>>
{
static constexpr int value = 1 + get_index_of<Tp, std::tuple<Tail...>>::value;
};
template <typename Tp, typename... Tail>
struct get_index_of<Tp, std::tuple<Tail...>>
{
static_assert(sizeof...(Tail) != 0, "Error! Type not found!");
};
//----------------------------------------------------------------------------------//
// invoke a function with a tuple
//
template <typename Fn, typename Tuple, size_t... Idx>
static TIMEMORY_HOT_INLINE Ret invoke(Fn&& __f, Tuple&& __t, index_sequence<Idx...>)
{
__f(std::get<Idx>(std::forward<Tuple>(__t))...);
}
//----------------------------------------------------------------------------------//
// temporary construction
//
template <typename Type, typename... Args>
static TIMEMORY_HOT_INLINE void construct(Args&&... _args)
{
Type(std::forward<Args>(_args)...);
}
//----------------------------------------------------------------------------------//
// temporary construction
//
template <typename Type, typename... Args, size_t... Idx>
static TIMEMORY_HOT_INLINE void construct_tuple(std::tuple<Args...>&& _args,
index_sequence<Idx>...)
{
construct<Type>(std::get<Idx>(_args)...);
}
//----------------------------------------------------------------------------------//
template <template <typename> class Access, typename Tuple, typename... Args,
size_t... Idx>
static TIMEMORY_HOT_INLINE void unroll_access(Tuple&& __t, index_sequence<Idx...>,
Args&&... __args)
{
TIMEMORY_FOLD_EXPRESSION(Access<decay_t<decltype(std::get<Idx>(__t))>>(
std::forward<decltype(std::get<Idx>(__t))>(std::get<Idx>(__t)),
std::forward<Args>(__args)...));
}
//----------------------------------------------------------------------------------//
template <typename Access, typename Tuple, typename... Args, size_t... Idx>
static TIMEMORY_HOT_INLINE void variadic_1d(Tuple&& __t, Args&&... _args,
index_sequence<Idx...>)
{
TIMEMORY_FOLD_EXPRESSION(
construct<typename std::tuple_element<Idx, Access>::type>(
std::get<Idx>(__t), std::forward<Args>(_args)...));
}
//----------------------------------------------------------------------------------//
template <typename Access, typename TupleA, typename TupleB, typename... Args,
size_t... Idx>
static TIMEMORY_HOT_INLINE void variadic_2d(TupleA&& __a, TupleB&& __b,
Args&&... _args, index_sequence<Idx...>)
{
TIMEMORY_FOLD_EXPRESSION(
construct<typename std::tuple_element<Idx, Access>::type>(
std::get<Idx>(__a), std::get<Idx>(__b), std::forward<Args>(_args)...));
}
//----------------------------------------------------------------------------------//
template <template <typename> class Access, typename Tuple, typename... Args,
size_t... Idx>
static TIMEMORY_HOT_INLINE void type_access(index_sequence<Idx...>, Args&&... __args)
{
TIMEMORY_FOLD_EXPRESSION(
Access<decay_t<typename std::tuple_element<Idx, Tuple>::type>>(
std::forward<Args>(__args)...));
}
//----------------------------------------------------------------------------------//
template <typename Access, typename Tuple, typename... Args, size_t... Idx>
static TIMEMORY_HOT_INLINE void apply_access_with_indices(Tuple&& __t,
index_sequence<Idx...>,
Args&&... __args)
{
// call constructor
TIMEMORY_FOLD_EXPRESSION(decay_t<typename std::tuple_element<Idx, Access>::type>(
Idx, sizeof...(Idx),
std::forward<decltype(std::get<Idx>(__t))>(std::get<Idx>(__t)),
std::forward<Args>(__args)...));
}
//----------------------------------------------------------------------------------//
template <typename Access, typename TupleA, typename TupleB, typename... Args,
size_t... Idx>
static TIMEMORY_HOT_INLINE void apply_access2(TupleA&& __ta, TupleB&& __tb,
index_sequence<Idx...>,
Args&&... __args)
{
// call constructor
TIMEMORY_FOLD_EXPRESSION(decay_t<typename std::tuple_element<Idx, Access>::type>(
std::forward<decltype(std::get<Idx>(__ta))>(std::get<Idx>(__ta)),
std::forward<decltype(std::get<Idx>(__tb))>(std::get<Idx>(__tb)),
std::forward<Args>(__args)...));
}
//----------------------------------------------------------------------------------//
// unroll
template <size_t N, typename Device, typename Func, typename... Args,
typename std::enable_if<
(N == 1 && std::is_same<Device, device::gpu>::value), char>::type = 0>
TIMEMORY_LAMBDA static void unroll(Func&& __func, Args&&... __args)
{
std::forward<Func>(__func)(std::forward<Args>(__args)...);
}
template <size_t N, typename Device, typename Func, typename... Args,
typename std::enable_if<(N > 1 && std::is_same<Device, device::gpu>::value),
char>::type = 0>
TIMEMORY_LAMBDA static void unroll(Func&& __func, Args&&... __args)
{
std::forward<Func>(__func)(std::forward<Args>(__args)...);
unroll<N - 1, Device, Func, Args...>(std::forward<Func>(__func),
std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
// unroll
template <size_t N, typename Device, typename Func, typename... Args,
typename std::enable_if<
(N == 1 && std::is_same<Device, device::cpu>::value), int>::type = 0>
static TIMEMORY_HOT_INLINE void unroll(Func&& __func, Args&&... __args)
{
std::forward<Func>(__func)(std::forward<Args>(__args)...);
}
template <size_t N, typename Device, typename Func, typename... Args,
typename std::enable_if<(N > 1 && std::is_same<Device, device::cpu>::value),
int>::type = 0>
static TIMEMORY_HOT_INLINE void unroll(Func&& __func, Args&&... __args)
{
std::forward<Func>(__func)(std::forward<Args>(__args)...);
unroll<N - 1, Device, Func, Args...>(std::forward<Func>(__func),
std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
};
//======================================================================================//
} // namespace internal
//======================================================================================//
//
// Declaration
//
//======================================================================================//
namespace mpl
{
template <typename Ret>
struct apply;
//======================================================================================//
//
// apply --> std::string
//
//======================================================================================//
template <>
struct apply<std::string>
{
using Ret = std::string;
using string_t = std::string;
using string_tuple_t = std::tuple<std::string>;
//----------------------------------------------------------------------------------//
// Helper
//----------------------------------------------------------------------------------//
template <typename Tp, bool _Val = true, typename Up = int,
typename Dt = typename std::remove_const<decay_t<Tp>>::type>
using if_string_t = enable_if_t<std::is_same<Dt, char*>::value == _Val, Up>;
//----------------------------------------------------------------------------------//
template <typename SepT, typename... Args, typename ReturnT = Ret,
size_t N = sizeof...(Args), enable_if_t<(N > 0), char> = 0>
static TIMEMORY_HOT_INLINE ReturnT join(SepT&& separator, Args&&... __args) noexcept
{
std::stringstream ss;
ss << std::boolalpha;
return internal::apply<Ret>::template join<SepT, Args...>(
std::ref(ss), std::forward<SepT>(separator), std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
template <typename SepT, typename Arg, if_string_t<Arg, true> = 0>
static TIMEMORY_HOT_INLINE Ret join(SepT&&, Arg&& _arg) noexcept
{
return std::forward<Arg>(_arg);
}
//----------------------------------------------------------------------------------//
template <typename SepT, typename Arg, if_string_t<Arg, false> = 0>
static TIMEMORY_HOT_INLINE Ret join(SepT&&, Arg&& _arg) noexcept
{
std::stringstream ss;
ss << _arg;
return ss.str();
}
//----------------------------------------------------------------------------------//
static TIMEMORY_HOT_INLINE Ret join(const string_t&) noexcept { return Ret{}; }
static TIMEMORY_HOT_INLINE Ret join(const char) noexcept { return Ret{}; }
//----------------------------------------------------------------------------------//
};
//======================================================================================//
//
// apply --> generic
//
//======================================================================================//
template <typename Ret>
struct apply
{
using string_t = std::string;
//----------------------------------------------------------------------------------//
// invoke a function
//
template <typename Fn, typename... Args, size_t N = sizeof...(Args)>
static TIMEMORY_HOT_INLINE Ret invoke(Fn&& __f, Args&&... __args) noexcept
{
return __f(std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
// invoke a function with a tuple
//
template <typename Fn, template <typename...> class Tuple, typename... Args,
size_t N = sizeof...(Args)>
static TIMEMORY_HOT_INLINE Ret invoke(Fn&& __f, Tuple<Args...>&& __t) noexcept
{
using Tuple_t = Tuple<Args...>;
return internal::apply<Ret>::template invoke<Fn, Tuple_t>(
std::forward<Fn>(__f), std::forward<Tuple_t>(__t), make_index_sequence<N>{});
}
//----------------------------------------------------------------------------------//
template <typename SepT, typename Tuple, size_t... Idx>
static TIMEMORY_HOT_INLINE string_t join(SepT&& separator, Tuple&& __tup,
index_sequence<Idx...>) noexcept
{
return apply<string_t>::join(separator, std::get<Idx>(__tup)...);
}
};
//======================================================================================//
//
// apply --> std::tuple<std::string>
//
//======================================================================================//
template <>
struct apply<std::tuple<std::string>>
{
using string_t = std::string;
using Ret = string_t;
using apply_v = apply<string_t>;
//----------------------------------------------------------------------------------//
// implementation for label + entry join
//
struct impl
{
template <typename LabelSep, typename EntrySep, typename LabelTup,
typename EntryTup, size_t... Idx>
static Ret join(LabelSep&& _label_sep, EntrySep&& _entry_sep,
LabelTup&& _label_tup, EntryTup&& _entry_tup,
index_sequence<Idx...>) noexcept
{
return apply_v::join(std::forward<LabelSep>(_label_sep),
apply_v::join(std::forward<EntrySep>(_entry_sep),
std::get<Idx>(_label_tup),
std::get<Idx>(_entry_tup))...);
}
};
//----------------------------------------------------------------------------------//
// join a tuple of labels with entries
//
template <typename LabelSep, typename EntrySep, typename LabelTup, typename EntryTup,
size_t N = std::tuple_size<decay_t<LabelTup>>::value,
enable_if_t<(N > 0), int> = 0>
static TIMEMORY_HOT_INLINE Ret join(LabelSep&& _label_sep, EntrySep&& _entry_sep,
LabelTup&& _label_tup,
EntryTup&& _entry_tup) noexcept
{
// clang-format off
return impl::join(std::forward<LabelSep>(_label_sep),
std::forward<EntrySep>(_entry_sep),
std::forward<LabelTup>(_label_tup),
std::forward<EntryTup>(_entry_tup),
make_index_sequence<N>{});
// clang-format on
}
//----------------------------------------------------------------------------------//
// join a tuple of labels with entries
//
template <typename LabelSep, typename EntrySep, typename LabelTup, typename EntryTup,
size_t N = std::tuple_size<decay_t<LabelTup>>::value,
enable_if_t<N == 0, int> = 0>
static TIMEMORY_HOT_INLINE Ret join(LabelSep&&, EntrySep&&, LabelTup&&,
EntryTup&&) noexcept
{
return "";
}
//----------------------------------------------------------------------------------//
};
//======================================================================================//
//
// apply --> void
//
//======================================================================================//
template <>
struct apply<void>
{
using Ret = void;
//----------------------------------------------------------------------------------//
template <size_t I, typename A>
using Access_t = typename std::tuple_element<I, A>::type;
//----------------------------------------------------------------------------------//
// invoke a function
//
template <typename Fn, typename... Args, size_t N = sizeof...(Args)>
static TIMEMORY_HOT_INLINE Ret invoke(Fn&& __f, Args&&... __args) noexcept
{
__f(std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
// invoke a function with a tuple
//
template <typename Fn, template <typename...> class Tuple, typename... Args,
size_t N = sizeof...(Args)>
static TIMEMORY_HOT_INLINE Ret invoke(Fn&& __f, Tuple<Args...>&& __t) noexcept
{
using Tuple_t = Tuple<Args...>;
internal::apply<Ret>::template invoke<Fn, Tuple_t>(
std::forward<Fn>(__f), std::forward<Tuple_t>(__t), make_index_sequence<N>{});
}
//----------------------------------------------------------------------------------//
// per-element addition
//
template <typename Tuple, size_t N = std::tuple_size<Tuple>::value>
static TIMEMORY_HOT_INLINE void plus(Tuple& _lhs, const Tuple& _rhs) noexcept
{
math::plus(_lhs, _rhs);
}
//----------------------------------------------------------------------------------//
// per-element subtraction
//
template <typename Tuple, size_t N = std::tuple_size<Tuple>::value>
static TIMEMORY_HOT_INLINE void minus(Tuple& _lhs, const Tuple& _rhs) noexcept
{
math::minus(_lhs, _rhs);
}
//----------------------------------------------------------------------------------//
template <size_t N, typename Device, typename Func, typename... Args,
enable_if_t<std::is_same<Device, device::gpu>::value, char> = 0>
TIMEMORY_LAMBDA static void unroll(Func&& __func, Args&&... __args) noexcept
{
internal::apply<void>::template unroll<N, Device, Func, Args...>(
std::forward<Func>(__func), std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
template <size_t N, typename Device, typename Func, typename... Args,
enable_if_t<std::is_same<Device, device::cpu>::value, char> = 0>
static TIMEMORY_HOT_INLINE void unroll(Func&& __func, Args&&... __args) noexcept
{
internal::apply<void>::template unroll<N, Device, Func, Args...>(
std::forward<Func>(__func), std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
//
// N > 0
//
//----------------------------------------------------------------------------------//
template <typename Tp, typename Value>
static TIMEMORY_HOT_INLINE auto set_value_fold(Tp&& _t, int, Value&& _v) noexcept
-> decltype(std::forward<Tp>(_t) = std::forward<Value>(_v), void())
{
std::forward<Tp>(_t) = std::forward<Value>(_v);
}
template <typename Tp, typename Value>
static TIMEMORY_HOT_INLINE void set_value_fold(Tp&&, long, Value&&) noexcept
{}
template <typename Tuple, typename Value, size_t... Idx>
static TIMEMORY_HOT_INLINE void set_value_fold(Tuple&& _t, Value&& _v,
index_sequence<Idx...>) noexcept
{
TIMEMORY_FOLD_EXPRESSION(
set_value_fold(std::get<Idx>(_t), 0, std::forward<Value>(_v)));
}
//----------------------------------------------------------------------------------//
template <typename Tuple, typename Value>
static TIMEMORY_HOT_INLINE void set_value(Tuple&& _t, Value&& _v) noexcept
{
constexpr auto N = std::tuple_size<decay_t<Tuple>>::value;
set_value_fold(std::forward<Tuple>(_t), std::forward<Value>(_v),
make_index_sequence<N>{});
}
//----------------------------------------------------------------------------------//
template <typename Access, typename Tuple, size_t... Idx, typename... Args>
static TIMEMORY_HOT_INLINE void access_fold(Tuple&& _t, index_sequence<Idx...>,
Args&&... _args)
{
TIMEMORY_FOLD_EXPRESSION(
Access_t<Idx, Access>(std::get<Idx>(_t), std::forward<Args>(_args)...));
}
//----------------------------------------------------------------------------------//
template <typename Access, typename Tuple, typename... Args>
static TIMEMORY_HOT_INLINE void access(Tuple&& __t, Args&&... __args) noexcept
{
constexpr auto N = std::tuple_size<decay_t<Access>>::value;
constexpr auto Nt = std::tuple_size<decay_t<Tuple>>::value;
static_assert(N == Nt, "Cannot fold Access from Tuple because sizes differ");
access_fold<Access>(std::forward<Tuple>(__t), std::make_index_sequence<N>{},
std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
template <typename Access, size_t... Idx, typename... Args>
static TIMEMORY_HOT_INLINE auto get_fold(index_sequence<Idx...>, Args&&... _args)
{
return std::make_tuple(
Access_t<Idx, Access>::get(std::forward<Args>(_args)...)...);
}
//----------------------------------------------------------------------------------//
template <typename Access, typename... Args>
static TIMEMORY_HOT_INLINE auto get(Args&&... __args)
{
constexpr auto N = std::tuple_size<decay_t<Access>>::value;
return get_fold<Access>(std::make_index_sequence<N>{},
std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
template <typename Access, typename Tuple, typename... Args>
static TIMEMORY_HOT_INLINE void access_with_indices(Tuple&& __t,
Args&&... __args) noexcept
{
constexpr auto N = std::tuple_size<decay_t<Tuple>>::value;
internal::apply<void>::template apply_access_with_indices<Access, Tuple, Args...>(
std::forward<Tuple>(__t), make_index_sequence<N>{},
std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
template <typename Access, typename TupleA, typename TupleB, typename... Args>
static TIMEMORY_HOT_INLINE void access2(TupleA&& __ta, TupleB&& __tb,
Args&&... __args) noexcept
{
constexpr size_t N = std::tuple_size<decay_t<Access>>::value;
constexpr size_t Na = std::tuple_size<decay_t<TupleA>>::value;
constexpr size_t Nb = std::tuple_size<decay_t<TupleB>>::value;
static_assert(Na == Nb, "tuple A size must match tuple B size");
internal::apply<void>::template apply_access2<Access, TupleA, TupleB, Args...>(
std::forward<TupleA>(__ta), std::forward<TupleB>(__tb),
make_index_sequence<N>{}, std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
template <template <typename> class Access, typename Tuple, typename... Args>
static TIMEMORY_HOT_INLINE void unroll_access(Tuple&& __t, Args&&... __args) noexcept
{
constexpr size_t N = std::tuple_size<decay_t<Tuple>>::value;
internal::apply<void>::template unroll_access<Access, Tuple, Args...>(
std::forward<Tuple>(__t), make_index_sequence<N>{},
std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
template <template <typename> class Access, typename Tuple, typename... Args>
static TIMEMORY_HOT_INLINE void type_access(Args&&... __args) noexcept
{
constexpr size_t N = std::tuple_size<decay_t<Tuple>>::value;
internal::apply<void>::template type_access<Access, Tuple, Args...>(
make_index_sequence<N>{}, std::forward<Args>(__args)...);
}
//----------------------------------------------------------------------------------//
};
//
} // namespace mpl
} // namespace tim
+461
Просмотреть файл
@@ -0,0 +1,461 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include "timemory/mpl/bits/types.hpp"
#include "timemory/mpl/math.hpp"
#include "timemory/mpl/types.hpp"
#include "timemory/utility/types.hpp"
#include <array>
#include <ostream>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
//======================================================================================//
#if defined(TIMEMORY_WINDOWS)
namespace std
{
template <typename Lhs, typename Rhs>
const pair<Lhs, Rhs>
operator-(pair<Lhs, Rhs>, const pair<Lhs, Rhs>&);
template <typename... Types>
const tuple<Types...>
operator-(tuple<Types...>, const tuple<Types...>&);
} // namespace std
#endif
//======================================================================================//
namespace tim
{
/// \namespace tim::stl
/// \brief the namespace is provided to hide stl overload from global namespace but
/// provide a method of using the namespace without a "using namespace tim;"
namespace stl
{
namespace ostream
{
/// \namespace tim::stl::ostream
/// \brief the namespace provides overloads to output complex data types w/ streams
//--------------------------------------------------------------------------------------//
//
// operator <<
//
//--------------------------------------------------------------------------------------//
template <typename T, typename U>
std::ostream&
operator<<(std::ostream& os, const std::pair<T, U>& p)
{
os << "(" << p.first << "," << p.second << ")";
return os;
}
//--------------------------------------------------------------------------------------//
//
template <typename... Types>
std::ostream&
operator<<(std::ostream& os, const std::tuple<Types...>& p)
{
constexpr size_t N = sizeof...(Types);
tuple_printer(p, os, make_index_sequence<N>{});
return os;
}
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... ExtraT>
std::ostream&
operator<<(std::ostream& os, const std::vector<Tp, ExtraT...>& p)
{
os << "(";
for(size_t i = 0; i < p.size(); ++i)
os << p.at(i) << ((i + 1 < p.size()) ? "," : "");
os << ")";
return os;
}
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::ostream&
operator<<(std::ostream& os, const std::array<Tp, N>& p)
{
os << "(";
for(size_t i = 0; i < p.size(); ++i)
os << p.at(i) << ((i + 1 < p.size()) ? "," : "");
os << ")";
return os;
}
} // namespace ostream
//--------------------------------------------------------------------------------------//
//
// operator += (same type)
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N, typename OtherT>
std::array<Tp, N>&
operator+=(std::array<Tp, N>& lhs, OtherT&& rhs)
{
math::plus(lhs, std::forward<OtherT>(rhs));
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs, typename OtherT>
std::pair<Lhs, Rhs>&
operator+=(std::pair<Lhs, Rhs>& lhs, OtherT&& rhs)
{
math::plus(lhs, std::forward<OtherT>(rhs));
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... ExtraT, typename OtherT>
std::vector<Tp, ExtraT...>&
operator+=(std::vector<Tp, ExtraT...>& lhs, OtherT&& rhs)
{
math::plus(lhs, std::forward<OtherT>(rhs));
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename... Types, typename OtherT>
std::tuple<Types...>&
operator+=(std::tuple<Types...>& lhs, OtherT&& rhs)
{
math::plus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
//
// operator -= (same type)
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N>&
operator-=(std::array<Tp, N>& lhs, const std::array<Tp, N>& rhs)
{
math::minus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs>&
operator-=(std::pair<Lhs, Rhs>& lhs, const std::pair<Lhs, Rhs>& rhs)
{
math::minus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... ExtraT>
std::vector<Tp, ExtraT...>&
operator-=(std::vector<Tp, ExtraT...>& lhs, const std::vector<Tp, ExtraT...>& rhs)
{
math::minus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...>&
operator-=(std::tuple<Types...>& lhs, const std::tuple<Types...>& rhs)
{
math::minus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
//
// operator *= (same type)
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N>&
operator*=(std::array<Tp, N>& lhs, const std::array<Tp, N>& rhs)
{
math::multiply(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs>&
operator*=(std::pair<Lhs, Rhs>& lhs, const std::pair<Lhs, Rhs>& rhs)
{
math::multiply(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... ExtraT>
std::vector<Tp, ExtraT...>&
operator*=(std::vector<Tp, ExtraT...>& lhs, const std::vector<Tp, ExtraT...>& rhs)
{
math::multiply(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...>&
operator*=(std::tuple<Types...>& lhs, const std::tuple<Types...>& rhs)
{
math::multiply(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
//
// operator /= (same type)
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N>&
operator/=(std::array<Tp, N>& lhs, const std::array<Tp, N>& rhs)
{
math::divide(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs>&
operator/=(std::pair<Lhs, Rhs>& lhs, const std::pair<Lhs, Rhs>& rhs)
{
math::divide(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... ExtraT>
std::vector<Tp, ExtraT...>&
operator/=(std::vector<Tp, ExtraT...>& lhs, const std::vector<Tp, ExtraT...>& rhs)
{
math::divide(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...>&
operator/=(std::tuple<Types...>& lhs, const std::tuple<Types...>& rhs)
{
math::divide(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
//
// operator *= (fundamental)
//
//--------------------------------------------------------------------------------------//
template <typename Lhs, size_t N, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int>>
std::array<Lhs, N>&
operator*=(std::array<Lhs, N>& lhs, const Rhs& rhs)
{
math::multiply(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs, typename ArithT,
enable_if_t<std::is_arithmetic<decay_t<ArithT>>::value, int>>
std::pair<Lhs, Rhs>&
operator*=(std::pair<Lhs, Rhs>& lhs, const ArithT& rhs)
{
math::multiply(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs, typename... ExtraT,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int>>
std::vector<Lhs, ExtraT...>&
operator*=(std::vector<Lhs, ExtraT...>& lhs, const Rhs& rhs)
{
math::multiply(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename... Lhs, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int>>
std::tuple<Lhs...>&
operator*=(std::tuple<Lhs...>& lhs, const Rhs& rhs)
{
math::multiply(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
//
// operator /= (fundamental)
//
//--------------------------------------------------------------------------------------//
template <typename Lhs, size_t N, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int>>
std::array<Lhs, N>&
operator/=(std::array<Lhs, N>& lhs, const Rhs& rhs)
{
math::divide(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs, typename ArithT,
enable_if_t<std::is_arithmetic<decay_t<ArithT>>::value, int>>
std::pair<Lhs, Rhs>&
operator/=(std::pair<Lhs, Rhs>& lhs, const ArithT& rhs)
{
math::divide(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs, typename... ExtraT,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int>>
std::vector<Lhs, ExtraT...>&
operator/=(std::vector<Lhs, ExtraT...>& lhs, const Rhs& rhs)
{
math::divide(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename... Lhs, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int>>
std::tuple<Lhs...>&
operator/=(std::tuple<Lhs...>& lhs, const Rhs& rhs)
{
math::divide(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
//
// operator * (fundamental)
// operator / (fundamental)
//
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int>>
Lhs operator*(Lhs lhs, const Rhs& rhs)
{
return (lhs *= rhs);
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int>>
Lhs
operator/(Lhs lhs, const Rhs& rhs)
{
return (lhs /= rhs);
}
//--------------------------------------------------------------------------------------//
} // namespace stl
using namespace stl;
//======================================================================================//
} // namespace tim
//======================================================================================//
namespace std
{
#if defined(TIMEMORY_WINDOWS)
template <typename Lhs, typename Rhs>
const pair<Lhs, Rhs>
operator-(pair<Lhs, Rhs> lhs, const pair<Lhs, Rhs>& rhs)
{
::tim::math::minus(lhs, rhs);
return lhs;
}
template <typename... Types>
const tuple<Types...>
operator-(tuple<Types...> lhs, const tuple<Types...>& rhs)
{
::tim::math::minus(lhs, rhs);
return lhs;
}
#endif
template <typename Tp>
tuple<>&
operator+=(tuple<>& _lhs, const Tp&)
{
return _lhs;
}
} // namespace std
+297
Просмотреть файл
@@ -0,0 +1,297 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
/** \file mpl/bits/types.hpp
* \headerfile mpl/bits/types.hpp "timemory/mpl/bits/types.hpp"
*
* This is a declaration of the STL overload types
*
*/
#pragma once
#include <array>
#include <ostream>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "timemory/mpl/types.hpp"
namespace tim
{
namespace stl
{
namespace ostream
{
//--------------------------------------------------------------------------------------//
//
// operator <<
//
//--------------------------------------------------------------------------------------//
template <typename T, typename U>
std::ostream&
operator<<(std::ostream&, const std::pair<T, U>&);
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::ostream&
operator<<(std::ostream&, const std::tuple<Types...>&);
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... _Extra>
std::ostream&
operator<<(std::ostream&, const std::vector<Tp, _Extra...>&);
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::ostream&
operator<<(std::ostream&, const std::array<Tp, N>&);
//--------------------------------------------------------------------------------------//
template <template <typename...> class _Tuple, typename... Types, size_t... Idx>
void
tuple_printer(const _Tuple<Types...>& obj, std::ostream& os, index_sequence<Idx...>)
{
using namespace ::tim::stl::ostream;
constexpr size_t N = sizeof...(Types);
if(N > 0)
os << "(";
char delim[N];
TIMEMORY_FOLD_EXPRESSION(delim[Idx] = ',');
delim[N - 1] = '\0';
TIMEMORY_FOLD_EXPRESSION(os << std::get<Idx>(obj) << delim[Idx]);
if(N > 0)
os << ")";
}
//--------------------------------------------------------------------------------------//
} // namespace ostream
//--------------------------------------------------------------------------------------//
//
// operator +=
// operator +
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N, typename Other>
std::array<Tp, N>&
operator+=(std::array<Tp, N>&, Other&&);
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs, typename Other>
std::pair<Lhs, Rhs>&
operator+=(std::pair<Lhs, Rhs>&, Other&&);
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... _Extra, typename Other>
std::vector<Tp, _Extra...>&
operator+=(std::vector<Tp, _Extra...>&, Other&&);
//--------------------------------------------------------------------------------------//
template <typename... Types, typename Other>
std::tuple<Types...>&
operator+=(std::tuple<Types...>&, Other&&);
//--------------------------------------------------------------------------------------//
//
// operator -=
// operator -
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N>&
operator-=(std::array<Tp, N>&, const std::array<Tp, N>&);
template <typename Lhs, size_t N, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int> = 0>
std::array<Lhs, N>&
operator-=(std::array<Lhs, N>&, const Rhs&);
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs>&
operator-=(std::pair<Lhs, Rhs>&, const std::pair<Lhs, Rhs>&);
template <typename Lhs, typename Rhs, typename ArithT,
enable_if_t<std::is_arithmetic<decay_t<ArithT>>::value, int> = 0>
std::pair<Lhs, Rhs>&
operator-=(std::pair<Lhs, Rhs>&, const ArithT&);
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... _Extra>
std::vector<Tp, _Extra...>&
operator-=(std::vector<Tp, _Extra...>&, const std::vector<Tp, _Extra...>&);
template <typename Lhs, typename Rhs, typename... _Extra,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int> = 0>
std::vector<Lhs, _Extra...>&
operator-=(std::vector<Lhs, _Extra...>&, const Rhs&);
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...>&
operator-=(std::tuple<Types...>&, const std::tuple<Types...>&);
template <typename... Lhs, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int> = 0>
std::tuple<Lhs...>&
operator-=(std::tuple<Lhs...>&, const Rhs&);
//--------------------------------------------------------------------------------------//
//
// operator *=
// operator *
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N>&
operator*=(std::array<Tp, N>&, const std::array<Tp, N>&);
template <typename Lhs, size_t N, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int> = 0>
std::array<Lhs, N>&
operator*=(std::array<Lhs, N>&, const Rhs&);
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs>&
operator*=(std::pair<Lhs, Rhs>&, const std::pair<Lhs, Rhs>&);
template <typename Lhs, typename Rhs, typename ArithT,
enable_if_t<std::is_arithmetic<decay_t<ArithT>>::value, int> = 0>
std::pair<Lhs, Rhs>&
operator*=(std::pair<Lhs, Rhs>&, const ArithT&);
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... _Extra>
std::vector<Tp, _Extra...>&
operator*=(std::vector<Tp, _Extra...>&, const std::vector<Tp, _Extra...>&);
template <typename Lhs, typename Rhs, typename... _Extra,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int> = 0>
std::vector<Lhs, _Extra...>&
operator*=(std::vector<Lhs, _Extra...>&, const Rhs&);
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...>&
operator*=(std::tuple<Types...>&, const std::tuple<Types...>&);
template <typename... Lhs, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int> = 0>
std::tuple<Lhs...>&
operator*=(std::tuple<Lhs...>&, const Rhs&);
//--------------------------------------------------------------------------------------//
//
// operator /=
// operator /
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N>&
operator/=(std::array<Tp, N>&, const std::array<Tp, N>&);
template <typename Lhs, size_t N, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int> = 0>
std::array<Lhs, N>&
operator/=(std::array<Lhs, N>&, const Rhs&);
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs>&
operator/=(std::pair<Lhs, Rhs>&, const std::pair<Lhs, Rhs>&);
template <typename Lhs, typename Rhs, typename ArithT,
enable_if_t<std::is_arithmetic<decay_t<ArithT>>::value, int> = 0>
std::pair<Lhs, Rhs>&
operator/=(std::pair<Lhs, Rhs>&, const ArithT&);
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... _Extra>
std::vector<Tp, _Extra...>&
operator/=(std::vector<Tp, _Extra...>&, const std::vector<Tp, _Extra...>&);
template <typename Lhs, typename Rhs, typename... _Extra,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int> = 0>
std::vector<Lhs, _Extra...>&
operator/=(std::vector<Lhs, _Extra...>&, const Rhs&);
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...>&
operator/=(std::tuple<Types...>&, const std::tuple<Types...>&);
template <typename... Lhs, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int> = 0>
std::tuple<Lhs...>&
operator/=(std::tuple<Lhs...>&, const Rhs&);
//--------------------------------------------------------------------------------------//
//
// operator * (fundamental)
// operator / (fundamental)
//
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int> = 0>
Lhs operator*(Lhs, const Rhs&);
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs,
enable_if_t<std::is_arithmetic<decay_t<Rhs>>::value, int> = 0>
Lhs
operator/(Lhs, const Rhs&);
} // namespace stl
} // namespace tim
+647
Просмотреть файл
@@ -0,0 +1,647 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
#include <cstddef>
#include <cstdint>
#include <string>
#include <tuple>
#include <type_traits>
#if __cplusplus >= 201703L // C++17
# include <string_view>
#endif
//--------------------------------------------------------------------------------------//
#define TIMEMORY_IMPL_IS_CONCEPT(CONCEPT) \
struct CONCEPT \
{}; \
template <typename Tp> \
struct is_##CONCEPT \
{ \
private: \
template <typename, typename = std::true_type> \
struct have : std::false_type \
{}; \
template <typename U> \
struct have<U, typename std::is_base_of<typename U::CONCEPT, U>::type> \
: std::true_type \
{}; \
template <typename U> \
struct have<U, typename std::is_base_of<typename U::CONCEPT##_type, U>::type> \
: std::true_type \
{}; \
\
public: \
using type = typename is_##CONCEPT::template have< \
typename std::remove_cv<Tp>::type>::type; \
static constexpr bool value = \
is_##CONCEPT::template have<typename std::remove_cv<Tp>::type>::value; \
};
// constexpr operator bool() const noexcept { return value; }
//--------------------------------------------------------------------------------------//
namespace tim
{
namespace cereal
{
namespace detail
{
//
class OutputArchiveBase;
class InputArchiveBase;
//
} // namespace detail
} // namespace cereal
} // namespace tim
//
namespace tim
{
//
using true_type = std::true_type;
using false_type = std::false_type;
//
struct null_type;
//
struct quirk_type;
//
namespace audit
{
struct incoming;
struct outgoing;
} // namespace audit
//
namespace trait
{
template <typename Tp>
struct is_available;
//
template <typename Tp>
struct is_component;
} // namespace trait
//
namespace
{
template <typename Tp>
struct anonymous
{
using type = Tp;
};
//
template <typename Tp>
using anonymous_t = typename anonymous<Tp>::type;
} // namespace
//
namespace component
{
template <size_t Idx, typename Tag>
struct user_bundle;
//
template <size_t Nt, typename ComponentsT, typename DifferentiatorT = anonymous_t<void>>
struct gotcha;
//
template <typename... Types>
struct placeholder;
//
struct nothing;
//
} // namespace component
//
template <typename... Types>
class lightweight_tuple;
//
namespace concepts
{
//
using input_archive_base = cereal::detail::InputArchiveBase;
using output_archive_base = cereal::detail::OutputArchiveBase;
//
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_empty
/// \brief concept that specifies that a variadic type is empty
///
TIMEMORY_IMPL_IS_CONCEPT(empty)
template <template <typename...> class Tuple>
struct is_empty<Tuple<>> : true_type
{};
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_null_type
/// \brief concept that specifies that a type is not a useful type
///
TIMEMORY_IMPL_IS_CONCEPT(null_type)
template <template <typename...> class Tuple>
struct is_null_type<Tuple<>> : true_type
{};
template <>
struct is_null_type<void> : true_type
{};
template <>
struct is_null_type<false_type> : true_type
{};
template <>
struct is_null_type<::tim::null_type> : true_type
{};
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_placeholder
/// \brief concept that specifies that a type is not necessarily marked as not available
/// but is still a dummy type
///
TIMEMORY_IMPL_IS_CONCEPT(placeholder)
template <typename... Types>
struct is_placeholder<component::placeholder<Types...>> : true_type
{};
template <>
struct is_placeholder<component::placeholder<component::nothing>> : true_type
{};
template <>
struct is_placeholder<component::nothing> : true_type
{};
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_component
/// \brief concept that specifies that a type is a component. Components are used to
/// perform some measurement, capability, or logging implementation. Adding this
/// concept can be performs through inheriting from \ref tim::component::base,
/// inheriting from tim::concepts::component, or specializing either \ref
/// tim::concepts::is_component or \ref tim::trait::is_component (with the latter
/// being deprecated).
///
struct component
{};
//
template <typename Tp>
struct is_component
{
private:
/// did not inherit
template <typename, typename = std::true_type>
struct have : std::false_type
{};
/// did inherit
template <typename U>
struct have<U, typename std::is_base_of<typename U::component, U>::type>
: std::true_type
{};
/// this uses sfinae to see if U::is_component is provided within the type
template <typename U>
static constexpr decltype(U::is_component, bool{}) test(int)
{
return U::is_component;
}
/// this checks for the (deprecated) `tim::trait::is_component` specialization
/// and checks for inheritance
template <typename Up>
static constexpr bool test(long)
{
return trait::is_component<Up>::value ||
is_component::template have<std::remove_cv_t<Tp>>::value;
}
public:
static constexpr bool value = test<Tp>(int{});
using type = std::conditional_t<value, true_type, false_type>;
};
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_quirk_type
/// \brief concept that specifies that a type is a quirk. Quirks are used to modify
/// the traditional behavior of component bundles slightly. E.g. disable calling
/// start in the constructor of an auto_tuple.
///
TIMEMORY_IMPL_IS_CONCEPT(quirk_type)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_api
/// \brief concept that specifies that a type is an API. APIs are used to designate
/// different project implementations, different external library tools, etc.
///
TIMEMORY_IMPL_IS_CONCEPT(api)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_variadic
/// \brief concept that specifies that a type is a generic variadic wrapper
///
TIMEMORY_IMPL_IS_CONCEPT(variadic)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_wrapper
/// \brief concept that specifies that a type is a timemory variadic wrapper
///
TIMEMORY_IMPL_IS_CONCEPT(wrapper)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_stack_wrapper
/// \brief concept that specifies that a type is a timemory variadic wrapper
/// and components are stack-allocated
///
TIMEMORY_IMPL_IS_CONCEPT(stack_wrapper)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_heap_wrapper
/// \brief concept that specifies that a type is a timemory variadic wrapper
/// and components are heap-allocated
///
TIMEMORY_IMPL_IS_CONCEPT(heap_wrapper)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_mixed_wrapper
/// \brief concept that specifies that a type is a timemory variadic wrapper
/// and variadic types are mix of stack- and heap- allocated
///
TIMEMORY_IMPL_IS_CONCEPT(mixed_wrapper)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_tagged
/// \brief concept that specifies that a type's template parameters include
/// a API specific tag as one of the template parameters (usually first)
///
TIMEMORY_IMPL_IS_CONCEPT(tagged)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_comp_wrapper
/// \brief concept that specifies that a type is a timemory variadic wrapper
/// that does not perform auto start/stop, e.g. component_{tuple,list,hybrid}
///
TIMEMORY_IMPL_IS_CONCEPT(comp_wrapper)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_auto_wrapper
/// \brief concept that specifies that a type is a timemory variadic wrapper
/// that performs auto start/stop, e.g. auto_{tuple,list,hybrid}
///
TIMEMORY_IMPL_IS_CONCEPT(auto_wrapper)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_runtime_configurable
/// \brief concept that specifies that a type is used to modify behavior at runtime.
/// For example, the \ref tim::component::user_bundle component is runtime configurable bc
/// it allows you insert components at runtime. The timing category
/// (`tim::category::timing`) is another example of a type that is runtime configurable --
/// setting `tim::trait::runtime_enabled<tim::category::timing>::set(false);` will disable
/// (at runtime) all the types which are part of the timing API. It should be noted that
/// types which satisfy `is_runtime_configurable<Tp>::value == true` (e.g. \ref
/// tim::component::user_bundle) are not eligible to be inserted into other runtime
/// configurable components; i.e. you cannot insert/add \ref
/// tim::component::user_trace_bundle into \ref tim::component::user_global_bundle, etc.
/// This restriction is primarily due to the significant increase in compile-time that
/// arises from allowing this behavior.
///
TIMEMORY_IMPL_IS_CONCEPT(runtime_configurable)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_external_function_wrapper
/// \brief concept that specifies that a component type wraps external functions
///
TIMEMORY_IMPL_IS_CONCEPT(external_function_wrapper)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_phase_id
/// \brief concept that specifies that a type is used for identifying a phase in some
/// measurement. For example, `tim::audit::incoming` and `tim::audit::outgoing`
/// can be added to overloads to distinguish whether the `double` type in `double
/// exp(double val)` is `val` or whether it is the return value.
///
/// \code{.cpp}
/// struct exp_wrapper_A
/// {
/// // unable to distingush whether "val" is input or output
/// void audit(double val) { ... }
/// };
///
/// struct exp_wrapper_B
/// {
/// // able to distingush whether "val" is input or output
/// void audit(audit::incoming, double val) { ... }
/// void audit(audit::outgoing, double val) { ... }
/// };
/// \endcode
TIMEMORY_IMPL_IS_CONCEPT(phase_id)
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_string_type
/// \brief concept that specifies that a component type wraps external functions
///
TIMEMORY_IMPL_IS_CONCEPT(string_type)
template <>
struct is_string_type<std::string> : true_type
{};
template <>
struct is_string_type<char*> : true_type
{};
template <>
struct is_string_type<const char*> : true_type
{};
#if __cplusplus >= 201703L // C++17
template <>
struct is_string_type<std::string_view> : true_type
{};
#endif
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::has_gotcha
/// \brief determines if a variadic wrapper contains a gotcha component
///
template <typename T>
struct has_gotcha : std::false_type
{};
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::has_user_bundle
/// \brief concept that specifies that a type is a user_bundle type
///
template <typename T>
struct has_user_bundle : false_type
{};
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_output_archive
/// \brief concept that specifies that a type is an output serialization archive
///
template <typename Tp>
struct is_output_archive
{
private:
/// did not inherit
template <typename, typename = std::true_type>
struct have : std::false_type
{};
/// did inherit
template <typename U>
struct have<U, typename std::is_base_of<output_archive_base, U>::type>
: std::true_type
{};
public:
static constexpr bool value =
is_output_archive::template have<std::remove_cv_t<Tp>>::value;
using type = std::conditional_t<value, true_type, false_type>;
};
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_input_archive
/// \brief concept that specifies that a type is an input serialization archive
///
template <typename Tp>
struct is_input_archive
{
private:
/// did not inherit
template <typename, typename = std::true_type>
struct have : std::false_type
{};
/// did inherit
template <typename U>
struct have<U, typename std::is_base_of<input_archive_base, U>::type> : std::true_type
{};
public:
static constexpr bool value =
is_input_archive::template have<std::remove_cv_t<Tp>>::value;
using type = std::conditional_t<value, true_type, false_type>;
};
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_archive
/// \brief concept that specifies that a type is a serialization archive (input or output)
///
template <typename Tp>
struct is_archive
{
static constexpr bool value =
is_input_archive<Tp>::value || is_output_archive<Tp>::value;
using type = std::conditional_t<value, true_type, false_type>;
};
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::is_acceptable_conversion
/// \tparam Lhs the provided type
/// \tparam Rhs the target type
///
/// \brief This concept designates that is safe to perform a `static_cast<Lhs>(rhs)`
/// where needed. This is primarily used in the \ref tim::component::data_tracker
/// where `data_tracker<unsigned int, ...>` might be provided another integral type,
/// such as `int`.
///
template <typename Lhs, typename Rhs>
struct is_acceptable_conversion
{
static constexpr bool value =
(std::is_same<Lhs, Rhs>::value ||
(std::is_integral<Lhs>::value && std::is_integral<Rhs>::value) ||
(std::is_floating_point<Lhs>::value && std::is_floating_point<Rhs>::value));
};
//--------------------------------------------------------------------------------------//
/// \struct tim::concepts::tuple_type
/// \brief This concept is used to express how to convert a given type into a
/// `std::tuple`, e.g. `tim::component_tuple<T...>` to `std::tuple<T...>`. It
/// is necessary for types like \ref tim::component_bundle where certain template
/// parameters are tags.
///
template <typename T>
struct tuple_type
{
using type = typename T::tuple_type;
};
/// \struct tim::concepts::auto_type
/// \brief This concept is used to express how to convert a component bundler into
/// another component bundler which performs automatic starting upon construction.
///
template <typename T>
struct auto_type
{
using type = typename T::auto_type;
};
/// \struct tim::concepts::component_type
/// \brief This concept is used to express how to convert a component bundler which
/// automatically starts upon construction into a type that requires an explicit
/// call to start.
///
template <typename T>
struct component_type
{
using type = typename T::component_type;
};
template <>
struct component_type<std::tuple<>>
{
using type = lightweight_tuple<>;
};
//--------------------------------------------------------------------------------------//
} // namespace concepts
template <typename T>
using is_empty_t = typename concepts::is_empty<T>::type;
template <typename T>
using is_variadic_t = typename concepts::is_variadic<T>::type;
template <typename T>
using is_wrapper_t = typename concepts::is_wrapper<T>::type;
template <typename T>
using is_stack_wrapper_t = typename concepts::is_stack_wrapper<T>::type;
template <typename T>
using is_heap_wrapper_t = typename concepts::is_heap_wrapper<T>::type;
//--------------------------------------------------------------------------------------//
} // namespace tim
//======================================================================================//
#if !defined(TIMEMORY_CONCEPT_ALIAS)
# define TIMEMORY_CONCEPT_ALIAS(ALIAS, TYPE) \
namespace tim \
{ \
namespace concepts \
{ \
template <typename T> \
using ALIAS = typename TYPE<T>::type; \
} \
}
#endif
//--------------------------------------------------------------------------------------//
TIMEMORY_CONCEPT_ALIAS(is_empty_t, is_empty)
TIMEMORY_CONCEPT_ALIAS(is_variadic_t, is_variadic)
TIMEMORY_CONCEPT_ALIAS(is_wrapper_t, is_wrapper)
TIMEMORY_CONCEPT_ALIAS(is_stack_wrapper_t, is_stack_wrapper)
TIMEMORY_CONCEPT_ALIAS(is_heap_wrapper_t, is_heap_wrapper)
TIMEMORY_CONCEPT_ALIAS(tuple_type_t, tuple_type)
TIMEMORY_CONCEPT_ALIAS(auto_type_t, auto_type)
TIMEMORY_CONCEPT_ALIAS(component_type_t, component_type)
//--------------------------------------------------------------------------------------//
#define TIMEMORY_DEFINE_CONCRETE_CONCEPT(CONCEPT, SPECIALIZED_TYPE, VALUE) \
namespace tim \
{ \
namespace concepts \
{ \
template <> \
struct CONCEPT<SPECIALIZED_TYPE> : VALUE \
{}; \
} \
}
//--------------------------------------------------------------------------------------//
#define TIMEMORY_DEFINE_TEMPLATE_CONCEPT(CONCEPT, SPECIALIZED_TYPE, VALUE, TYPE) \
namespace tim \
{ \
namespace concepts \
{ \
template <TYPE T> \
struct CONCEPT<SPECIALIZED_TYPE<T>> : VALUE \
{}; \
} \
}
//--------------------------------------------------------------------------------------//
#define TIMEMORY_DEFINE_VARIADIC_CONCEPT(CONCEPT, SPECIALIZED_TYPE, VALUE, TYPE) \
namespace tim \
{ \
namespace concepts \
{ \
template <TYPE... T> \
struct CONCEPT<SPECIALIZED_TYPE<T...>> : VALUE \
{}; \
} \
}
//--------------------------------------------------------------------------------------//
#define TIMEMORY_DEFINE_CONCRETE_CONCEPT_TYPE(CONCEPT, SPECIALIZED_TYPE, ...) \
namespace tim \
{ \
namespace concepts \
{ \
template <> \
struct CONCEPT<SPECIALIZED_TYPE> \
{ \
using type = __VA_ARGS__; \
}; \
} \
}
//--------------------------------------------------------------------------------------//
#define TIMEMORY_DEFINE_TEMPLATE_CONCEPT_TYPE(CONCEPT, SPECIALIZED_TYPE, TYPE, ...) \
namespace tim \
{ \
namespace concepts \
{ \
template <TYPE T> \
struct CONCEPT<SPECIALIZED_TYPE<T>> \
{ \
using type = __VA_ARGS__; \
}; \
} \
}
//--------------------------------------------------------------------------------------//
#define TIMEMORY_DEFINE_VARIADIC_CONCEPT_TYPE(CONCEPT, SPECIALIZED_TYPE, TYPE, ...) \
namespace tim \
{ \
namespace concepts \
{ \
template <TYPE... T> \
struct CONCEPT<SPECIALIZED_TYPE<T...>> \
{ \
using type = __VA_ARGS__; \
}; \
} \
}
Разница между файлами не показана из-за своего большого размера Загрузить разницу
+371
Просмотреть файл
@@ -0,0 +1,371 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
/** \file mpl/stl.hpp
* \headerfile mpl/stl.hpp "timemory/mpl/stl.hpp"
* Provides operators on common STL structures such as <<, +=, -=, *=, /=, +, -, *, /
*
*/
#pragma once
#include <array>
#include <ostream>
#include <tuple>
#include <utility>
#include <vector>
#include "timemory/mpl/math.hpp"
#include "timemory/utility/macros.hpp"
namespace tim
{
namespace stl
{
namespace ostream
{
//--------------------------------------------------------------------------------------//
//
// operator <<
//
//--------------------------------------------------------------------------------------//
template <typename T, typename U>
std::ostream&
operator<<(std::ostream&, const std::pair<T, U>&);
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::ostream&
operator<<(std::ostream&, const std::tuple<Types...>&);
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... Extra>
std::ostream&
operator<<(std::ostream&, const std::vector<Tp, Extra...>&);
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::ostream&
operator<<(std::ostream&, const std::array<Tp, N>&);
//--------------------------------------------------------------------------------------//
} // namespace ostream
//--------------------------------------------------------------------------------------//
//
// operator +=
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N, typename Other>
std::array<Tp, N>&
operator+=(std::array<Tp, N>&, Other&&);
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs, typename Other>
std::pair<Lhs, Rhs>&
operator+=(std::pair<Lhs, Rhs>&, Other&&);
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... Extra, typename Other>
std::vector<Tp, Extra...>&
operator+=(std::vector<Tp, Extra...>&, Other&&);
//--------------------------------------------------------------------------------------//
template <typename... Types, typename Other>
std::tuple<Types...>&
operator+=(std::tuple<Types...>&, Other&&);
//--------------------------------------------------------------------------------------//
//
// operator -=
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N>&
operator-=(std::array<Tp, N>&, const std::array<Tp, N>&);
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...>&
operator-=(std::tuple<Types...>&, const std::tuple<Types...>&);
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs>&
operator-=(std::pair<Lhs, Rhs>&, const std::pair<Lhs, Rhs>&);
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... Extra>
std::vector<Tp, Extra...>&
operator-=(std::vector<Tp, Extra...>&, const std::vector<Tp, Extra...>&);
//--------------------------------------------------------------------------------------//
//
// operator *=
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N>&
operator*=(std::array<Tp, N>&, const std::array<Tp, N>&);
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs>&
operator*=(std::pair<Lhs, Rhs>&, const std::pair<Lhs, Rhs>&);
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...>&
operator*=(std::tuple<Types...>&, const std::tuple<Types...>&);
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... Extra>
std::vector<Tp, Extra...>&
operator*=(std::vector<Tp, Extra...>&, const std::vector<Tp, Extra...>&);
//--------------------------------------------------------------------------------------//
//
// operator /=
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N>&
operator/=(std::array<Tp, N>&, const std::array<Tp, N>&);
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs>&
operator/=(std::pair<Lhs, Rhs>&, const std::pair<Lhs, Rhs>&);
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...>&
operator/=(std::tuple<Types...>&, const std::tuple<Types...>&);
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... Extra>
std::vector<Tp, Extra...>&
operator/=(std::vector<Tp, Extra...>&, const std::vector<Tp, Extra...>&);
//--------------------------------------------------------------------------------------//
//
// operator +
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N>
operator+(std::array<Tp, N> lhs, const std::array<Tp, N>& rhs)
{
math::plus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...>
operator+(std::tuple<Types...> lhs, const std::tuple<Types...>& rhs)
{
math::plus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs>
operator+(std::pair<Lhs, Rhs> lhs, const std::pair<Lhs, Rhs>& rhs)
{
math::plus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... Extra>
std::vector<Tp, Extra...>
operator+(std::vector<Tp, Extra...> lhs, const std::vector<Tp, Extra...>& rhs)
{
math::plus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
//
// operator -
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N>
operator-(std::array<Tp, N> lhs, const std::array<Tp, N>& rhs)
{
math::minus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...>
operator-(std::tuple<Types...> lhs, const std::tuple<Types...>& rhs)
{
math::minus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs>
operator-(std::pair<Lhs, Rhs> lhs, const std::pair<Lhs, Rhs>& rhs)
{
math::minus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... Extra>
std::vector<Tp, Extra...>
operator-(std::vector<Tp, Extra...> lhs, const std::vector<Tp, Extra...>& rhs)
{
math::minus(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
//
// operator *
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N> operator*(std::array<Tp, N> lhs, const std::array<Tp, N>& rhs)
{
math::multiply(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...> operator*(std::tuple<Types...> lhs, const std::tuple<Types...>& rhs)
{
math::multiply(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs> operator*(std::pair<Lhs, Rhs> lhs, const std::pair<Lhs, Rhs>& rhs)
{
math::multiply(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... Extra>
std::vector<Tp, Extra...> operator*(std::vector<Tp, Extra...> lhs,
const std::vector<Tp, Extra...>& rhs)
{
math::multiply(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
//
// operator /
//
//--------------------------------------------------------------------------------------//
template <typename Tp, size_t N>
std::array<Tp, N>
operator/(std::array<Tp, N> lhs, const std::array<Tp, N>& rhs)
{
math::divide(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename... Types>
std::tuple<Types...>
operator/(std::tuple<Types...> lhs, const std::tuple<Types...>& rhs)
{
math::divide(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Lhs, typename Rhs>
std::pair<Lhs, Rhs>
operator/(std::pair<Lhs, Rhs> lhs, const std::pair<Lhs, Rhs>& rhs)
{
math::divide(lhs, rhs);
return lhs;
}
//--------------------------------------------------------------------------------------//
template <typename Tp, typename... Extra>
std::vector<Tp, Extra...>
operator/(std::vector<Tp, Extra...> lhs, const std::vector<Tp, Extra...>& rhs)
{
math::divide(lhs, rhs);
return lhs;
}
} // namespace stl
using namespace stl;
} // namespace tim
#include "timemory/mpl/bits/stl.hpp"
Разница между файлами не показана из-за своего большого размера Загрузить разницу
+45
Просмотреть файл
@@ -0,0 +1,45 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
// cereal will cause some -Wclass-memaccess warnings that are quite annoying
#if defined(__GNUC__) && (__GNUC__ > 7)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
// define this so avoid warnings about noexcept functions throwing
#if !defined(TIMEMORY_CEREAL_RAPIDJSON_ASSERT)
# define TIMEMORY_CEREAL_RAPIDJSON_ASSERT(x) \
{}
#endif
// general
#include "timemory/tpls/cereal/cereal/cereal.hpp"
#include "timemory/tpls/cereal/cereal/macros.hpp"
#if defined(__GNUC__) && (__GNUC__ > 7)
# pragma GCC diagnostic pop
#endif
+434
Просмотреть файл
@@ -0,0 +1,434 @@
/*! \file access.hpp
\brief Access control and default construction */
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of cereal nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TIMEMORY_CEREAL_ACCESS_HPP_
#define TIMEMORY_CEREAL_ACCESS_HPP_
#include <cstdint>
#include <functional>
#include <iostream>
#include <type_traits>
#include <utility>
#include "timemory/tpls/cereal/cereal/details/helpers.hpp"
#include "timemory/tpls/cereal/cereal/macros.hpp"
#include "timemory/tpls/cereal/cereal/specialize.hpp"
namespace tim
{
namespace cereal
{
// ######################################################################
//! A class that allows cereal to load smart pointers to types that have no default
//! constructor
/*! If your class does not have a default constructor, cereal will not be able
to load any smart pointers to it unless you overload LoadAndConstruct
for your class, and provide an appropriate load_and_construct method. You can also
choose to define a member static function instead of specializing this class.
The specialization of LoadAndConstruct must be placed within the cereal namespace:
@code{.cpp}
struct MyType
{
MyType( int x ); // note: no default ctor
int myX;
// Define a serialize or load/save pair as you normally would
template <class Archive>
void serialize( Archive & ar )
{
ar( myX );
}
};
// Provide a specialization for LoadAndConstruct for your type
namespace cereal
{
template <> struct LoadAndConstruct<MyType>
{
// load_and_construct will be passed the archive that you will be loading
// from as well as a construct object which you can use as if it were the
// constructor for your type. cereal will handle all memory management for you.
template <class Archive>
static void load_and_construct( Archive & ar, cereal::construct<MyType> &
construct )
{
int x;
ar( x );
construct( x );
}
// if you require versioning, simply add a const std::uint32_t as the final
parameter, e.g.:
// load_and_construct( Archive & ar, cereal::construct<MyType> & construct,
std::uint32_t const version )
};
} // end namespace cereal
@endcode
Please note that just as in using external serialization functions, you cannot get
access to non-public members of your class by befriending cereal::access. If you
have the ability to modify the class you wish to serialize, it is recommended that you
use member serialize functions and a static member load_and_construct function.
load_and_construct functions, regardless of whether they are static members of your
class or whether you create one in the LoadAndConstruct specialization, have the
following signature:
@code{.cpp}
// generally Archive will be templated, but it can be specific if desired
template <class Archive>
static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct );
// with an optional last parameter specifying the version: const std::uint32_t version
@endcode
Versioning behaves the same way as it does for standard serialization functions.
@tparam T The type to specialize for
@ingroup Access */
template <class T>
struct LoadAndConstruct
{};
// forward decl for construct
//! @cond PRIVATE_NEVERDEFINED
namespace memory_detail
{
template <class Ar, class T>
struct LoadAndConstructLoadWrapper;
}
namespace boost_variant_detail
{
template <class Ar, class T>
struct LoadAndConstructLoadWrapper;
}
//! @endcond
//! Used to construct types with no default constructor
/*! When serializing a type that has no default constructor, cereal
will attempt to call either the class static function load_and_construct
or the appropriate template specialization of LoadAndConstruct. cereal
will pass that function a reference to the archive as well as a reference
to a construct object which should be used to perform the allocation once
data has been appropriately loaded.
@code{.cpp}
struct MyType
{
// note the lack of default constructor
MyType( int xx, int yy );
int x, y;
double notInConstructor;
template <class Archive>
void serialize( Archive & ar )
{
ar( x, y );
ar( notInConstructor );
}
template <class Archive>
static void load_and_construct( Archive & ar, cereal::construct<MyType> & construct
)
{
int x, y;
ar( x, y );
// use construct object to initialize with loaded data
construct( x, y );
// access to member variables and functions via -> operator
ar( construct->notInConstructor );
// could also do the above section by:
double z;
ar( z );
construct->notInConstructor = z;
}
};
@endcode
@tparam T The class type being serialized
*/
template <class T>
class construct
{
public:
//! Construct and initialize the type T with the given arguments
/*! This will forward all arguments to the underlying type T,
calling an appropriate constructor.
Calling this function more than once will result in an exception
being thrown.
@param args The arguments to the constructor for T
@throw Exception If called more than once */
template <class... Args>
void operator()(Args&&... args);
// implementation deferred due to reliance on cereal::access
//! Get a reference to the initialized underlying object
/*! This must be called after the object has been initialized.
@return A reference to the initialized object
@throw Exception If called before initialization */
T* operator->()
{
if(!itsValid)
throw Exception("Object must be initialized prior to accessing members");
return itsPtr;
}
//! Returns a raw pointer to the initialized underlying object
/*! This is mainly intended for use with passing an instance of
a constructed object to cereal::base_class.
It is strongly recommended to avoid using this function in
any other circumstance.
@return A raw pointer to the initialized type */
T* ptr() { return operator->(); }
construct(construct const&) = delete;
construct& operator=(construct const&) = delete;
private:
template <class Ar, class TT>
friend struct ::tim::cereal::memory_detail::LoadAndConstructLoadWrapper;
template <class Ar, class TT>
friend struct ::tim::cereal::boost_variant_detail::LoadAndConstructLoadWrapper;
construct(T* p)
: itsPtr(p)
, itsEnableSharedRestoreFunction([]() {})
, itsValid(false)
{}
construct(T* p, std::function<void()> enableSharedFunc)
: // g++4.7 ice with default lambda to std func
itsPtr(p)
, itsEnableSharedRestoreFunction(std::move(enableSharedFunc))
, itsValid(false)
{}
T* itsPtr;
std::function<void()> itsEnableSharedRestoreFunction;
bool itsValid;
};
// ######################################################################
//! A class that can be made a friend to give cereal access to non public functions
/*! If you desire non-public serialization functions within a class, cereal can only
access these if you declare cereal::access a friend.
@code{.cpp}
class MyClass
{
private:
friend class cereal::access; // gives access to the private serialize
template <class Archive>
void serialize( Archive & ar )
{
// some code
}
};
@endcode
@ingroup Access */
class access
{
public:
// ####### Standard Serialization ########################################
template <class Archive, class T>
inline static auto member_serialize(Archive& ar, T& t)
-> decltype(t.TIMEMORY_CEREAL_SERIALIZE_FUNCTION_NAME(ar))
{
return t.TIMEMORY_CEREAL_SERIALIZE_FUNCTION_NAME(ar);
}
template <class Archive, class T>
inline static auto member_save(Archive& ar, T const& t)
-> decltype(t.TIMEMORY_CEREAL_SAVE_FUNCTION_NAME(ar))
{
return t.TIMEMORY_CEREAL_SAVE_FUNCTION_NAME(ar);
}
template <class Archive, class T>
inline static auto member_save_non_const(Archive& ar, T& t)
-> decltype(t.TIMEMORY_CEREAL_SAVE_FUNCTION_NAME(ar))
{
return t.TIMEMORY_CEREAL_SAVE_FUNCTION_NAME(ar);
}
template <class Archive, class T>
inline static auto member_load(Archive& ar, T& t)
-> decltype(t.TIMEMORY_CEREAL_LOAD_FUNCTION_NAME(ar))
{
return t.TIMEMORY_CEREAL_LOAD_FUNCTION_NAME(ar);
}
template <class Archive, class T>
inline static auto member_save_minimal(Archive const& ar, T const& t)
-> decltype(t.TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
{
return t.TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar);
}
template <class Archive, class T>
inline static auto member_save_minimal_non_const(Archive const& ar, T& t)
-> decltype(t.TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar))
{
return t.TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar);
}
template <class Archive, class T, class U>
inline static auto member_load_minimal(Archive const& ar, T& t, U&& u)
-> decltype(t.TIMEMORY_CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u)))
{
return t.TIMEMORY_CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u));
}
// ####### Versioned Serialization #######################################
template <class Archive, class T>
inline static auto member_serialize(Archive& ar, T& t, std::uint32_t version)
-> decltype(t.TIMEMORY_CEREAL_SERIALIZE_FUNCTION_NAME(ar, version))
{
return t.TIMEMORY_CEREAL_SERIALIZE_FUNCTION_NAME(ar, version);
}
template <class Archive, class T>
inline static auto member_save(Archive& ar, T const& t, std::uint32_t version)
-> decltype(t.TIMEMORY_CEREAL_SAVE_FUNCTION_NAME(ar, version))
{
return t.TIMEMORY_CEREAL_SAVE_FUNCTION_NAME(ar, version);
}
template <class Archive, class T>
inline static auto member_save_non_const(Archive& ar, T& t, std::uint32_t version)
-> decltype(t.TIMEMORY_CEREAL_SAVE_FUNCTION_NAME(ar, version))
{
return t.TIMEMORY_CEREAL_SAVE_FUNCTION_NAME(ar, version);
}
template <class Archive, class T>
inline static auto member_load(Archive& ar, T& t, std::uint32_t version)
-> decltype(t.TIMEMORY_CEREAL_LOAD_FUNCTION_NAME(ar, version))
{
return t.TIMEMORY_CEREAL_LOAD_FUNCTION_NAME(ar, version);
}
template <class Archive, class T>
inline static auto member_save_minimal(Archive const& ar, T const& t,
const std::uint32_t version)
-> decltype(t.TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version))
{
return t.TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version);
}
template <class Archive, class T>
inline static auto member_save_minimal_non_const(Archive const& ar, T& t,
const std::uint32_t version)
-> decltype(t.TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version))
{
return t.TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME(ar, version);
}
template <class Archive, class T, class U>
inline static auto member_load_minimal(Archive const& ar, T& t, U&& u,
const std::uint32_t version)
-> decltype(t.TIMEMORY_CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u),
version))
{
return t.TIMEMORY_CEREAL_LOAD_MINIMAL_FUNCTION_NAME(ar, std::forward<U>(u),
version);
}
// ####### Other Functionality ##########################################
// for detecting inheritance from enable_shared_from_this
template <class T>
inline static auto shared_from_this(T& t) -> decltype(t.shared_from_this());
// for placement new
template <class T, class... Args>
inline static void construct(T*& ptr, Args&&... args)
{
new(ptr) T(std::forward<Args>(args)...);
}
// for non-placement new with a default constructor
template <class T>
inline static T* construct()
{
return new T();
}
template <class T>
inline static std::false_type load_and_construct(...)
{
return std::false_type();
}
template <class T, class Archive>
inline static auto load_and_construct(Archive& ar,
::tim::cereal::construct<T>& construct)
-> decltype(T::load_and_construct(ar, construct))
{
T::load_and_construct(ar, construct);
}
template <class T, class Archive>
inline static auto load_and_construct(Archive& ar,
::tim::cereal::construct<T>& construct,
const std::uint32_t version)
-> decltype(T::load_and_construct(ar, construct, version))
{
T::load_and_construct(ar, construct, version);
}
}; // end class access
// ######################################################################
// Deferred Implementation, see construct for more information
template <class T>
template <class... Args>
inline void
construct<T>::operator()(Args&&... args)
{
if(itsValid)
throw Exception("Attempting to construct an already initialized object");
::tim::cereal::access::construct(itsPtr, std::forward<Args>(args)...);
itsEnableSharedRestoreFunction();
itsValid = true;
}
} // namespace cereal
} // namespace tim
#endif // TIMEMORY_CEREAL_ACCESS_HPP_
Разница между файлами не показана из-за своего большого размера Загрузить разницу
+467
Просмотреть файл
@@ -0,0 +1,467 @@
/*! \file helpers.hpp
\brief Internal helper functionality
\ingroup Internal */
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of cereal nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TIMEMORY_CEREAL_DETAILS_HELPERS_HPP_
#define TIMEMORY_CEREAL_DETAILS_HELPERS_HPP_
#include <cstdint>
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include "timemory/tpls/cereal/cereal/details/static_object.hpp"
#include "timemory/tpls/cereal/cereal/macros.hpp"
namespace tim
{
namespace cereal
{
// ######################################################################
//! An exception class thrown when things go wrong at runtime
/*! @ingroup Utility */
struct Exception : public std::runtime_error
{
explicit Exception(const std::string& what_)
: std::runtime_error(what_)
{}
explicit Exception(const char* what_)
: std::runtime_error(what_)
{}
};
// ######################################################################
//! The size type used by cereal
/*! To ensure compatability between 32, 64, etc bit machines, we need to use
a fixed size type instead of size_t, which may vary from machine to
machine.
The default value for TIMEMORY_CEREAL_SIZE_TYPE is specified in cereal/macros.hpp */
using size_type = TIMEMORY_CEREAL_SIZE_TYPE;
// forward decls
class BinaryOutputArchive;
class BinaryInputArchive;
// ######################################################################
namespace detail
{
struct NameValuePairCore
{}; //!< Traits struct for NVPs
struct DeferredDataCore
{}; //!< Traits struct for DeferredData
} // namespace detail
// ######################################################################
//! For holding name value pairs
/*! This pairs a name (some string) with some value such that an archive
can potentially take advantage of the pairing.
In serialization functions, NameValuePairs are usually created like so:
@code{.cpp}
struct MyStruct
{
int a, b, c, d, e;
template<class Archive>
void serialize(Archive & archive)
{
archive( TIMEMORY_CEREAL_NVP(a),
TIMEMORY_CEREAL_NVP(b),
TIMEMORY_CEREAL_NVP(c),
TIMEMORY_CEREAL_NVP(d),
TIMEMORY_CEREAL_NVP(e) );
}
};
@endcode
Alternatively, you can give you data members custom names like so:
@code{.cpp}
struct MyStruct
{
int a, b, my_embarrassing_variable_name, d, e;
template<class Archive>
void serialize(Archive & archive)
{
archive( TIMEMORY_CEREAL_NVP(a),
TIMEMORY_CEREAL_NVP(b),
cereal::make_nvp("var", my_embarrassing_variable_name) );
TIMEMORY_CEREAL_NVP(d),
TIMEMORY_CEREAL_NVP(e) );
}
};
@endcode
There is a slight amount of overhead to creating NameValuePairs, so there
is a third method which will elide the names when they are not used by
the Archive:
@code{.cpp}
struct MyStruct
{
int a, b;
template<class Archive>
void serialize(Archive & archive)
{
archive( cereal::make_nvp<Archive>(a),
cereal::make_nvp<Archive>(b) );
}
};
@endcode
This third method is generally only used when providing generic type
support. Users writing their own serialize functions will normally
explicitly control whether they want to use NVPs or not.
@internal */
template <class T>
class NameValuePair : detail::NameValuePairCore
{
private:
// If we get passed an array, keep the type as is, otherwise store
// a reference if we were passed an l value reference, else copy the value
using Type = typename std::conditional<
std::is_array<typename std::remove_reference<T>::type>::value,
typename std::remove_cv<T>::type,
typename std::conditional<std::is_lvalue_reference<T>::value, T,
typename std::decay<T>::type>::type>::type;
// prevent nested nvps
static_assert(!std::is_base_of<detail::NameValuePairCore, T>::value,
"Cannot pair a name to a NameValuePair");
public:
//! Constructs a new NameValuePair
/*! @param n The name of the pair
@param v The value to pair. Ideally this should be an l-value reference so that
the value can be both loaded and saved to. If you pass an r-value
reference, the NameValuePair will store a copy of it instead of a reference. Thus
you should only pass r-values in cases where this makes sense, such as the result
of some size() call.
@internal */
NameValuePair(char const* n, T&& v)
: name(n)
, value(std::forward<T>(v))
{}
NameValuePair& operator=(NameValuePair const&) = delete;
char const* name; // NOLINT(misc-non-private-member-variables-in-classes)
Type value; // NOLINT(misc-non-private-member-variables-in-classes)
};
//! A specialization of make_nvp<> that simply forwards the value for binary archives
/*! @relates NameValuePair
@internal */
template <class Archive, class T>
inline typename std::enable_if<
std::is_same<Archive, ::tim::cereal::BinaryInputArchive>::value ||
std::is_same<Archive, ::tim::cereal::BinaryOutputArchive>::value,
T&&>::type
make_nvp(const char*, T&& value)
{
return std::forward<T>(value);
}
//! A specialization of make_nvp<> that actually creates an nvp for non-binary archives
/*! @relates NameValuePair
@internal */
template <class Archive, class T>
inline typename std::enable_if<
!std::is_same<Archive, ::tim::cereal::BinaryInputArchive>::value &&
!std::is_same<Archive, ::tim::cereal::BinaryOutputArchive>::value,
NameValuePair<T>>::type
make_nvp(const char* name, T&& value)
{
return { name, std::forward<T>(value) };
}
//! Convenience for creating a templated NVP
/*! For use in internal generic typing functions which have an
Archive type declared
@internal */
#define TIMEMORY_CEREAL_NVP_(name, value) ::tim::cereal::make_nvp<Archive>(name, value)
// ######################################################################
//! A wrapper around data that can be serialized in a binary fashion
/*! This class is used to demarcate data that can safely be serialized
as a binary chunk of data. Individual archives can then choose how
best represent this during serialization.
@internal */
template <class T>
struct BinaryData
{
//! Internally store the pointer as a void *, keeping const if created with
//! a const pointer
using PT = typename std::conditional<
std::is_const<typename std::remove_pointer<
typename std::remove_reference<T>::type>::type>::value,
const void*, void*>::type;
BinaryData(T&& d, uint64_t s)
: data(std::forward<T>(d))
, size(s)
{}
// NOLINTNEXTLINE
PT data; //!< pointer to beginning of data
// NOLINTNEXTLINE
uint64_t size; //!< size in bytes
};
// ######################################################################
//! A wrapper around data that should be serialized after all non-deferred data
/*! This class is used to demarcate data that can only be safely serialized after
any data not wrapped in this class.
@internal */
template <class T>
class DeferredData : detail::DeferredDataCore
{
private:
// If we get passed an array, keep the type as is, otherwise store
// a reference if we were passed an l value reference, else copy the value
using Type = typename std::conditional<
std::is_array<typename std::remove_reference<T>::type>::value,
typename std::remove_cv<T>::type,
typename std::conditional<std::is_lvalue_reference<T>::value, T,
typename std::decay<T>::type>::type>::type;
// prevent nested nvps
static_assert(!std::is_base_of<detail::DeferredDataCore, T>::value,
"Cannot defer DeferredData");
public:
//! Constructs a new NameValuePair
/*! @param v The value to defer. Ideally this should be an l-value reference so that
the value can be both loaded and saved to. If you pass an r-value
reference, the DeferredData will store a copy of it instead of a reference. Thus
you should only pass r-values in cases where this makes sense, such as the result
of some size() call.
@internal */
DeferredData(T&& v)
: value(std::forward<T>(v))
{}
DeferredData& operator=(DeferredData const&) = delete;
Type value; // NOLINT
};
// ######################################################################
namespace detail
{
// base classes for type checking
/* The rtti virtual function only exists to enable an archive to
be used in a polymorphic fashion, if necessary. See the
archive adapters for an example of this */
class OutputArchiveBase
{
public:
OutputArchiveBase() = default;
OutputArchiveBase(OutputArchiveBase&&) TIMEMORY_CEREAL_NOEXCEPT {}
OutputArchiveBase& operator=(OutputArchiveBase&&) TIMEMORY_CEREAL_NOEXCEPT
{
return *this;
}
virtual ~OutputArchiveBase() TIMEMORY_CEREAL_NOEXCEPT = default;
private:
virtual void rtti() {}
};
class InputArchiveBase
{
public:
InputArchiveBase() = default;
InputArchiveBase(InputArchiveBase&&) TIMEMORY_CEREAL_NOEXCEPT {}
InputArchiveBase& operator=(InputArchiveBase&&) TIMEMORY_CEREAL_NOEXCEPT
{
return *this;
}
virtual ~InputArchiveBase() TIMEMORY_CEREAL_NOEXCEPT = default;
private:
virtual void rtti() {}
};
// forward decls for polymorphic support
template <class Archive, class T>
struct polymorphic_serialization_support;
struct adl_tag;
// used during saving pointers
static const uint32_t msb_32bit = 0x80000000;
static const int32_t msb2_32bit = 0x40000000;
} // namespace detail
// ######################################################################
//! A wrapper around size metadata
/*! This class provides a way for archives to have more flexibility over how
they choose to serialize size metadata for containers. For some archive
types, the size may be implicitly encoded in the output (e.g. JSON) and
not need an explicit entry. Specializing serialize or load/save for
your archive and SizeTags allows you to choose what happens.
@internal */
template <class T>
class SizeTag
{
private:
// Store a reference if passed an lvalue reference, otherwise
// make a copy of the data
using Type = typename std::conditional<std::is_lvalue_reference<T>::value, T,
typename std::decay<T>::type>::type;
public:
SizeTag(T&& sz)
: size(std::forward<T>(sz))
{}
SizeTag& operator=(SizeTag const&) = delete;
Type size; // NOLINT
};
// ######################################################################
//! A wrapper around a key and value for serializing data into maps.
/*! This class just provides a grouping of keys and values into a struct for
human readable archives. For example, XML archives will use this wrapper
to write maps like so:
@code{.xml}
<mymap>
<item0>
<key>MyFirstKey</key>
<value>MyFirstValue</value>
</item0>
<item1>
<key>MySecondKey</key>
<value>MySecondValue</value>
</item1>
</mymap>
@endcode
\sa make_map_item
@internal */
template <class Key, class Value>
struct MapItem
{
using KeyType = typename std::conditional<std::is_lvalue_reference<Key>::value, Key,
typename std::decay<Key>::type>::type;
using ValueType =
typename std::conditional<std::is_lvalue_reference<Value>::value, Value,
typename std::decay<Value>::type>::type;
//! Construct a MapItem from a key and a value
/*! @internal */
MapItem(Key&& key_, Value&& value_)
: key(std::forward<Key>(key_))
, value(std::forward<Value>(value_))
{}
MapItem& operator=(MapItem const&) = delete;
KeyType key; // NOLINT
ValueType value; // NOLINT
//! Serialize the MapItem with the NVPs "key" and "value"
template <class Archive>
inline void TIMEMORY_CEREAL_SERIALIZE_FUNCTION_NAME(Archive& archive)
{
archive(make_nvp<Archive>("key", key), make_nvp<Archive>("value", value));
}
};
//! Create a MapItem so that human readable archives will group keys and values together
/*! @internal
@relates MapItem */
template <class KeyType, class ValueType>
inline MapItem<KeyType, ValueType>
make_map_item(KeyType&& key, ValueType&& value)
{
return { std::forward<KeyType>(key), std::forward<ValueType>(value) };
}
namespace detail
{
//! Tag for Version, which due to its anonymous namespace, becomes a different
//! type in each translation unit
/*! This allows TIMEMORY_CEREAL_CLASS_VERSION to be safely called in a header file */
namespace
{
struct version_binding_tag
{};
} // namespace
// ######################################################################
//! Static Version information class
/*! This is the base case for classes that have not been explicitly
registered */
template <class T>
struct StaticVersion
{
static constexpr std::uint32_t version = 0;
};
/*
// ######################################################################
/// Version information class
/// This is the base case for classes that have not been explicitly
/// registered
template <class T, class BindingTag = version_binding_tag>
struct Version
{
static const std::uint32_t version = 0;
// we don't need to explicitly register these types since they
// always get a version number of 0
};
/// Holds all registered version information
struct Versions
{
std::unordered_map<std::size_t, std::uint32_t> mapping;
std::uint32_t find(std::size_t hash, std::uint32_t version)
{
const auto result = mapping.emplace(hash, version);
return result.first->second;
}
}; // struct Versions
*/
} // namespace detail
} // namespace cereal
} // namespace tim
#endif // TIMEMORY_CEREAL_DETAILS_HELPERS_HPP_
+69
Просмотреть файл
@@ -0,0 +1,69 @@
/*! \file polymorphic_impl_fwd.hpp
\brief Internal polymorphism support forward declarations
\ingroup Internal */
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of cereal nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* This code is heavily inspired by the boost serialization implementation by the
following authors
(C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)
See http://www.boost.org for updates, documentation, and revision history.
(C) Copyright 2006 David Abrahams - http://www.boost.org.
See /boost/serialization/export.hpp and /boost/archive/detail/register_archive.hpp for
their implementation.
*/
#ifndef TIMEMORY_CEREAL_DETAILS_POLYMORPHIC_IMPL_FWD_HPP_
#define TIMEMORY_CEREAL_DETAILS_POLYMORPHIC_IMPL_FWD_HPP_
namespace tim
{
namespace cereal
{
namespace detail
{
//! Forward declaration, see polymorphic_impl.hpp for more information
template <class Base, class Derived>
struct RegisterPolymorphicCaster;
//! Forward declaration, see polymorphic_impl.hpp for more information
struct PolymorphicCasters;
//! Forward declaration, see polymorphic_impl.hpp for more information
template <class Base, class Derived>
struct PolymorphicRelation;
} // namespace detail
} // namespace cereal
} // namespace tim
#endif // TIMEMORY_CEREAL_DETAILS_POLYMORPHIC_IMPL_FWD_HPP_
+124
Просмотреть файл
@@ -0,0 +1,124 @@
/*! \file static_object.hpp
\brief Internal polymorphism static object support
\ingroup Internal */
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of cereal nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TIMEMORY_CEREAL_DETAILS_STATIC_OBJECT_HPP_
#define TIMEMORY_CEREAL_DETAILS_STATIC_OBJECT_HPP_
#include "timemory/tpls/cereal/cereal/macros.hpp"
#include <mutex>
//! Prevent link optimization from removing non-referenced static objects
/*! Especially for polymorphic support, we create static objects which
may not ever be explicitly referenced. Most linkers will detect this
and remove the code causing various unpleasant runtime errors. These
macros, adopted from Boost (see force_include.hpp) prevent this
(C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
Use, modification and distribution is subject to the Boost Software
License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt) */
#if !defined(TIMEMORY_CEREAL_DLL_EXPORT)
# ifdef _MSC_VER
# define TIMEMORY_CEREAL_DLL_EXPORT __declspec(dllexport)
# else // clang or gcc
# define TIMEMORY_CEREAL_DLL_EXPORT __attribute__((visibility("default")))
# endif
#endif
#if !defined(TIMEMORY_CEREAL_USED)
# ifdef _MSC_VER
# define TIMEMORY_CEREAL_USED
# else // clang or gcc
# define TIMEMORY_CEREAL_USED __attribute__((__used__))
# endif
#endif
namespace tim
{
namespace cereal
{
namespace detail
{
//! A static, pre-execution object
/*! This class will create a single copy (singleton) of some
type and ensures that merely referencing this type will
cause it to be instantiated and initialized pre-execution.
For example, this is used heavily in the polymorphic pointer
serialization mechanisms to bind various archive types with
different polymorphic classes */
template <class T>
class TIMEMORY_CEREAL_DLL_EXPORT StaticObject
{
private:
static T& create()
{
static T t;
//! Forces instantiation at pre-execution time
(void) instance;
return t;
}
StaticObject(StaticObject const& /*other*/) = default;
public:
static T& getInstance() { return create(); }
//! A class that acts like std::lock_guard
class LockGuard
{
public:
LockGuard(std::mutex& m)
: lock(m)
{}
private:
std::unique_lock<std::mutex> lock;
};
//! Attempts to lock this static object for the current scope
/*!
This function returns an object that holds a lock for
this StaticObject that will release its lock upon destruction. This
call will block until the lock is available. */
static LockGuard lock()
{
static std::mutex instanceMutex;
return LockGuard{ instanceMutex };
}
private:
static T& instance;
};
template <class T>
T& StaticObject<T>::instance = StaticObject<T>::create();
} // namespace detail
} // namespace cereal
} // namespace tim
#endif // TIMEMORY_CEREAL_DETAILS_STATIC_OBJECT_HPP_
Разница между файлами не показана из-за своего большого размера Загрузить разницу
+143
Просмотреть файл
@@ -0,0 +1,143 @@
/*! \file macros.hpp
\brief Preprocessor macros that can customise the cereal library
By default, cereal looks for serialization functions with very
specific names, that is: serialize, load, save, load_minimal,
or save_minimal.
This file allows an advanced user to change these names to conform
to some other style or preference. This is implemented using
preprocessor macros.
As a result of this, in internal cereal code you will see macros
used for these function names. In user code, you should name
the functions like you normally would and not use the macros
to improve readability.
\ingroup utility */
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of cereal nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TIMEMORY_CEREAL_MACROS_HPP_
#define TIMEMORY_CEREAL_MACROS_HPP_
#ifndef TIMEMORY_CEREAL_SIZE_TYPE
//! Determines the data type used for size_type
/*! cereal uses size_type to ensure that the serialized size of
dynamic containers is compatible across different architectures
(e.g. 32 vs 64 bit), which may use different underlying types for
std::size_t.
More information can be found in cereal/details/helpers.hpp.
If you choose to modify this type, ensure that you use a fixed
size type (e.g. uint32_t). */
# define TIMEMORY_CEREAL_SIZE_TYPE uint64_t
#endif // TIMEMORY_CEREAL_SIZE_TYPE
// ######################################################################
#ifndef TIMEMORY_CEREAL_SERIALIZE_FUNCTION_NAME
//! The serialization/deserialization function name to search for.
/*! You can define @c TIMEMORY_CEREAL_SERIALIZE_FUNCTION_NAME to be different assuming
you do so before this file is included. */
# define TIMEMORY_CEREAL_SERIALIZE_FUNCTION_NAME serialize
#endif // TIMEMORY_CEREAL_SERIALIZE_FUNCTION_NAME
#ifndef TIMEMORY_CEREAL_LOAD_FUNCTION_NAME
//! The deserialization (load) function name to search for.
/*! You can define @c TIMEMORY_CEREAL_LOAD_FUNCTION_NAME to be different assuming you do
so before this file is included. */
# define TIMEMORY_CEREAL_LOAD_FUNCTION_NAME load
#endif // TIMEMORY_CEREAL_LOAD_FUNCTION_NAME
#ifndef TIMEMORY_CEREAL_SAVE_FUNCTION_NAME
//! The serialization (save) function name to search for.
/*! You can define @c TIMEMORY_CEREAL_SAVE_FUNCTION_NAME to be different assuming you do
so before this file is included. */
# define TIMEMORY_CEREAL_SAVE_FUNCTION_NAME save
#endif // TIMEMORY_CEREAL_SAVE_FUNCTION_NAME
#ifndef TIMEMORY_CEREAL_LOAD_MINIMAL_FUNCTION_NAME
//! The deserialization (load_minimal) function name to search for.
/*! You can define @c TIMEMORY_CEREAL_LOAD_MINIMAL_FUNCTION_NAME to be different assuming
you do so before this file is included. */
# define TIMEMORY_CEREAL_LOAD_MINIMAL_FUNCTION_NAME load_minimal
#endif // TIMEMORY_CEREAL_LOAD_MINIMAL_FUNCTION_NAME
#ifndef TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME
//! The serialization (save_minimal) function name to search for.
/*! You can define @c TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME to be different assuming
you do so before this file is included. */
# define TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME save_minimal
#endif // TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME
// ######################################################################
//! Defines the TIMEMORY_CEREAL_NOEXCEPT macro to use instead of noexcept
/*! If a compiler we support does not support noexcept, this macro
will detect this and define TIMEMORY_CEREAL_NOEXCEPT as a no-op
@internal */
#if !defined(TIMEMORY_CEREAL_HAS_NOEXCEPT)
# if defined(__clang__)
# if __has_feature(cxx_noexcept)
# define TIMEMORY_CEREAL_HAS_NOEXCEPT
# endif
# else // NOT clang
# if defined(__GXX_EXPERIMENTAL_CXX0X__) && \
__GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
# define TIMEMORY_CEREAL_HAS_NOEXCEPT
# endif // end GCC/MSVC check
# endif // end NOT clang block
# ifndef TIMEMORY_CEREAL_NOEXCEPT
# ifdef TIMEMORY_CEREAL_HAS_NOEXCEPT
# define TIMEMORY_CEREAL_NOEXCEPT noexcept
# else
# define TIMEMORY_CEREAL_NOEXCEPT
# endif // end TIMEMORY_CEREAL_HAS_NOEXCEPT
# endif // end !defined(TIMEMORY_CEREAL_HAS_NOEXCEPT)
#endif // ifndef TIMEMORY_CEREAL_NOEXCEPT
// ######################################################################
//! Checks if C++17 is available
#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
# define TIMEMORY_CEREAL_HAS_CPP17
#endif
//! Checks if C++14 is available
#if __cplusplus >= 201402L
# define TIMEMORY_CEREAL_HAS_CPP14
#endif
// ######################################################################
//! Defines the TIMEMORY_CEREAL_ALIGNOF macro to use instead of alignof
#if defined(_MSC_VER) && _MSC_VER < 1900
# define TIMEMORY_CEREAL_ALIGNOF __alignof
#else // not MSVC 2013 or older
# define TIMEMORY_CEREAL_ALIGNOF alignof
#endif // end MSVC check
#endif // TIMEMORY_CEREAL_MACROS_HPP_
+168
Просмотреть файл
@@ -0,0 +1,168 @@
/*! \file specialize.hpp
\brief Serialization disambiguation */
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of cereal nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TIMEMORY_CEREAL_SPECIALIZE_HPP_
#define TIMEMORY_CEREAL_SPECIALIZE_HPP_
namespace tim
{
namespace cereal
{
// Forward declaration of access class that users can become friends with
class access;
// ######################################################################
//! A specifier used in conjunction with cereal::specialize to disambiguate
//! serialization in special cases
/*! @relates specialize
@ingroup Access */
enum class specialization
{
member_serialize, //!< Force the use of a member serialize function
member_load_save, //!< Force the use of a member load/save pair
member_load_save_minimal, //!< Force the use of a member minimal load/save pair
non_member_serialize, //!< Force the use of a non-member serialize function
non_member_load_save, //!< Force the use of a non-member load/save pair
non_member_load_save_minimal //!< Force the use of a non-member minimal load/save
//!< pair
};
//! A class used to disambiguate cases where cereal cannot detect a unique way of
//! serializing a class
/*! cereal attempts to figure out which method of serialization (member vs. non-member
serialize or load/save pair) at compile time. If for some reason cereal cannot find a
non-ambiguous way of serializing a type, it will produce a static assertion complaining
about this.
This can happen because you have both a serialize and load/save pair, or even because
a base class has a serialize (public or private with friend access) and a derived class
does not overwrite this due to choosing some other serialization type.
Specializing this class will tell cereal to explicitly use the serialization type you
specify and it will not complain about ambiguity in its compile time selection.
However, if cereal detects an ambiguity in specializations, it will continue to issue a
static assertion.
@code{.cpp}
class MyParent
{
friend class cereal::access;
template <class Archive>
void serialize( Archive & ar ) {}
};
// Although serialize is private in MyParent, to cereal::access it will look public,
// even through MyDerived
class MyDerived : public MyParent
{
public:
template <class Archive>
void load( Archive & ar ) {}
template <class Archive>
void save( Archive & ar ) {}
};
// The load/save pair in MyDerived is ambiguous because serialize in MyParent can
// be accessed from cereal::access. This looks the same as making serialize public
// in MyParent, making it seem as though MyDerived has both a serialize and a
load/save pair.
// cereal will complain about this at compile time unless we disambiguate:
namespace cereal
{
// This struct specialization will tell cereal which is the right way to serialize
the ambiguity template <class Archive> struct specialize<Archive, MyDerived,
cereal::specialization::member_load_save> {};
// If we only had a disambiguation for a specific archive type, it would look
something like this template <> struct specialize<cereal::BinaryOutputArchive,
MyDerived, cereal::specialization::member_load_save> {};
}
@endcode
You can also choose to use the macros TIMEMORY_CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES or
TIMEMORY_CEREAL_SPECIALIZE_FOR_ARCHIVE if you want to type a little bit less.
@tparam T The type to specialize the serialization for
@tparam S The specialization type to use for T
@ingroup Access */
template <class Archive, class T, specialization S>
struct specialize : public std::false_type
{};
//! Convenient macro for performing specialization for all archive types
/*! This performs specialization for the specific type for all types of archives.
This macro should be placed at the global namespace.
@code{cpp}
struct MyType {};
TIMEMORY_CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( MyType,
cereal::specialization::member_load_save
);
@endcode
@relates specialize
@ingroup Access */
#define TIMEMORY_CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES(Type, Specialization) \
namespace tim \
{ \
namespace cereal \
{ \
template <class Archive> \
struct specialize<Archive, Type, Specialization> \
{}; \
} \
}
//! Convenient macro for performing specialization for a single archive type
/*! This performs specialization for the specific type for a single type of archive.
This macro should be placed at the global namespace.
@code{cpp}
struct MyType {};
TIMEMORY_CEREAL_SPECIALIZE_FOR_ARCHIVE( cereal::XMLInputArchive, MyType,
cereal::specialization::member_load_save );
@endcode
@relates specialize
@ingroup Access */
#define TIMEMORY_CEREAL_SPECIALIZE_FOR_ARCHIVE(Archive, Type, Specialization) \
namespace tim \
{ \
namespace cereal \
{ \
template <> \
struct specialize<Archive, Type, Specialization> \
{}; \
} \
}
} // namespace cereal
} // namespace tim
#endif
+217
Просмотреть файл
@@ -0,0 +1,217 @@
/*! \file base_class.hpp
\brief Support for base classes (virtual and non-virtual)
\ingroup OtherTypes */
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of cereal nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TIMEMORY_CEREAL_TYPES_BASE_CLASS_HPP_
#define TIMEMORY_CEREAL_TYPES_BASE_CLASS_HPP_
#include "timemory/tpls/cereal/cereal/details/polymorphic_impl_fwd.hpp"
#include "timemory/tpls/cereal/cereal/details/traits.hpp"
namespace tim
{
namespace cereal
{
namespace base_class_detail
{
//! Used to register polymorphic relations and avoid the need to include
//! polymorphic.hpp when no polymorphism is used
/*! @internal */
template <class Base, class Derived,
bool IsPolymorphic = std::is_polymorphic<Base>::value>
struct RegisterPolymorphicBaseClass
{
static void bind() {}
};
//! Polymorphic version
/*! @internal */
template <class Base, class Derived>
struct RegisterPolymorphicBaseClass<Base, Derived, true>
{
static void bind() { detail::RegisterPolymorphicCaster<Base, Derived>::bind(); }
};
} // namespace base_class_detail
//! Casts a derived class to its non-virtual base class in a way that safely supports
//! abstract classes
/*! This should be used in cases when a derived type needs to serialize its base type.
This is better than directly using static_cast, as it allows for serialization of pure
virtual (abstract) base classes.
This also automatically registers polymorphic relation between the base and derived
class, assuming they are indeed polymorphic. Note this is not the same as polymorphic
type registration. For more information see the documentation on polymorphism. If using
a polymorphic class, be sure to include support for polymorphism
(cereal/types/polymorphic.hpp).
\sa virtual_base_class
@code{.cpp}
struct MyBase
{
int x;
virtual void foo() = 0;
template <class Archive>
void serialize( Archive & ar )
{
ar( x );
}
};
struct MyDerived : public MyBase //<-- Note non-virtual inheritance
{
int y;
virtual void foo() {};
template <class Archive>
void serialize( Archive & ar )
{
ar( cereal::base_class<MyBase>(this) );
ar( y );
}
};
@endcode */
template <class Base>
struct base_class : private traits::detail::BaseCastBase
{
template <class Derived>
base_class(Derived const* derived)
: base_ptr(const_cast<Base*>(static_cast<Base const*>(derived)))
{
static_assert(std::is_base_of<Base, Derived>::value,
"Can only use base_class on a valid base class");
base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind();
}
Base* base_ptr;
};
//! Casts a derived class to its virtual base class in a way that allows cereal to track
//! inheritance
/*! This should be used in cases when a derived type features virtual inheritance from
some base type. This allows cereal to track the inheritance and to avoid making
duplicate copies during serialization.
It is safe to use virtual_base_class in all circumstances for serializing base
classes, even in cases where virtual inheritance does not take place, though it may be
slightly faster to utilize cereal::base_class<> if you do not need to worry about
virtual inheritance.
This also automatically registers polymorphic relation between the base and derived
class, assuming they are indeed polymorphic. Note this is not the same as polymorphic
type registration. For more information see the documentation on polymorphism. If using
a polymorphic class, be sure to include support for polymorphism
(cereal/types/polymorphic.hpp).
\sa base_class
@code{.cpp}
struct MyBase
{
int x;
template <class Archive>
void serialize( Archive & ar )
{
ar( x );
}
};
struct MyLeft : virtual MyBase //<-- Note the virtual inheritance
{
int y;
template <class Archive>
void serialize( Archive & ar )
{
ar( cereal::virtual_base_class<MyBase>( this ) );
ar( y );
}
};
struct MyRight : virtual MyBase
{
int z;
template <class Archive>
void serialize( Archive & ar )
{
ar( cereal::virtual_base_clas<MyBase>( this ) );
ar( z );
}
};
// diamond virtual inheritance; contains one copy of each base class
struct MyDerived : virtual MyLeft, virtual MyRight
{
int a;
template <class Archive>
void serialize( Archive & ar )
{
ar( cereal::virtual_base_class<MyLeft>( this ) ); // safely serialize data
members in MyLeft ar( cereal::virtual_base_class<MyRight>( this ) ); // safely
serialize data members in MyRight ar( a );
// Because we used virtual_base_class, cereal will ensure that only one instance
of MyBase is
// serialized as we traverse the inheritance heirarchy. This means that there will
be one copy
// each of the variables x, y, z, and a
// If we had chosen to use static_cast<> instead, cereal would perform no tracking
and
// assume that every base class should be serialized (in this case leading to a
duplicate
// serialization of MyBase due to diamond inheritance
};
}
@endcode */
template <class Base>
struct virtual_base_class : private traits::detail::BaseCastBase
{
template <class Derived>
virtual_base_class(Derived const* derived)
: base_ptr(const_cast<Base*>(static_cast<Base const*>(derived)))
{
static_assert(std::is_base_of<Base, Derived>::value,
"Can only use virtual_base_class on a valid base class");
base_class_detail::RegisterPolymorphicBaseClass<Base, Derived>::bind();
}
Base* base_ptr;
};
} // namespace cereal
} // namespace tim
#endif // TIMEMORY_CEREAL_TYPES_BASE_CLASS_HPP_
+143
Просмотреть файл
@@ -0,0 +1,143 @@
/*! \file common.hpp
\brief Support common types - always included automatically
\ingroup OtherTypes */
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of cereal nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TIMEMORY_CEREAL_TYPES_COMMON_HPP_
#define TIMEMORY_CEREAL_TYPES_COMMON_HPP_
#include "timemory/tpls/cereal/cereal/cereal.hpp"
namespace tim
{
namespace cereal
{
namespace common_detail
{
//! Serialization for arrays if BinaryData is supported and we are arithmetic
/*! @internal */
template <class Archive, class T>
inline void
serializeArray(Archive& ar, T& array, std::true_type /* binary_supported */)
{
ar(binary_data(array, sizeof(array)));
}
//! Serialization for arrays if BinaryData is not supported or we are not arithmetic
/*! @internal */
template <class Archive, class T>
inline void
serializeArray(Archive& ar, T& array, std::false_type /* binary_supported */)
{
for(auto& i : array)
ar(i);
}
namespace
{
//! Gets the underlying type of an enum
/*! @internal */
template <class T, bool IsEnum>
struct enum_underlying_type : std::false_type
{};
//! Gets the underlying type of an enum
/*! Specialization for when we actually have an enum
@internal */
template <class T>
struct enum_underlying_type<T, true>
{
using type = typename std::underlying_type<T>::type;
};
} // namespace
//! Checks if a type is an enum
/*! This is needed over simply calling std::is_enum because the type
traits checking at compile time will attempt to call something like
load_minimal with a special NoConvertRef struct that wraps up the true type.
This will strip away any of that and also expose the true underlying type.
@internal */
template <class T>
class is_enum
{
private:
using DecayedT = typename std::decay<T>::type;
using StrippedT = typename ::tim::cereal::traits::strip_minimal<DecayedT>::type;
public:
static const bool value = std::is_enum<StrippedT>::value;
using type = StrippedT;
using base_type = typename enum_underlying_type<StrippedT, value>::type;
};
} // namespace common_detail
//! Saving for enum types
template <class Archive, class T>
inline typename std::enable_if<common_detail::is_enum<T>::value,
typename common_detail::is_enum<T>::base_type>::type
TIMEMORY_CEREAL_SAVE_MINIMAL_FUNCTION_NAME(Archive const&, T const& t)
{
return static_cast<typename common_detail::is_enum<T>::base_type>(t);
}
//! Loading for enum types
template <class Archive, class T>
inline typename std::enable_if<common_detail::is_enum<T>::value, void>::type
TIMEMORY_CEREAL_LOAD_MINIMAL_FUNCTION_NAME(
Archive const&, T&& t, typename common_detail::is_enum<T>::base_type const& value)
{
t = reinterpret_cast<typename common_detail::is_enum<T>::type const&>(value);
}
//! Serialization for raw pointers
/*! This exists only to throw a static_assert to let users know we don't support raw
* pointers. */
template <class Archive, class T>
inline void
TIMEMORY_CEREAL_SERIALIZE_FUNCTION_NAME(Archive&, T*&)
{
static_assert(
cereal::traits::detail::delay_static_assert<T>::value,
"Cereal does not support serializing raw pointers - please use a smart pointer");
}
//! Serialization for C style arrays
template <class Archive, class T>
inline typename std::enable_if<std::is_array<T>::value, void>::type
TIMEMORY_CEREAL_SERIALIZE_FUNCTION_NAME(Archive& ar, T& array)
{
common_detail::serializeArray(
ar, array, std::integral_constant < bool,
traits::is_output_serializable<BinaryData<T>, Archive>::value&&
std::is_arithmetic<typename std::remove_all_extents<T>::type>::value >
());
}
} // namespace cereal
} // namespace tim
#endif // TIMEMORY_CEREAL_TYPES_COMMON_HPP_
+706
Просмотреть файл
@@ -0,0 +1,706 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#ifndef TIMEMORY_UTILITY_ARGPARSE_CPP_
#define TIMEMORY_UTILITY_ARGPARSE_CPP_
#include "timemory/utility/macros.hpp"
#if !defined(TIMEMORY_UTILITY_HEADER_MODE)
# include "timemory/utility/argparse.hpp"
#endif
namespace tim
{
namespace argparse
{
TIMEMORY_UTILITY_INLINE
argument_vector::argument_vector(int& argc, char**& argv)
: base_type()
{
reserve(argc);
for(int i = 0; i < argc; ++i)
push_back(argv[i]);
}
TIMEMORY_UTILITY_INLINE
argument_vector::argument_vector(int& argc, const char**& argv)
: base_type()
{
reserve(argc);
for(int i = 0; i < argc; ++i)
push_back(argv[i]);
}
TIMEMORY_UTILITY_INLINE
argument_vector::argument_vector(int& argc, const char* const*& argv)
{
reserve(argc);
for(int i = 0; i < argc; ++i)
push_back(argv[i]);
}
TIMEMORY_UTILITY_INLINE argument_vector::cargs_t
argument_vector::get_execv(const base_type& _prepend, size_t _beg, size_t _end) const
{
std::stringstream cmdss;
// find the end if not specified
_end = std::min<size_t>(size(), _end);
// determine the number of arguments
auto _argc = (_end - _beg) + _prepend.size();
// create the new C argument array, add an extra entry at the end which will
// always be a null pointer because that is how execv determines the end
char** _argv = new char*[_argc + 1];
// ensure all arguments are null pointers initially
for(size_t i = 0; i < _argc + 1; ++i)
_argv[i] = nullptr;
// add the prepend list
size_t _idx = 0;
for(const auto& itr : _prepend)
_argv[_idx++] = helpers::strdup(itr.c_str());
// copy over the arguments stored internally from the range specified
for(auto i = _beg; i < _end; ++i)
_argv[_idx++] = helpers::strdup(this->at(i).c_str());
// add check that last argument really is a nullptr
assert(_argv[_argc] == nullptr);
// create the command string
for(size_t i = 0; i < _argc; ++i)
cmdss << " " << _argv[i];
auto cmd = cmdss.str().substr(1);
// return a new (int argc, char** argv) and subtract 1 bc nullptr in last entry
// does not count as argc
return cargs_t(_argc - 1, _argv, cmd);
}
TIMEMORY_UTILITY_INLINE argument_vector::cargs_t
argument_vector::get_execv(size_t _beg, size_t _end) const
{
return get_execv(base_type{}, _beg, _end);
}
TIMEMORY_UTILITY_INLINE void
argument_parser::print_help(const std::string& _extra)
{
std::stringstream _usage;
if(!m_desc.empty())
_usage << "[" << m_desc << "] ";
_usage << "Usage: " << m_bin;
std::cerr << _usage.str();
std::stringstream _sshort_desc;
auto _indent = _usage.str().length() + 2;
size_t _ncnt = 0;
for(auto& a : m_arguments)
{
std::string name = a.m_names.at(0);
if(name.empty() || name.find_first_of('-') > name.find_first_not_of(" -"))
continue;
// select the first long option
for(size_t n = 1; n < a.m_names.size(); ++n)
{
if(name.find("--") == 0)
break;
else if(a.m_names.at(n).find("--") == 0)
{
name = a.m_names.at(n);
break;
}
}
if(name.length() > 0)
{
if(_ncnt++ > 0)
_sshort_desc << "\n " << std::setw(_indent) << " " << name;
else
_sshort_desc << " " << name;
_sshort_desc << " (";
if(a.m_count != argument::Count::ANY)
_sshort_desc << "count: " << a.m_count;
else if(a.m_min_count != argument::Count::ANY)
_sshort_desc << "min: " << a.m_min_count;
else if(a.m_max_count != argument::Count::ANY)
_sshort_desc << "max: " << a.m_max_count;
else
_sshort_desc << "count: unlimited";
if(!a.m_dtype.empty())
_sshort_desc << ", dtype: " << a.m_dtype;
else if(a.m_count == 0 ||
(a.m_count == argument::Count::ANY && a.m_max_count == 1))
_sshort_desc << ", dtype: bool" << a.m_dtype;
_sshort_desc << ")";
}
}
std::string _short_desc;
if(!_sshort_desc.str().empty())
{
_short_desc.append("[" + _sshort_desc.str());
std::stringstream _tmp;
_tmp << "\n" << std::setw(_indent) << "]";
_short_desc.append(_tmp.str());
}
if(m_positional_arguments.empty())
{
std::cerr << " " << _short_desc << " " << _extra << std::endl;
}
else
{
std::cerr << " " << _short_desc;
if(!_short_desc.empty())
std::cerr << "\n" << std::setw(_indent - 2) << " ";
for(auto& itr : m_positional_arguments)
{
std::cerr << " " << helpers::ltrim(itr.m_names.at(0), [](int c) -> bool {
return c != static_cast<int>('-');
});
}
int current = 0;
for(auto& v : m_positional_map)
{
if(v.first != argument::Position::LastArgument)
{
for(; current < v.first; ++current)
std::cerr << " [" << current << "]";
std::cerr << " ["
<< helpers::ltrim(
m_arguments[static_cast<size_t>(v.second)].m_names.at(0),
[](int c) -> bool { return c != static_cast<int>('-'); })
<< "]";
}
else
{
std::cerr << " ... ["
<< helpers::ltrim(
m_arguments[static_cast<size_t>(v.second)].m_names.at(0),
[](int c) -> bool { return c != static_cast<int>('-'); })
<< "]";
}
}
std::cerr << " " << _extra << std::endl;
}
std::cerr << "\nOptions:" << std::endl;
for(auto& a : m_arguments)
{
std::string name = a.m_names.at(0);
for(size_t n = 1; n < a.m_names.size(); ++n)
name.append(", " + a.m_names[n]);
std::stringstream ss;
ss << name;
if(a.m_choices.size() > 0)
{
ss << " [";
auto itr = a.m_choices.begin();
ss << " " << *itr++;
for(; itr != a.m_choices.end(); ++itr)
ss << " | " << *itr;
ss << " ] ";
}
std::stringstream prefix;
prefix << " " << std::setw(m_width) << std::left << ss.str();
std::cerr << std::left << prefix.str();
auto desc = a.m_desc;
if(ss.str().length() >= static_cast<size_t>(m_width))
desc = std::string("\n%{NEWLINE}%") + desc;
{
// replace %{INDENT}% with indentation
const std::string indent_key = "%{INDENT}%";
const auto npos = std::string::npos;
auto pos = npos;
std::stringstream indent;
indent << std::setw(prefix.str().length()) << "";
while((pos = desc.find(indent_key)) != npos)
desc = desc.replace(pos, indent_key.length(), indent.str());
}
{
// replace %{NEWLINE}% with indentation
const std::string indent_key = "%{NEWLINE}%";
const auto npos = std::string::npos;
auto pos = npos;
std::stringstream indent;
indent << std::setw(m_width + 5) << "";
while((pos = desc.find(indent_key)) != npos)
desc = desc.replace(pos, indent_key.length(), indent.str());
}
std::cerr << " " << std::setw(m_width) << desc;
if(a.m_required)
std::cerr << " (Required)";
std::cerr << std::endl;
}
std::cerr << '\n';
}
TIMEMORY_UTILITY_INLINE argument_parser::arg_result
argument_parser::parse_known_args(int* argc, char*** argv, strvec_t& _args,
const std::string& _delim, int verbose_level)
{
// check for help flag
auto help_check = [&](int _argc, char** _argv) {
strset_t help_args = { "-h", "--help", "-?" };
auto _help_req = (exists("help") ||
(_argc > 1 && help_args.find(_argv[1]) != help_args.end()));
if(_help_req && !exists("help"))
{
for(auto hitr : help_args)
{
auto hstr = hitr.substr(hitr.find_first_not_of('-'));
auto itr = m_name_map.find(hstr);
if(itr != m_name_map.end())
m_arguments[static_cast<size_t>(itr->second)].m_found = true;
}
}
return _help_req;
};
// check for a dash in th command line
bool _pdash = false;
for(int i = 1; i < *argc; ++i)
{
if((*argv)[i] == std::string("--"))
_pdash = true;
}
// parse the known args and get the remaining argc/argv
auto _pargs = parse_known_args(*argc, *argv, _args, _delim, verbose_level);
auto _perrc = std::get<0>(_pargs);
auto _pargc = std::get<1>(_pargs);
auto _pargv = std::get<2>(_pargs);
// check if help was requested before the dash (if dash exists)
if(help_check((_pdash) ? 0 : _pargc, _pargv))
return arg_result{ "help requested" };
// assign the argc and argv
*argc = _pargc;
*argv = _pargv;
return _perrc;
}
TIMEMORY_UTILITY_INLINE argument_parser::known_args_t
argument_parser::parse_known_args(int argc, char** argv, strvec_t& _args,
const std::string& _delim, int verbose_level)
{
int _cmdc = argc; // the argc after known args removed
char** _cmdv = argv; // the argv after known args removed
// _cmdv and argv are same pointer unless delimiter is found
if(argc > 0)
{
m_bin = std::string((const char*) argv[0]);
_args.push_back(std::string((const char*) argv[0]));
}
for(int i = 1; i < argc; ++i)
{
std::string _arg = argv[i];
if(_arg == _delim)
{
_cmdc = argc - i;
_cmdv = new char*[_cmdc + 1];
_cmdv[_cmdc] = nullptr;
_cmdv[0] = helpers::strdup(argv[0]);
int k = 1;
for(int j = i + 1; j < argc; ++j, ++k)
_cmdv[k] = helpers::strdup(argv[j]);
break;
}
else
{
_args.push_back(std::string((const char*) argv[i]));
}
}
auto cmd_string = [](int _ac, char** _av) {
std::stringstream ss;
for(int i = 0; i < _ac; ++i)
ss << _av[i] << " ";
return ss.str();
};
if((_cmdc > 0 && verbose_level > 0) || verbose_level > 1)
std::cerr << "\n";
if(verbose_level > 1)
{
std::cerr << "[original]> " << cmd_string(argc, argv) << std::endl;
std::cerr << "[cfg-args]> ";
for(auto& itr : _args)
std::cerr << itr << " ";
std::cerr << std::endl;
}
if(_cmdc > 0 && verbose_level > 0)
std::cerr << "[command]> " << cmd_string(_cmdc, _cmdv) << "\n\n";
return known_args_t{ parse(_args, verbose_level), _cmdc, _cmdv };
}
TIMEMORY_UTILITY_INLINE argument_parser::arg_result
argument_parser::parse(const std::vector<std::string>& _args, int verbose_level)
{
if(verbose_level > 0)
{
std::cerr << "[argparse::parse]> parsing '";
for(const auto& itr : _args)
std::cerr << itr << " ";
std::cerr << "'" << '\n';
}
for(auto& a : m_arguments)
a.m_callback(a.m_default);
for(auto& a : m_positional_arguments)
a.m_callback(a.m_default);
using argmap_t = std::map<std::string, argument*>;
argmap_t m_arg_map = {};
arg_result err;
int argc = _args.size();
// the set of options which use a single leading dash but are longer than
// one character, e.g. -LS ...
std::set<std::string> long_short_opts;
if(_args.size() > 1)
{
auto is_leading_dash = [](int c) -> bool { return c != static_cast<int>('-'); };
// build name map
for(auto& a : m_arguments)
{
for(auto& n : a.m_names)
{
auto nleading_dash = helpers::lcount(n, is_leading_dash);
std::string name = helpers::ltrim(n, is_leading_dash);
if(name.empty())
continue;
if(m_name_map.find(name) != m_name_map.end())
return arg_result("Duplicate of argument name: " + n);
m_name_map[name] = a.m_index;
m_arg_map[name] = &a;
if(nleading_dash == 1 && name.length() > 1)
long_short_opts.insert(name);
}
if(a.m_position >= 0 || a.m_position == argument::Position::LastArgument)
m_positional_map.at(a.m_position) = a.m_index;
}
m_bin = _args.at(0);
// parse
std::string current_arg;
size_t arg_len;
for(int argv_index = 1; argv_index < argc; ++argv_index)
{
current_arg = _args.at(argv_index);
arg_len = current_arg.length();
if(arg_len == 0)
continue;
if(argv_index == argc - 1 &&
m_positional_map.find(argument::Position::LastArgument) !=
m_positional_map.end())
{
err = end_argument();
arg_result b = err;
err = add_value(current_arg, argument::Position::LastArgument);
if(b)
return b;
// return (m_error_func(*this, b), b);
if(err)
return (m_error_func(*this, err), err);
continue;
}
// count number of leading dashes
auto nleading_dash = helpers::lcount(current_arg, is_leading_dash);
// ignores the case if the arg is just a '-'
// look for -a (short) or --arg (long) args
bool is_arg = (nleading_dash > 0 && arg_len > 1 && arg_len != nleading_dash)
? true
: false;
if(is_arg && !helpers::is_numeric(current_arg))
{
err = end_argument();
if(err)
return (m_error_func(*this, err), err);
auto name = current_arg.substr(nleading_dash);
auto islong = (nleading_dash > 1 || long_short_opts.count(name) > 0);
err = begin_argument(name, islong, argv_index);
if(err)
return (m_error_func(*this, err), err);
}
else if(current_arg.length() > 0)
{
// argument value
err = add_value(current_arg, argv_index);
if(err)
return (m_error_func(*this, err), err);
}
}
}
// return the help
if(m_help_enabled && exists("help"))
return arg_result("help requested");
err = end_argument();
if(err)
return (m_error_func(*this, err), err);
// check requirements
for(auto& a : m_arguments)
{
if(a.m_required && !a.m_found)
{
return arg_result("Required argument not found: " + a.m_names.at(0));
}
if(a.m_position >= 0 && argc >= a.m_position && !a.m_found)
{
return arg_result("argument " + a.m_names.at(0) + " expected in position " +
std::to_string(a.m_position));
}
}
// check requirements
for(auto& a : m_positional_arguments)
{
if(a.m_required && !a.m_found)
return arg_result("Required argument not found: " + a.m_names.at(0));
}
// check all the counts have been satisfied
for(auto& a : m_arguments)
{
if(a.m_found && a.m_default == nullptr)
{
auto cnt_err = check_count(a);
if(cnt_err)
return cnt_err;
}
}
// execute the global actions
for(auto& itr : m_actions)
{
if(itr.first(*this))
itr.second(*this);
}
// execute the argument-specific actions
for(auto& itr : m_arg_map)
{
if(exists(itr.first))
itr.second->execute_actions(*this);
}
return arg_result{};
}
TIMEMORY_UTILITY_INLINE argument_parser::arg_result
argument_parser::begin_argument(const std::string& arg, bool longarg, int position)
{
auto it = m_positional_map.find(position);
if(it != m_positional_map.end())
{
arg_result err = end_argument();
argument& a = m_arguments[static_cast<size_t>(it->second)];
a.m_values.push_back(arg);
a.m_found = true;
return err;
}
if(m_current != -1)
{
return arg_result("Current argument left open");
}
size_t name_end = helpers::find_punct(arg);
std::string arg_name = arg.substr(0, name_end);
if(longarg)
{
int equal_pos = helpers::find_equiv(arg);
auto nmf = m_name_map.find(arg_name);
if(nmf == m_name_map.end())
{
arg_name = arg.substr(0, equal_pos);
nmf = m_name_map.find(arg_name);
}
if(nmf == m_name_map.end())
{
return arg_result("Unrecognized command line option '" + arg_name + "'");
}
m_current = nmf->second;
m_arguments[static_cast<size_t>(nmf->second)].m_found = true;
if(equal_pos == 0 || (equal_pos < 0 && arg_name.length() < arg.length()))
{
// malformed argument
return arg_result("Malformed argument: " + arg);
}
else if(equal_pos > 0)
{
std::string arg_value = arg.substr(name_end + 1);
add_value(arg_value, position);
}
}
else
{
arg_result r;
if(arg_name.length() == 1)
{
return begin_argument(arg, true, position);
}
else
{
for(char& c : arg_name)
{
r = begin_argument(std::string(1, c), true, position);
if(r)
{
return r;
}
r = end_argument();
if(r)
{
return r;
}
}
}
}
return arg_result{};
}
TIMEMORY_UTILITY_INLINE argument_parser::arg_result
argument_parser::add_value(const std::string& value, int location)
{
auto unnamed = [&]() {
auto itr = m_positional_map.find(location);
if(itr != m_positional_map.end())
{
argument& a = m_arguments[static_cast<size_t>(itr->second)];
a.m_values.push_back(value);
a.m_found = true;
}
else
{
auto idx = m_positional_values.size();
m_positional_values.emplace(idx, value);
if(idx < m_positional_arguments.size())
{
auto& a = m_positional_arguments.at(idx);
a.m_found = true;
auto err = a.check_choice(value);
if(err)
return err;
a.m_values.push_back(value);
a.execute_actions(*this);
}
}
return arg_result{};
};
if(m_current >= 0)
{
arg_result err;
size_t c = static_cast<size_t>(m_current);
consume_parameters(c);
argument& a = m_arguments[static_cast<size_t>(m_current)];
err = a.check_choice(value);
if(err)
return err;
auto num_values = [&]() { return static_cast<int>(a.m_values.size()); };
// check {m_count, m_max_count} > COUNT::ANY && m_values.size() >= {value}
if((a.m_count >= 0 && num_values() >= a.m_count) ||
(a.m_max_count >= 0 && num_values() >= a.m_max_count))
{
err = end_argument();
if(err)
return err;
return unnamed();
}
a.m_values.push_back(value);
// check {m_count, m_max_count} > COUNT::ANY && m_values.size() >= {value}
if((a.m_count >= 0 && num_values() >= a.m_count) ||
(a.m_max_count >= 0 && num_values() >= a.m_max_count))
{
err = end_argument();
if(err)
return err;
}
return arg_result{};
}
return unnamed();
}
TIMEMORY_UTILITY_INLINE argument_parser::arg_result
argument_parser::end_argument()
{
if(m_current >= 0)
{
argument& a = m_arguments[static_cast<size_t>(m_current)];
m_current = -1;
if(static_cast<int>(a.m_values.size()) < a.m_count)
return arg_result("Too few arguments given for " + a.m_names.at(0));
if(a.m_max_count >= 0)
{
if(static_cast<int>(a.m_values.size()) > a.m_max_count)
return arg_result("Too many arguments given for " + a.m_names.at(0));
}
else if(a.m_count >= 0)
{
if(static_cast<int>(a.m_values.size()) > a.m_count)
return arg_result("Too many arguments given for " + a.m_names.at(0));
}
}
return arg_result{};
}
TIMEMORY_UTILITY_INLINE std::ostream&
operator<<(std::ostream& os, const argument_parser::arg_result& r)
{
os << r.what();
return os;
}
} // namespace argparse
} // namespace tim
#endif
Разница между файлами не показана из-за своего большого размера Загрузить разницу
+205
Просмотреть файл
@@ -0,0 +1,205 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
/** \file timemory/utility/bits/macros.hpp
* \headerfile timemory/utility/bits/macros.hpp "timemory/utility/bits/macros.hpp"
* Deprecated macros
*/
//======================================================================================//
//
// ALL OF THESE MACROS ARE DEPRECATED!
//
//======================================================================================//
#pragma once
//======================================================================================//
//
// OBJECT MACROS
//
//======================================================================================//
/// \deprecated
#define TIMEMORY_BLANK_OBJECT(type, ...) TIMEMORY_BLANK_MARKER(type, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
/// \deprecated
#define TIMEMORY_BASIC_OBJECT(type, ...) TIMEMORY_BASIC_MARKER(type, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
/// \deprecated
#define TIMEMORY_OBJECT(type, ...) TIMEMORY_MARKER(type, __VA_ARGS__)
//======================================================================================//
//
// INSTANCE MACROS
//
//======================================================================================//
/// \deprecated
#define TIMEMORY_BLANK_INSTANCE(type, ...) TIMEMORY_BLANK_HANDLE(type, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
/// \deprecated
#define TIMEMORY_BASIC_INSTANCE(type, ...) TIMEMORY_BASIC_HANDLE(type, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
/// \deprecated
#define TIMEMORY_INSTANCE(type, ...) TIMEMORY_HANDLE(type, __VA_ARGS__)
//======================================================================================//
//
// AUTO_TUPLE MACROS
//
//======================================================================================//
// DEPRECATED use macros in timemory/variadic/macros.hpp!
/// \deprecated
#define TIMEMORY_BLANK_AUTO_TUPLE(auto_tuple_type, ...) \
TIMEMORY_BLANK_MARKER(auto_tuple_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_BASIC_AUTO_TUPLE(auto_tuple_type, ...) \
TIMEMORY_BASIC_MARKER(auto_tuple_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_AUTO_TUPLE(auto_tuple_type, ...) \
TIMEMORY_MARKER(auto_tuple_type, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
// caliper versions -- DEPRECATED use macros in timemory/variadic/macros.hpp!
/// \deprecated
#define TIMEMORY_BLANK_AUTO_TUPLE_CALIPER(id, auto_tuple_type, ...) \
TIMEMORY_BLANK_CALIPER(id, auto_tuple_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_BASIC_AUTO_TUPLE_CALIPER(id, auto_tuple_type, ...) \
TIMEMORY_BASIC_CALIPER(id, auto_tuple_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_AUTO_TUPLE_CALIPER(id, auto_tuple_type, ...) \
TIMEMORY_CALIPER(id, auto_tuple_type, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
// instance versions -- DEPRECATED use macros in timemory/variadic/macros.hpp!
/// \deprecated
#define TIMEMORY_BLANK_AUTO_TUPLE_INSTANCE(auto_tuple_type, ...) \
TIMEMORY_BLANK_HANDLE(auto_tuple_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_BASIC_AUTO_TUPLE_INSTANCE(auto_tuple_type, ...) \
TIMEMORY_BASIC_HANDLE(auto_tuple_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_AUTO_TUPLE_INSTANCE(auto_tuple_type, ...) \
TIMEMORY_HANDLE(auto_tuple_type, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
// debug versions -- DEPRECATED use macros in timemory/variadic/macros.hpp!
/// \deprecated
#define TIMEMORY_DEBUG_BASIC_AUTO_TUPLE(auto_tuple_type, ...) \
TIMEMORY_DEBUG_BASIC_MARKER(auto_tuple_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_DEBUG_AUTO_TUPLE(auto_tuple_type, ...) \
TIMEMORY_DEBUG_MARKER(auto_tuple_type, __VA_ARGS__)
//======================================================================================//
//
// AUTO_LIST MACROS
//
//======================================================================================//
/// \deprecated
#define TIMEMORY_BLANK_AUTO_LIST(auto_list_type, ...) \
TIMEMORY_BLANK_MARKER(auto_list_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_BASIC_AUTO_LIST(auto_list_type, ...) \
TIMEMORY_BASIC_MARKER(auto_list_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_AUTO_LIST(auto_list_type, ...) \
TIMEMORY_MARKER(auto_list_type, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
// caliper versions
/// \deprecated
#define TIMEMORY_BLANK_AUTO_LIST_CALIPER(id, auto_list_type, ...) \
TIMEMORY_BLANK_CALIPER(id, auto_list_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_BASIC_AUTO_LIST_CALIPER(id, auto_list_type, ...) \
TIMEMORY_BASIC_CALIPER(id, auto_list_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_AUTO_LIST_CALIPER(id, auto_list_type, ...) \
TIMEMORY_CALIPER(id, auto_list_type, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
// instance versions
/// \deprecated
#define TIMEMORY_BLANK_AUTO_LIST_INSTANCE(auto_list_type, ...) \
TIMEMORY_BLANK_HANDLE(auto_list_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_BASIC_AUTO_LIST_INSTANCE(auto_list_type, ...) \
TIMEMORY_BASIC_HANDLE(auto_list_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_AUTO_LIST_INSTANCE(auto_list_type, ...) \
TIMEMORY_HANDLE(auto_list_type, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
// debug versions
/// \deprecated
#define TIMEMORY_DEBUG_BASIC_AUTO_LIST(auto_list_type, ...) \
TIMEMORY_DEBUG_BASIC_MARKER(auto_list_type, __VA_ARGS__)
/// \deprecated
#define TIMEMORY_DEBUG_AUTO_LIST(auto_list_type, ...) \
TIMEMORY_DEBUG_MARKER(auto_list_type, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
/// \deprecated
#define TIMEMORY_CALIPER_MARK_STREAM_BEGIN(id, stream) \
TIMEMORY_CALIPER_APPLY(id, mark_begin, stream)
//--------------------------------------------------------------------------------------//
/// \deprecated
#define TIMEMORY_CALIPER_MARK_STREAM_END(id, stream) \
TIMEMORY_CALIPER_APPLY(id, mark_end, stream)
+305
Просмотреть файл
@@ -0,0 +1,305 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
//
#pragma once
#include "timemory/macros/attributes.hpp"
#include <cstdint>
#include <cstdio>
#include <iosfwd>
#include <string>
#include <utility>
#if defined(TIMEMORY_CORE_SOURCE)
# define TIMEMORY_UTILITY_SOURCE
#elif defined(TIMEMORY_USE_CORE_EXTERN)
# define TIMEMORY_USE_UTILITY_EXTERN
#endif
//
#if defined(TIMEMORY_USE_EXTERN) && !defined(TIMEMORY_USE_UTILITY_EXTERN)
# define TIMEMORY_USE_UTILITY_EXTERN
#endif
//======================================================================================//
//
// Quick way to create a globally accessible setting
//
//======================================================================================//
#if !defined(CREATE_STATIC_VARIABLE_ACCESSOR)
# define CREATE_STATIC_VARIABLE_ACCESSOR(TYPE, FUNC_NAME, VARIABLE) \
static TYPE& FUNC_NAME() \
{ \
static TYPE _instance = Type::VARIABLE; \
return _instance; \
}
#endif
//--------------------------------------------------------------------------------------//
#if !defined(CREATE_STATIC_FUNCTION_ACCESSOR)
# define CREATE_STATIC_FUNCTION_ACCESSOR(TYPE, FUNC_NAME, VARIABLE) \
static TYPE& FUNC_NAME() \
{ \
static TYPE _instance = Type::VARIABLE(); \
return _instance; \
}
#endif
//======================================================================================//
//
// DEBUG
//
//======================================================================================//
// stringify some macro -- uses TIMEMORY_STRINGIZE2 which does the actual
// "stringify-ing" after the macro has been substituted by it's result
#if !defined(TIMEMORY_STRINGIZE)
# define TIMEMORY_STRINGIZE(X) TIMEMORY_STRINGIZE2(X)
#endif
// actual stringifying
#if !defined(TIMEMORY_STRINGIZE2)
# define TIMEMORY_STRINGIZE2(X) # X
#endif
#if !defined(TIMEMORY_TRUNCATED_FILE_STRING)
# define TIMEMORY_TRUNCATED_FILE_STRING(FILE) \
[]() { \
std::string _f{ FILE }; \
auto _pos = _f.find("/timemory/"); \
if(_pos != std::string::npos) \
{ \
return _f.substr(_pos + 1); \
} \
return _f; \
}()
#endif
#if !defined(TIMEMORY_FILE_LINE_FUNC_STRING)
# define TIMEMORY_FILE_LINE_FUNC_STRING \
std::string \
{ \
std::string{ "[" } + TIMEMORY_TRUNCATED_FILE_STRING(__FILE__) + ":" + \
std::to_string(__LINE__) + "@'" + __FUNCTION__ + "']" \
}
#endif
#if !defined(TIMEMORY_PID_TID_STRING)
# define TIMEMORY_PID_TID_STRING \
std::string \
{ \
std::string{ "[pid=" } + std::to_string(::tim::process::get_id()) + \
std::string{ "][tid=" } + std::to_string(::tim::threading::get_id()) + \
"]" \
}
#endif
template <typename Arg>
TIMEMORY_NOINLINE auto
timemory_proxy_value(Arg&& arg, int) -> decltype(arg.proxy_value())
{
return arg.proxy_value();
}
template <typename Arg>
TIMEMORY_NOINLINE auto
timemory_proxy_value(Arg&& arg, long)
{
return std::forward<Arg>(arg);
}
template <typename... Args>
TIMEMORY_NOINLINE void
timemory_print_here(const char* _pid_tid, const char* _file, int _line, const char* _func,
Args&&... args)
{
fprintf(stderr, "%s[%s:%i@'%s']> ", _pid_tid, _file, _line, _func);
fprintf(stderr, timemory_proxy_value(std::forward<Args>(args), 0)...);
fprintf(stderr, "...\n");
fflush(stderr);
}
#if !defined(PRINT_HERE)
# define PRINT_HERE(...) \
timemory_print_here(TIMEMORY_PID_TID_STRING.c_str(), \
TIMEMORY_TRUNCATED_FILE_STRING(__FILE__).c_str(), __LINE__, \
__FUNCTION__, __VA_ARGS__)
#endif
#if !defined(DEBUG_PRINT_HERE)
# if defined(DEBUG)
# define DEBUG_PRINT_HERE(...) \
if(::tim::settings::debug()) \
{ \
timemory_print_here(TIMEMORY_PID_TID_STRING.c_str(), \
TIMEMORY_TRUNCATED_FILE_STRING(__FILE__).c_str(), \
__LINE__, __FUNCTION__, __VA_ARGS__); \
}
# else
# define DEBUG_PRINT_HERE(...)
# endif
#endif
#if !defined(VERBOSE_PRINT_HERE)
# define VERBOSE_PRINT_HERE(VERBOSE_LEVEL, ...) \
if(::tim::settings::verbose() >= VERBOSE_LEVEL) \
{ \
timemory_print_here(TIMEMORY_PID_TID_STRING.c_str(), \
TIMEMORY_TRUNCATED_FILE_STRING(__FILE__).c_str(), \
__LINE__, __FUNCTION__, __VA_ARGS__); \
}
#endif
#if !defined(CONDITIONAL_PRINT_HERE)
# define CONDITIONAL_PRINT_HERE(CONDITION, ...) \
if(CONDITION) \
{ \
timemory_print_here(TIMEMORY_PID_TID_STRING.c_str(), \
TIMEMORY_TRUNCATED_FILE_STRING(__FILE__).c_str(), \
__LINE__, __FUNCTION__, __VA_ARGS__); \
}
#endif
#if !defined(TIMEMORY_CONDITIONAL_BACKTRACE)
# define TIMEMORY_CONDITIONAL_BACKTRACE(CONDITION, DEPTH) \
if(CONDITION) \
{ \
::tim::print_backtrace<DEPTH>(std::cerr, TIMEMORY_PID_TID_STRING, \
TIMEMORY_FILE_LINE_FUNC_STRING); \
}
#endif
#if !defined(TIMEMORY_CONDITIONAL_DEMANGLED_BACKTRACE)
# define TIMEMORY_CONDITIONAL_DEMANGLED_BACKTRACE(CONDITION, DEPTH) \
if(CONDITION) \
{ \
::tim::print_demangled_backtrace<DEPTH>(std::cerr, TIMEMORY_PID_TID_STRING, \
TIMEMORY_FILE_LINE_FUNC_STRING); \
}
#endif
#if !defined(PRETTY_PRINT_HERE)
# if defined(TIMEMORY_GNU_COMPILER) || defined(TIMEMORY_CLANG_COMPILER)
# define PRETTY_PRINT_HERE(...) \
timemory_print_here(TIMEMORY_PID_TID_STRING.c_str(), \
TIMEMORY_TRUNCATED_FILE_STRING(__FILE__).c_str(), \
__LINE__, __PRETTY_FUNCTION__, __VA_ARGS__)
# else
# define PRETTY_PRINT_HERE(...) \
timemory_print_here(TIMEMORY_PID_TID_STRING.c_str(), \
TIMEMORY_TRUNCATED_FILE_STRING(__FILE__).c_str(), \
__LINE__, __FUNCTION__, __VA_ARGS__)
# endif
#endif
#if !defined(TIMEMORY_CONDITIONAL_BACKTRACE)
# define TIMEMORY_CONDITIONAL_BACKTRACE(CONDITION, DEPTH) \
if(CONDITION) \
{ \
::tim::print_backtrace<DEPTH>(std::cerr, TIMEMORY_PID_TID_STRING); \
}
#endif
#if !defined(TIMEMORY_CONDITIONAL_DEMANGLED_BACKTRACE)
# define TIMEMORY_CONDITIONAL_DEMANGLED_BACKTRACE(CONDITION, DEPTH) \
if(CONDITION) \
{ \
::tim::print_demangled_backtrace<DEPTH>(std::cerr, TIMEMORY_PID_TID_STRING); \
}
#endif
#if defined(DEBUG)
template <typename... Args>
inline void
__LOG(std::string file, int line, const char* msg, Args&&... args)
{
auto _pos = file.find("/timemory/");
if(_pos == std::string::npos)
_pos = file.find_last_of('/');
if(_pos != std::string::npos)
file = file.substr(_pos);
fprintf(stderr, "[Log @ %s:%i]> ", file.c_str(), line);
fprintf(stderr, msg, std::forward<Args>(args)...);
fprintf(stderr, "\n");
}
//--------------------------------------------------------------------------------------//
inline void
__LOG(std::string file, int line, const char* msg)
{
if(file.find('/') != std::string::npos)
file = file.substr(file.find_last_of('/'));
fprintf(stderr, "[Log @ %s:%i]> %s\n", file.c_str(), line, msg);
}
//--------------------------------------------------------------------------------------//
// auto insert the file and line
# define _LOG(...) __LOG(__FILE__, __LINE__, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
template <typename... Args>
inline void
_DBG(const char* msg, Args&&... args)
{
fprintf(stderr, msg, std::forward<Args>(args)...);
}
//--------------------------------------------------------------------------------------//
inline void
_DBG(const char* msg)
{
fprintf(stderr, "%s", msg);
}
#else
# define _LOG(...) \
{}
# define _DBG(...) \
{}
#endif
//======================================================================================//
//
// Define macros for utility
//
//======================================================================================//
//
#if defined(TIMEMORY_UTILITY_SOURCE)
# define TIMEMORY_UTILITY_LINKAGE(...) __VA_ARGS__
# define TIMEMORY_UTILITY_INLINE
#elif defined(TIMEMORY_USE_EXTERN) || defined(TIMEMORY_USE_UTILITY_EXTERN)
# define TIMEMORY_UTILITY_LINKAGE(...) __VA_ARGS__
# define TIMEMORY_UTILITY_INLINE
#else
# define TIMEMORY_UTILITY_LINKAGE(...) inline __VA_ARGS__
# define TIMEMORY_UTILITY_INLINE inline
# define TIMEMORY_UTILITY_HEADER_MODE
#endif
+391
Просмотреть файл
@@ -0,0 +1,391 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
//
#include "timemory/macros/os.hpp"
#if !defined(TIMEMORY_WINDOWS)
# include "timemory/utility/popen.hpp"
# include <limits>
# if !defined(OPEN_MAX)
# define OPEN_MAX 1024
# endif
# if !defined(NGROUPS_MAX)
# define NGROUPS_MAX 16
# endif
extern "C"
{
extern char** environ;
}
namespace tim
{
namespace popen
{
//
//--------------------------------------------------------------------------------------//
//
struct group_info
{
int ngroups = -1;
gid_t group_id;
uid_t user_id;
gid_t groups[NGROUPS_MAX];
};
//
//--------------------------------------------------------------------------------------//
//
inline group_info&
get_group_info()
{
static group_info _instance;
return _instance;
}
//
//--------------------------------------------------------------------------------------//
//
void
drop_privileges(int permanent)
{
gid_t newgid = getgid();
gid_t oldgid = getegid();
uid_t newuid = getuid();
uid_t olduid = geteuid();
if(permanent == 0)
{
// Save information about the privileges that are being dropped so that they
// can be restored later.
//
get_group_info().group_id = oldgid;
get_group_info().user_id = olduid;
get_group_info().ngroups = getgroups(NGROUPS_MAX, get_group_info().groups);
}
// If root privileges are to be dropped, be sure to pare down the ancillary
// groups for the process before doing anything else because the setgroups( )
// system call requires root privileges. Drop ancillary groups regardless of
// whether privileges are being dropped temporarily or permanently.
//
if(olduid == 0)
setgroups(1, &newgid);
if(newgid != oldgid)
{
# if !defined(TIMEMORY_LINUX)
auto ret = setegid(newgid);
if(ret != 0)
abort();
if(permanent != 0 && setgid(newgid) == -1)
abort();
# else
if(setregid((permanent ? newgid : oldgid), newgid) == -1)
abort();
# endif
}
if(newuid != olduid)
{
# if !defined(TIMEMORY_LINUX)
auto ret = seteuid(newuid);
if(ret != 0)
abort();
if(permanent != 0 && setuid(newuid) == -1)
abort();
# else
if(setreuid(((permanent != 0) ? newuid : olduid), newuid) == -1)
abort();
# endif
}
// verify that the changes were successful
if(permanent != 0)
{
if(newgid != oldgid && (setegid(oldgid) != -1 || getegid() != newgid))
abort();
if(newuid != olduid && (seteuid(olduid) != -1 || geteuid() != newuid))
abort();
}
else
{
if(newgid != oldgid && getegid() != newgid)
abort();
if(newuid != olduid && geteuid() != newuid)
abort();
}
}
//
//--------------------------------------------------------------------------------------//
//
void
restore_privileges()
{
if(geteuid() != get_group_info().user_id)
if(seteuid(get_group_info().user_id) == -1 ||
geteuid() != get_group_info().user_id)
abort();
if(getegid() != get_group_info().group_id)
if(setegid(get_group_info().group_id) == -1 ||
getegid() != get_group_info().group_id)
abort();
if(get_group_info().user_id == 0U)
setgroups(get_group_info().ngroups, get_group_info().groups);
}
//
//--------------------------------------------------------------------------------------//
//
int
open_devnull(int fd)
{
FILE* f = nullptr;
switch(fd)
{
case 0: f = freopen("/dev/null", "rb", stdin); break;
case 1: f = freopen("/dev/null", "wb", stdout); break;
case 2: f = freopen("/dev/null", "wb", stderr); break;
default: break;
}
return (f != nullptr && fileno(f) == fd) ? 1 : 0;
}
//
//--------------------------------------------------------------------------------------//
//
void
sanitize_files()
{
// int fds;
struct stat st;
// Make sure all open descriptors other than the standard ones are closed
// if((fds = getdtablesize()) == -1)
// fds = OPEN_MAX;
// closing these files results in the inability to read the pipe from the parent
// for(int fd = 3; fd < fds; ++fd)
// close(fd);
// Verify that the standard descriptors are open. If they're not, attempt to
// open them using /dev/null. If any are unsuccessful, abort.
for(int fd = 0; fd < 3; ++fd)
{
if(fstat(fd, &st) == -1 && (errno != EBADF || open_devnull(fd) == 0))
{
abort();
}
}
}
//
//--------------------------------------------------------------------------------------//
//
pid_t
fork()
{
pid_t childpid;
if((childpid = ::fork()) == -1)
return -1;
// If this is the parent process, there's nothing more to do
if(childpid != 0)
return childpid;
// This is the child process
tim::popen::sanitize_files(); // Close all open files.
tim::popen::drop_privileges(1); // Permanently drop privileges.
return 0;
}
//
//--------------------------------------------------------------------------------------//
//
TIMEMORY_PIPE*
popen(const char* path, char** argv, char** envp)
{
int stdin_pipe[2] = { 0, 0 };
int stdout_pipe[2] = { 0, 0 };
TIMEMORY_PIPE* p = nullptr;
static char** _argv = []() {
static auto _tmp = new char*[1];
_tmp[0] = nullptr;
return _tmp;
}();
if(envp == nullptr)
envp = environ;
if(argv == nullptr)
argv = _argv;
p = new TIMEMORY_PIPE;
if(!p)
return nullptr;
p->read_fd = nullptr;
p->write_fd = nullptr;
p->child_pid = -1;
if(pipe(stdin_pipe) == -1)
{
delete p;
return nullptr;
}
if(pipe(stdout_pipe) == -1)
{
close(stdin_pipe[1]);
close(stdin_pipe[0]);
delete p;
return nullptr;
}
if(!(p->read_fd = fdopen(stdout_pipe[0], "r")))
{
close(stdout_pipe[1]);
close(stdout_pipe[0]);
close(stdin_pipe[1]);
close(stdin_pipe[0]);
delete p;
return nullptr;
}
if(!(p->write_fd = fdopen(stdin_pipe[1], "w")))
{
fclose(p->read_fd);
close(stdout_pipe[1]);
close(stdin_pipe[1]);
close(stdin_pipe[0]);
delete p;
return nullptr;
}
if((p->child_pid = tim::popen::fork()) == -1)
{
fclose(p->write_fd);
fclose(p->read_fd);
close(stdout_pipe[1]);
close(stdin_pipe[0]);
delete p;
return nullptr;
}
if(p->child_pid == 0)
{
// this is the child process
close(stdout_pipe[0]);
close(stdin_pipe[1]);
if(stdin_pipe[0] != 0)
{
dup2(stdin_pipe[0], 0);
close(stdin_pipe[0]);
}
if(stdout_pipe[1] != 1)
{
dup2(stdout_pipe[1], 1);
close(stdout_pipe[1]);
}
execve(path, argv, envp);
exit(127);
}
close(stdout_pipe[1]);
close(stdin_pipe[0]);
return p;
}
//
//--------------------------------------------------------------------------------------//
//
int
pclose(TIMEMORY_PIPE* p)
{
int status = p->child_status;
pid_t pid = -1;
// clean up memory
auto _clean = [&]() {
if(p->read_fd)
fclose(p->read_fd);
if(p->write_fd)
fclose(p->write_fd);
delete p;
};
if(status != std::numeric_limits<int>::max())
{
_clean();
if(WIFEXITED(status))
{
// printf("process %i exited, status=%d\n", p->child_pid,
// WEXITSTATUS(status));
return EXIT_SUCCESS;
}
else if(WIFSIGNALED(status))
{
printf("process %i killed by signal %d\n", p->child_pid, WTERMSIG(status));
return EXIT_FAILURE;
}
else if(WIFSTOPPED(status))
{
printf("process %i stopped by signal %d\n", p->child_pid, WSTOPSIG(status));
// return EXIT_FAILURE;
}
else if(WIFCONTINUED(status))
{
printf("process %i continued\n", p->child_pid);
// return EXIT_FAILURE;
}
}
else
{
if(p->child_pid != -1)
{
do
{
pid = waitpid(p->child_pid, &status, 0);
} while(pid == -1 && errno == EINTR);
}
}
_clean();
if(pid != -1 && WIFEXITED(status))
return WEXITSTATUS(status);
return (pid == -1 ? -1 : 0);
}
//
//--------------------------------------------------------------------------------------//
//
} // namespace popen
} // namespace tim
#else
namespace
{
int windows_popen = 0;
}
#endif
+241
Просмотреть файл
@@ -0,0 +1,241 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
//
#pragma once
#include "timemory/macros/os.hpp"
#include "timemory/utility/macros.hpp"
#include "timemory/utility/utility.hpp"
#if !defined(TIMEMORY_WINDOWS)
# include <sstream>
# include <string>
# include <vector>
# include <cerrno>
# include <cstdio>
# include <cstdlib>
# include <cstring>
# include <ctime>
# include <fcntl.h>
# include <grp.h>
# include <paths.h>
# include <sys/param.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <unistd.h>
namespace tim
{
namespace popen
{
//
using string_t = std::string;
using strvec_t = std::vector<string_t>;
//
struct TIMEMORY_PIPE
{
FILE* read_fd = nullptr;
FILE* write_fd = nullptr;
pid_t child_pid;
int child_status = std::numeric_limits<int>::max();
};
//
TIMEMORY_UTILITY_LINKAGE(TIMEMORY_PIPE*)
popen(const char* path, char** argv = nullptr, char** envp = nullptr);
//
TIMEMORY_UTILITY_LINKAGE(int)
pclose(TIMEMORY_PIPE* p);
//
TIMEMORY_UTILITY_LINKAGE(pid_t)
fork();
//
TIMEMORY_UTILITY_LINKAGE(void) // NOLINT
sanitize_files();
//
TIMEMORY_UTILITY_LINKAGE(int)
open_devnull(int fd);
//
TIMEMORY_UTILITY_LINKAGE(void)
drop_privileges(int permanent);
//
TIMEMORY_UTILITY_LINKAGE(void) // NOLINT
restore_privileges();
//
inline strvec_t
read_fork(TIMEMORY_PIPE* proc, int max_counter = 50)
{
int counter = 0;
strvec_t linked_libraries;
while(proc)
{
char buffer[4096];
auto* ret = fgets(buffer, 4096, proc->read_fd);
if(ret == nullptr || strlen(buffer) == 0)
{
if(max_counter == 0)
{
pid_t cpid = waitpid(proc->child_pid, &proc->child_status, WNOHANG);
if(cpid == 0)
continue;
else
break;
}
if(counter++ > max_counter)
break;
continue;
}
auto line = string_t(buffer);
auto loc = string_t::npos;
while((loc = line.find_first_of("\n\t")) != string_t::npos)
line.erase(loc, 1);
auto delim = delimit(line, " \n\t=>");
for(const auto& itr : delim)
{
if(itr.find('/') == 0)
linked_libraries.push_back(itr);
}
}
return linked_libraries;
}
//
inline std::ostream&
flush_output(std::ostream& os, TIMEMORY_PIPE* proc, int max_counter = 0)
{
int counter = 0;
while(proc)
{
char buffer[4096];
auto* ret = fgets(buffer, 4096, proc->read_fd);
if(ret == nullptr || strlen(buffer) == 0)
{
if(max_counter == 0)
{
pid_t cpid = waitpid(proc->child_pid, &proc->child_status, WNOHANG);
if(cpid == 0)
continue;
else
break;
}
if(counter++ > max_counter)
break;
continue;
}
os << string_t{ buffer } << std::flush;
}
return os;
}
//
//--------------------------------------------------------------------------------------//
//
} // namespace popen
} // namespace tim
# if !defined(TIMEMORY_UTILITY_SOURCE) && !defined(TIMEMORY_USE_UTILITY_EXTERN)
# include "timemory/utility/popen.cpp"
# endif
#endif
namespace tim
{
//
//--------------------------------------------------------------------------------------//
//
inline bool
launch_process(const char* cmd, const std::string& extra, std::ostream* os)
{
#if !defined(TIMEMORY_WINDOWS)
auto delim = tim::delimit(cmd, " \t");
tim::popen::TIMEMORY_PIPE* fp = nullptr;
if(delim.size() < 2)
{
fp = tim::popen::popen(cmd, nullptr, nullptr);
}
else
{
static std::string _c = "-c";
std::array<char*, 4> _args;
_args.fill(nullptr);
char* _cshell = getenv("SHELL");
char* _ushell = getusershell();
std::string _shell = (_cshell) ? _cshell : (_ushell) ? getusershell() : "/bin/sh";
_args.at(0) = (char*) _shell.c_str();
_args.at(1) = (char*) _c.c_str();
_args.at(2) = (char*) cmd;
fp = tim::popen::popen(_args.at(0), _args.data());
}
if(fp == nullptr)
{
std::stringstream ss;
ss << "[timemory]> Error launching command: '" << cmd << "'... " << extra;
perror(ss.str().c_str());
return false;
}
if(os)
{
popen::flush_output(*os, fp);
}
auto ec = tim::popen::pclose(fp);
if(ec != 0)
{
std::stringstream ss;
ss << "[timemory]> Command: '" << cmd << "' returned a non-zero exit code: " << ec
<< "... " << extra;
perror(ss.str().c_str());
return false;
}
#else
if(std::system(nullptr) != 0)
{
int ec = std::system(cmd);
if(ec != 0)
{
fprintf(stderr,
"[timemory]> Command: '%s' returned a non-zero exit code: %i... %s\n",
cmd, ec, extra.c_str());
return false;
}
}
else
{
fprintf(stderr, "std::system unavailable for command: '%s'... %s\n", cmd,
extra.c_str());
return false;
}
(void) os;
#endif
return true;
}
} // namespace tim
+142
Просмотреть файл
@@ -0,0 +1,142 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#pragma once
// For std::decay
#include <type_traits>
namespace tim
{
namespace utility
{
template <typename>
struct transient_function; // intentionally not defined
/// \struct tim::utility::transient_function
/// \brief A light-weight alternative to std::function. Pass any callback - including
/// capturing lambdas - cheaply and quickly as a function argument
///
/// - No instantiation of called function at each call site
/// - Simple to use - use transient_function<...> as the function argument
/// - Low cost, cheap setup, one indirect function call to invoke
/// - No risk of dynamic allocation (unlike std::function)
/// - Not persistent: synchronous calls only
///
template <typename RetT, typename... Args>
struct transient_function<RetT(Args...)>
{
using dispatch_type = RetT (*)(void*, Args...);
using target_function_reference = RetT(Args...);
// dispatch_type() is instantiated by the transient_function constructor,
// which will store a pointer to the function in m_dispatch.
template <typename Up>
static RetT dispatcher(void* target, Args&&... args)
{
return (*static_cast<Up*>(target))(std::forward<Args>(args)...);
}
transient_function() = default;
~transient_function() = default;
transient_function(transient_function&&) noexcept = default;
transient_function& operator=(transient_function&&) noexcept = default;
template <typename Tp>
transient_function(Tp&& target)
: m_dispatch(&dispatcher<std::decay_t<Tp>>)
, m_target(&target)
{}
// Specialize for reference-to-function, to ensure that a valid pointer is stored.
transient_function(target_function_reference target)
: m_dispatch(dispatcher<target_function_reference>)
{
static_assert(
sizeof(void*) == sizeof(target),
"It will not be possible to pass functions by reference on this platform. "
"Please use explicit function pointers i.e. foo(target) -> foo(&target)");
m_target = static_cast<void*>(target);
}
// Specialize for reference-to-function, to ensure that a valid pointer is stored.
transient_function& operator=(target_function_reference target)
{
if(this == &target)
return *this;
static_assert(
sizeof(void*) == sizeof(target),
"It will not be possible to pass functions by reference on this platform. "
"Please use explicit function pointers i.e. foo(target) -> foo(&target)");
m_dispatch = dispatcher<target_function_reference>;
m_target = static_cast<void*>(target);
return *this;
}
RetT operator()(Args&&... args) const
{
return m_dispatch(m_target, std::forward<Args>(args)...);
}
private:
// A pointer to the static function that will call the wrapped invokable object
dispatch_type m_dispatch = nullptr;
void* m_target = nullptr; // pointer to the invokable object
};
//
} // namespace utility
//
namespace scope
{
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::scope::destructor
/// \brief provides an object which can be returned from functions that will execute
/// the lambda provided during construction when it is destroyed
///
struct transient_destructor
{
template <typename FuncT>
transient_destructor(FuncT&& _func)
: m_functor(std::forward<FuncT>(_func))
{}
// delete copy operations
transient_destructor(const transient_destructor&) = delete;
transient_destructor& operator=(const transient_destructor&) = delete;
// allow move operations
transient_destructor(transient_destructor&& rhs) noexcept = default;
transient_destructor& operator=(transient_destructor&& rhs) noexcept = default;
~transient_destructor() { m_functor(); }
private:
utility::transient_function<void()> m_functor = []() {};
};
} // namespace scope
//
} // namespace tim
+846
Просмотреть файл
@@ -0,0 +1,846 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
/** \file timemory/utility/types.hpp
* \headerfile timemory/utility/types.hpp "timemory/utility/types.hpp"
* Declaration of types for utility directory
*
*/
#pragma once
#include "timemory/compat/macros.h"
#include "timemory/hash/types.hpp"
#include "timemory/macros/attributes.hpp"
#include "timemory/macros/os.hpp"
#include "timemory/mpl/concepts.hpp"
#include <array>
#include <bitset>
#include <functional>
#include <initializer_list>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
#include <type_traits>
//======================================================================================//
//
#if !defined(TIMEMORY_FOLD_EXPRESSION)
# if defined(CXX17)
# define TIMEMORY_FOLD_EXPRESSION(...) ((__VA_ARGS__), ...)
# else
# define TIMEMORY_FOLD_EXPRESSION(...) \
::tim::consume_parameters(::std::initializer_list<int>{ (__VA_ARGS__, 0)... })
# endif
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_FOLD_EXPANSION)
# define TIMEMORY_FOLD_EXPANSION(TYPE, SIZE, ...) \
std::array<TYPE, SIZE>({ (::tim::consume_parameters(), __VA_ARGS__)... });
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_RETURN_FOLD_EXPRESSION)
# define TIMEMORY_RETURN_FOLD_EXPRESSION(...) \
::std::make_tuple((::tim::consume_parameters(), __VA_ARGS__)...)
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_DECLARE_EXTERN_TEMPLATE)
# define TIMEMORY_DECLARE_EXTERN_TEMPLATE(...) extern template __VA_ARGS__;
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_INSTANTIATE_EXTERN_TEMPLATE)
# define TIMEMORY_INSTANTIATE_EXTERN_TEMPLATE(...) template __VA_ARGS__;
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_ESC)
# define TIMEMORY_ESC(...) __VA_ARGS__
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_DELETED_OBJECT)
# define TIMEMORY_DELETED_OBJECT(NAME) \
NAME() = delete; \
NAME(const NAME&) = delete; \
NAME(NAME&&) = delete; \
NAME& operator=(const NAME&) = delete; \
NAME& operator=(NAME&&) = delete;
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_DELETE_COPY_MOVE_OBJECT)
# define TIMEMORY_DELETE_COPY_MOVE_OBJECT(NAME) \
NAME(const NAME&) = delete; \
NAME(NAME&&) = delete; \
NAME& operator=(const NAME&) = delete; \
NAME& operator=(NAME&&) = delete;
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_DEFAULT_MOVE_ONLY_OBJECT)
# define TIMEMORY_DEFAULT_MOVE_ONLY_OBJECT(NAME) \
NAME(const NAME&) = delete; \
NAME(NAME&&) noexcept = default; \
NAME& operator=(const NAME&) = delete; \
NAME& operator=(NAME&&) noexcept = default;
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_DEFAULT_OBJECT)
# define TIMEMORY_DEFAULT_OBJECT(NAME) \
TIMEMORY_HOST_DEVICE_FUNCTION NAME() = default; \
NAME(const NAME&) = default; \
NAME(NAME&&) noexcept = default; \
NAME& operator=(const NAME&) = default; \
NAME& operator=(NAME&&) noexcept = default;
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_EXCEPTION)
# define TIMEMORY_EXCEPTION(...) \
{ \
std::stringstream _errmsg; \
_errmsg << __VA_ARGS__; \
perror(_errmsg.str().c_str()); \
std::cerr << _errmsg.str() << std::endl; \
std::exit(EXIT_FAILURE); \
}
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_TESTING_EXCEPTION) && defined(TIMEMORY_INTERNAL_TESTING)
# define TIMEMORY_TESTING_EXCEPTION(...) \
{ \
TIMEMORY_EXCEPTION(__VA_ARGS__) \
}
#elif !defined(TIMEMORY_TESTING_EXCEPTION)
# define TIMEMORY_TESTING_EXCEPTION(...) \
{}
#endif
//======================================================================================//
//
#if !defined(TIMEMORY_TUPLE_ACCESSOR)
# define TIMEMORY_TUPLE_ACCESSOR(INDEX, TUPLE, NAME) \
auto& NAME() { return std::get<INDEX>(TUPLE); } \
const auto& NAME() const { return std::get<INDEX>(TUPLE); }
#endif
//======================================================================================//
//
namespace tim
{
//
/// Alias template make_integer_sequence
template <typename Tp, Tp Num>
using make_integer_sequence = std::make_integer_sequence<Tp, Num>;
//
/// Alias template index_sequence
template <size_t... Idx>
using index_sequence = std::integer_sequence<size_t, Idx...>;
//
/// Alias template make_index_sequence
template <size_t Num>
using make_index_sequence = std::make_integer_sequence<size_t, Num>;
//
/// Alias template index_sequence_for
template <typename... Types>
using index_sequence_for = std::make_index_sequence<sizeof...(Types)>;
//
/// Alias template for enable_if
template <bool B, typename T = int>
using enable_if_t = typename std::enable_if<B, T>::type;
//
/// Alias template for decay
template <typename T>
using decay_t = typename std::decay<T>::type;
//
template <bool B, typename Lhs, typename Rhs>
using conditional_t = typename std::conditional<B, Lhs, Rhs>::type;
//
template <typename T>
using remove_cv_t = typename std::remove_cv<T>::type;
//
template <typename T>
using remove_const_t = typename std::remove_const<T>::type;
//
template <int N>
using priority_constant = std::integral_constant<int, N>;
//
//--------------------------------------------------------------------------------------//
//
template <typename T>
struct identity
{
using type = T;
};
//
template <typename T>
using identity_t = typename identity<T>::type;
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::null_type
/// \brief this is a placeholder type for optional type-traits. It is used as the default
/// type for the type-traits to signify there is no specialization.
struct null_type : concepts::null_type
{};
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::type_list
/// \brief lightweight tuple-alternative for meta-programming logic
template <typename... Tp>
struct type_list
{};
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::type_list_element
/// \brief Variant of `std::tuple_element` for \ref tim::type_list
template <size_t Idx, typename Tp>
struct type_list_element;
namespace internal
{
template <size_t Idx, size_t TargIdx, typename... Tail>
struct type_list_element;
template <size_t Idx, size_t TargIdx>
struct type_list_element<Idx, TargIdx>
{
using type = tim::null_type;
// TargIdx will be equal to Idx + 1 in second half of conditional statement
// below. If the second half of that conditional statement is entered, the
// following static_assert will be true
static_assert(TargIdx < Idx + 2, "Error! Index exceeded size of of type_list");
};
template <size_t Idx, size_t TargIdx, typename Tp, typename... Tail>
struct type_list_element<Idx, TargIdx, Tp, Tail...>
{
using type =
conditional_t<Idx == TargIdx, Tp,
typename type_list_element<Idx + 1, TargIdx, Tail...>::type>;
};
} // namespace internal
template <size_t Idx, typename... Types>
struct type_list_element<Idx, type_list<Types...>>
{
using type = typename internal::type_list_element<0, Idx, Types...>::type;
};
template <size_t Idx, typename Tp>
using type_list_element_t = typename type_list_element<Idx, Tp>::type;
//
//--------------------------------------------------------------------------------------//
//
/// \fn tim::consume_parameters
/// \brief use this function to get rid of "unused parameter" warnings
template <typename... ArgsT>
TIMEMORY_ALWAYS_INLINE void
consume_parameters(ArgsT&&...) TIMEMORY_HIDDEN TIMEMORY_NEVER_INSTRUMENT;
//
template <typename... ArgsT>
void
consume_parameters(ArgsT&&...)
{}
//
//--------------------------------------------------------------------------------------//
//
template <typename Tp, typename DeleterT, typename Tag>
class singleton;
//
//--------------------------------------------------------------------------------------//
//
namespace cupti
{
struct result;
}
//
//--------------------------------------------------------------------------------------//
//
namespace crtp
{
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::crtp::base
/// \brief a generic type for prioritizing a function call to the base class over
/// derived functions, e.g. void start(crtp::base, Args&&... args) { start(args...); }
struct base
{};
//
//--------------------------------------------------------------------------------------//
//
} // namespace crtp
//
//--------------------------------------------------------------------------------------//
//
namespace mpl
{
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::mpl::lightweight
/// \brief a generic type for indicating that function call or constructor should be
/// as lightweight as possible.
struct lightweight
{};
//
//--------------------------------------------------------------------------------------//
//
template <typename... Tp>
struct piecewise_select
{};
//
//--------------------------------------------------------------------------------------//
//
} // namespace mpl
//
//--------------------------------------------------------------------------------------//
//
namespace scope
{
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::scope::tree
/// \brief Dummy struct to designates tree (hierarchical) storage. This scope (default)
/// maintains nesting in the call-graph storage. In this scoping mode, the results
/// will be separated from each other based on the identifier AND the current number
/// of component instances in a "start" region. E.g. for two components with the
/// same identifiers where the first calls start, then the second calls start then
/// the second will be at a depth of +1 relative to the first (i.e. a child of the first).
struct tree : std::integral_constant<int, 2>
{};
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::scope::flat
/// \brief Dummy struct to designates flat (no hierarchy) storage.
/// When flat scoping is globally enabled, all entries to the call-graph storage at
/// entered at a depth of zero. Thus, if you want a report of all the function calls
/// and their total values for each identifier, flat scoping should be globally enabled.
/// This can be combined with timeline scoping to produce results where every measurement
/// is its own call-graph entry at a depth of zero (produces a large amount of data).
/// Flat-scoping can be enabled at the component bundler level also, there are two
/// ways to do this: (1) to enable flat-scoping for all instances of the bundle, add \ref
/// tim::quirk::flat_scope to the template parameters of the bundler; (2) to enable
/// flat-scoping for specific bundler instances, pass \code{.cpp}
/// tim::quirk::config<tim::quirk::flat_scope, ...>{} \endcode as the second argument to
/// the constructor of the bundle.
struct flat : std::integral_constant<int, 0>
{};
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::scope::timeline
/// \brief Dummy struct to designates timeline (hierarchical, non-duplicated) storage.
/// It is meaningless by itself and should be combined with \ref tim::scope::tree or
/// \ref tim::scope::flat. A tree timeline has all the hierarchy properties of the
/// tree scope but entries at the same depth with the same identifiers are separated
/// entries in the resuls.
/// Timeline-scoping can be enabled at the component bundler level also, there are two
/// ways to do this: (1) to enable timeline-scoping for all instances of the bundle, add
/// \ref tim::quirk::timeline_scope to the template parameters of the bundler; (2) to
/// enable timeline-scoping for specific bundler instances, pass \code{.cpp}
/// tim::quirk::config<tim::quirk::timeline_scope, ...>{} \endcode as the second argument
/// to the constructor of the bundle.
struct timeline : std::integral_constant<int, 1>
{};
//
//--------------------------------------------------------------------------------------//
//
static constexpr size_t scope_count = 3;
using data_type = std::bitset<scope_count>;
using input_type = std::array<bool, scope_count>;
//
//--------------------------------------------------------------------------------------//
//
inline input_type&
get_fields()
{
static input_type _instance{ { false, false, false } };
return _instance;
}
//
//--------------------------------------------------------------------------------------//
//
template <typename Arg, size_t... Idx>
static TIMEMORY_HOT_INLINE auto
generate(Arg&& arg, index_sequence<Idx...>)
{
static_assert(sizeof...(Idx) <= scope_count, "Error! Bad index sequence size");
data_type ret;
TIMEMORY_FOLD_EXPRESSION(ret.set(Idx, arg[Idx]));
return ret;
}
//
//--------------------------------------------------------------------------------------//
//
template <size_t... Idx>
static TIMEMORY_HOT_INLINE auto
either(data_type ret, data_type arg, index_sequence<Idx...>)
{
static_assert(sizeof...(Idx) <= scope_count, "Error! Bad index sequence size");
TIMEMORY_FOLD_EXPRESSION(ret.set(Idx, ret.test(Idx) || arg.test(Idx)));
return ret;
}
//
//--------------------------------------------------------------------------------------//
//
static TIMEMORY_HOT_INLINE auto
get_default_bitset() -> data_type
{
return generate(get_fields(), make_index_sequence<scope_count>{});
}
//
//--------------------------------------------------------------------------------------//
/// \struct tim::scope::config
/// \brief this data type encodes the options of storage scope. The default is
/// hierarchical (tree) scope. Specification of flat scope overrides the hierarchy
/// scope, e.g. you cannot have a hierarchical flat scope. The timeline scope
/// is meaningless should a specification of tree or flat, thus the valid combinations
/// are: tree, flat, tree + timeline, flat + timeline.
struct config : public data_type
{
config()
: data_type(get_default_bitset())
{}
explicit config(const data_type& obj)
: data_type(obj)
{}
explicit config(data_type&& obj) noexcept
: data_type(std::forward<data_type>(obj))
{}
explicit config(bool _flat)
: data_type(generate(input_type{ { _flat, false, false } },
make_index_sequence<scope_count>{}))
{}
explicit config(bool _flat, bool _timeline)
: data_type(generate(input_type{ { _flat, _timeline, false } },
make_index_sequence<scope_count>{}))
{}
explicit config(bool _flat, bool _timeline, bool _tree)
: data_type(generate(input_type{ { _flat, _timeline, _tree } },
make_index_sequence<scope_count>{}))
{}
config(tree)
: config(false, false, false)
{}
config(flat)
: config(true, false, false)
{}
config(timeline)
: config(false, true, false)
{}
template <typename Arg, typename... Args,
std::enable_if_t<(std::is_same<Arg, tree>::value ||
std::is_same<Arg, flat>::value ||
std::is_same<Arg, timeline>::value),
int> = 0>
explicit config(Arg&& arg, Args&&... args)
{
*this += std::forward<Arg>(arg);
TIMEMORY_FOLD_EXPRESSION(*this += std::forward<Args>(args));
}
~config() = default;
config(const config&) = default;
config(config&&) noexcept = default;
config& operator=(const config&) = default;
config& operator=(config&&) noexcept = default;
config& operator=(const data_type& rhs)
{
if(this != &rhs)
data_type::operator=(rhs);
return *this;
}
config& operator=(data_type&& rhs) noexcept
{
if(this != &rhs)
data_type::operator=(std::forward<data_type>(rhs));
return *this;
}
template <typename T, std::enable_if_t<(std::is_same<T, tree>::value ||
std::is_same<T, flat>::value ||
std::is_same<T, timeline>::value),
int> = 0>
config& operator+=(T)
{
this->data_type::set(T::value, true);
return *this;
}
using data_type::set;
template <typename T, std::enable_if_t<(std::is_same<T, tree>::value ||
std::is_same<T, flat>::value ||
std::is_same<T, timeline>::value),
int> = 0>
config& set(bool val = true)
{
this->data_type::set(T::value, val);
return *this;
}
TIMEMORY_NODISCARD bool is_flat() const { return this->test(flat::value); }
TIMEMORY_NODISCARD bool is_timeline() const { return this->test(timeline::value); }
// "tree" is default behavior so it returns true if nothing is set but gives
// priority to the flat setting
TIMEMORY_NODISCARD bool is_tree() const
{
return this->none() || (this->test(tree::value) && !this->test(flat::value));
}
TIMEMORY_NODISCARD bool is_flat_timeline() const
{
return (is_flat() && is_timeline());
}
TIMEMORY_NODISCARD bool is_tree_timeline() const
{
return (is_tree() && is_timeline());
}
template <bool ForceFlatT>
TIMEMORY_NODISCARD bool is_flat() const
{
return (ForceFlatT) ? true : this->test(flat::value);
}
template <bool ForceTreeT, bool ForceTimeT>
TIMEMORY_NODISCARD bool is_tree() const
{
return (ForceTreeT)
? true
: ((ForceTimeT) ? false
: (this->none() || (this->test(tree::value) &&
!this->test(flat::value))));
}
friend std::ostream& operator<<(std::ostream& os, const config& obj)
{
std::stringstream ss;
ss << std::boolalpha << "tree: " << obj.is_tree() << ", flat: " << obj.is_flat()
<< ", timeline: " << obj.is_timeline()
<< ". Values: flat::value = " << obj.test(flat::value)
<< ", timeline::value = " << obj.test(timeline::value)
<< ", tree::value = " << obj.test(tree::value);
os << ss.str();
return os;
}
template <typename ForceTreeT = false_type, typename ForceFlatT = false_type,
typename ForceTimeT = false_type>
uint64_t compute_depth(uint64_t _current)
{
static_assert(!(ForceTreeT::value && ForceFlatT::value),
"Error! Type cannot enforce tree-based call-stack depth storage "
"and flat call-stack depth storage simulatenously");
// flat: always at depth of 1
// tree: features nesting
// timeline: features nesting if not flat and depth of 1 if flat
if(ForceFlatT::value || is_flat())
{
// flat + timeline will be differentiated via compute_hash
// flat + tree is invalid and flat takes precedence
// printf("compute_depth is flat at %i\n", (int) _current);
return 1;
}
// if not flat, return the nested depth and compute_hash will account
// for whether the entry is a duplicate or not
// printf("compute_depth is tree or timeline at %i\n", (int) _current);
return _current + 1;
}
template <typename ForceTreeT = false_type, typename ForceFlatT = false_type,
typename ForceTimeT = false_type>
uint64_t compute_hash(uint64_t _id, uint64_t _depth, uint64_t& _counter)
{
// flat/tree: always compute the same hash for a given depth and key
// timeline: uses a counter to differentiate idential hashes occurring at diff
// time points.
// below is a fall-through (i.e. not an if-else) bc either tree or flat can be
// combined with timeline but in the case of tree + flat, flat will take
// precedence.
if(is_tree<ForceTreeT::value, ForceTimeT::value>() ||
is_flat<ForceFlatT::value>())
{
// printf("compute_hash is tree or flat at %i\n", (int) _depth);
_id = get_combined_hash_id(_id, _depth);
// _id ^= _depth;
}
if(ForceTimeT::value || is_timeline())
{
// printf("compute_hash is timeline at %i\n", (int) _depth);
_id = get_combined_hash_id(_id, _counter++);
// _id ^= _counter++;
}
// printf("compute_hash is %i at depth %i (counter = %i)\n", (int) _id, (int)
// _depth,
// (int) _counter);
return _id;
}
};
//
//--------------------------------------------------------------------------------------//
// clang-format off
static TIMEMORY_INLINE config
get_default() TIMEMORY_HOT;
TIMEMORY_INLINE config
operator+(config _lhs, tree) TIMEMORY_HOT;
TIMEMORY_INLINE config
operator+(config _lhs, flat) TIMEMORY_HOT;
TIMEMORY_INLINE config
operator+(config _lhs, timeline) TIMEMORY_HOT;
TIMEMORY_INLINE config
operator+(config _lhs, config _rhs) TIMEMORY_HOT;
// clang-format on
//--------------------------------------------------------------------------------------//
//
static TIMEMORY_HOT_INLINE auto
get_default() -> config
{
return config{ get_default_bitset() };
}
//
//--------------------------------------------------------------------------------------//
//
TIMEMORY_HOT_INLINE auto
operator+(config _lhs, tree) -> config
{
_lhs.set(tree::value, true);
return _lhs;
}
//
//--------------------------------------------------------------------------------------//
//
TIMEMORY_HOT_INLINE auto
operator+(config _lhs, flat) -> config
{
_lhs.set(flat::value, true);
return _lhs;
}
//
//--------------------------------------------------------------------------------------//
//
TIMEMORY_HOT_INLINE auto
operator+(config _lhs, timeline) -> config
{
_lhs.set(timeline::value, true);
return _lhs;
}
//
//--------------------------------------------------------------------------------------//
//
TIMEMORY_HOT_INLINE auto
operator+(config _lhs, config _rhs) -> config
{
return config{ either(_lhs, _rhs, make_index_sequence<scope_count>{}) };
}
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::scope::destructor
/// \brief provides an object which can be returned from functions that will execute
/// the lambda provided during construction when it is destroyed
///
struct destructor
{
template <typename FuncT>
destructor(FuncT&& _func)
: m_functor(std::forward<FuncT>(_func))
{}
// delete copy operations
destructor(const destructor&) = delete;
destructor& operator=(const destructor&) = delete;
// allow move operations
destructor(destructor&& rhs) noexcept
: m_functor(std::move(rhs.m_functor))
{
rhs.m_functor = []() {};
}
destructor& operator=(destructor&& rhs) noexcept
{
if(this != &rhs)
{
m_functor = std::move(rhs.m_functor);
rhs.m_functor = []() {};
}
return *this;
}
~destructor() { m_functor(); }
private:
std::function<void()> m_functor = []() {};
};
//
//--------------------------------------------------------------------------------------//
//
} // namespace scope
//
//--------------------------------------------------------------------------------------//
//
namespace lifetime
{
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::lifetime::scoped
/// \brief Dummy struct for meta-programming to designate that a component activates
/// it's features at the first start() invocation and deactivates it's features when
/// all instances that called start() have called stop(). Thus, the component's
/// features are dependent on at least one component instance existing in memory
/// (excluding the instances in the call-graph, which never call start/stop)
///
struct scoped
{};
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::lifetime::persistent
/// \brief Dummy struct for meta-programming to designate that a component activates its
/// features in {global,thread}_init and deactivates it's features in
/// {global,thead}_finalize
///
struct persistent
{};
//
//--------------------------------------------------------------------------------------//
//
} // namespace lifetime
//
//--------------------------------------------------------------------------------------//
//
namespace audit
{
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::audit::incoming
/// \brief Used by component audit member function to designate the
/// parameters being passed are incoming (e.g. before a gotcha wrappee is invoked)
///
struct incoming : concepts::phase_id
{};
//
//--------------------------------------------------------------------------------------//
//
/// \struct tim::audit::outgoing
/// \brief Used by component audit member function to designate the
/// parameters being passed are outgoing (e.g. the return value from a gotcha wrappee)
///
// audit the return type
struct outgoing : concepts::phase_id
{};
//
//--------------------------------------------------------------------------------------//
//
} // namespace audit
//--------------------------------------------------------------------------------------//
} // namespace tim
namespace std
{
template <size_t Idx, typename... Types>
struct tuple_element<Idx, tim::type_list<Types...>>
{
using type = typename tim::type_list_element<Idx, tim::type_list<Types...>>::type;
};
} // namespace std
//--------------------------------------------------------------------------------------//
namespace tim
{
namespace cereal
{
namespace detail
{
template <typename Tp>
struct StaticVersion;
} // namespace detail
} // namespace cereal
} // namespace tim
//--------------------------------------------------------------------------------------//
#if !defined(TIMEMORY_SET_CLASS_VERSION)
# define TIMEMORY_SET_CLASS_VERSION(VERSION_NUMBER, ...) \
namespace tim \
{ \
namespace cereal \
{ \
namespace detail \
{ \
template <> \
struct StaticVersion<__VA_ARGS__> \
{ \
static constexpr std::uint32_t version = VERSION_NUMBER; \
}; \
} \
} \
}
#endif
#if !defined(TIMEMORY_GET_CLASS_VERSION)
# define TIMEMORY_GET_CLASS_VERSION(...) \
::tim::cereal::detail::StaticVersion<__VA_ARGS__>::version
#endif
+409
Просмотреть файл
@@ -0,0 +1,409 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#ifndef TIMEMORY_UTILITY_UTILITY_CPP_
#define TIMEMORY_UTILITY_UTILITY_CPP_ 1
#include "timemory/macros/os.hpp"
#include "timemory/utility/macros.hpp"
#if !defined(TIMEMORY_UTILITY_HEADER_MODE)
# include "timemory/utility/utility.hpp"
#endif
namespace tim
{
//
std::string
dirname(std::string _fname)
{
#if defined(TIMEMORY_UNIX)
char* _cfname = realpath(_fname.c_str(), nullptr);
_fname = std::string(_cfname);
free(_cfname);
while(_fname.find("\\\\") != std::string::npos)
_fname.replace(_fname.find("\\\\"), 2, "/");
while(_fname.find('\\') != std::string::npos)
_fname.replace(_fname.find('\\'), 1, "/");
return _fname.substr(0, _fname.find_last_of('/'));
#elif defined(TIMEMORY_WINDOWS)
while(_fname.find('/') != std::string::npos)
_fname.replace(_fname.find('/'), 1, "\\");
_fname = _fname.substr(0, _fname.find_last_of('\\'));
return (_fname.at(_fname.length() - 1) == '\\')
? _fname.substr(0, _fname.length() - 1)
: _fname;
#endif
}
//--------------------------------------------------------------------------------------//
int
makedir(std::string _dir, int umask)
{
#if defined(TIMEMORY_UNIX)
while(_dir.find("\\\\") != std::string::npos)
_dir.replace(_dir.find("\\\\"), 2, "/");
while(_dir.find('\\') != std::string::npos)
_dir.replace(_dir.find('\\'), 1, "/");
if(_dir.length() == 0)
return 0;
int ret = mkdir(_dir.c_str(), umask);
if(ret != 0)
{
int err = errno;
if(err != EEXIST)
{
std::cerr << "mkdir(" << _dir.c_str() << ", " << umask
<< ") returned: " << ret << std::endl;
std::stringstream _sdir;
_sdir << "/bin/mkdir -p " << _dir;
return (launch_process(_sdir.str().c_str())) ? 0 : 1;
}
}
#elif defined(TIMEMORY_WINDOWS)
consume_parameters(umask);
while(_dir.find('/') != std::string::npos)
_dir.replace(_dir.find('/'), 1, "\\");
if(_dir.length() == 0)
return 0;
int ret = _mkdir(_dir.c_str());
if(ret != 0)
{
int err = errno;
if(err != EEXIST)
{
std::cerr << "_mkdir(" << _dir.c_str() << ") returned: " << ret << std::endl;
std::stringstream _sdir;
_sdir << "mkdir " << _dir;
return (launch_process(_sdir.str().c_str())) ? 0 : 1;
}
}
#endif
return 0;
}
//--------------------------------------------------------------------------------------//
bool
get_bool(const std::string& strbool, bool _default) noexcept
{
// empty string returns default
if(strbool.empty())
return _default;
// check if numeric
if(strbool.find_first_not_of("0123456789") == std::string::npos)
{
if(strbool.length() > 1 || strbool[0] != '0')
return true;
return false;
}
// convert to lowercase
auto _val = std::string{ strbool };
for(auto& itr : _val)
itr = tolower(itr);
// check for matches to acceptable forms of false
for(const auto& itr : { "off", "false", "no", "n", "f" })
{
if(_val == itr)
return false;
}
// check for matches to acceptable forms of true
for(const auto& itr : { "on", "true", "yes", "y", "t" })
{
if(_val == itr)
return true;
}
return _default;
}
//
//--------------------------------------------------------------------------------------//
//
#if defined(TIMEMORY_UNIX)
//
std::string
demangle_backtrace(const char* cstr)
{
auto _trim = [](std::string& _sub, size_t& _len) {
size_t _pos = 0;
while(!_sub.empty() && (_pos = _sub.find_first_of(' ')) == 0)
{
_sub = _sub.erase(_pos, 1);
--_len;
}
while(!_sub.empty() && (_pos = _sub.find_last_of(' ')) == _sub.length() - 1)
{
_sub = _sub.substr(0, _sub.length() - 1);
--_len;
}
return _sub;
};
auto _save = std::string{ cstr };
auto str = demangle(std::string(cstr));
if(str.empty())
return str;
auto beg = str.find("(");
if(beg == std::string::npos)
{
beg = str.find("_Z");
if(beg != std::string::npos)
beg -= 1;
}
auto end = str.find("+", beg);
if(beg != std::string::npos && end != std::string::npos)
{
auto len = end - (beg + 1);
auto sub = str.substr(beg + 1, len);
auto dem = demangle(_trim(sub, len));
str = str.replace(beg + 1, len, dem);
}
else if(beg != std::string::npos)
{
auto len = str.length() - (beg + 1);
auto sub = str.substr(beg + 1, len);
auto dem = demangle(_trim(sub, len));
str = str.replace(beg + 1, len, dem);
}
else if(end != std::string::npos)
{
auto len = end;
auto sub = str.substr(beg, len);
auto dem = demangle(_trim(sub, len));
str = str.replace(beg, len, dem);
}
if(str.empty())
{
TIMEMORY_TESTING_EXCEPTION(__FUNCTION__ << " resulted in empty string. input: "
<< _save);
return _save;
}
// cleanup std::_1::basic_<...> types since demangled versions are for diagnostics
using pair_t = std::pair<std::string, std::string>;
for(auto&& itr : { pair_t{ demangle<std::string>(), "std::string" },
pair_t{ demangle<std::istream>(), "std::istream" },
pair_t{ demangle<std::ostream>(), "std::ostream" },
pair_t{ demangle<std::stringstream>(), "std::stringstream" },
pair_t{ demangle<std::istringstream>(), "std::istringstream" },
pair_t{ demangle<std::ostringstream>(), "std::ostringstream" } })
str = str_transform(str, itr.first, "", [itr](const std::string&) -> std::string {
return itr.second;
});
return str;
}
//
std::string
demangle_backtrace(const std::string& str)
{
return demangle_backtrace(str.c_str());
}
//
std::string
demangle_unw_backtrace(const char* cstr)
{
auto _save = std::string{ cstr };
auto _str = tim::demangle(cstr);
if(_str.empty())
return _str;
auto _beg = _str.find("_Z");
auto _end = _str.find(" ", _beg);
if(_beg != std::string::npos && _end != std::string::npos)
{
auto _len = _end - _beg;
auto _sub = _str.substr(_beg, _len);
auto _dem = demangle(_sub);
_str = _str.replace(_beg, _len, _dem);
}
if(_str.empty())
{
TIMEMORY_TESTING_EXCEPTION(__FUNCTION__ << " resulted in empty string. input: "
<< _save);
return _save;
}
// cleanup std::_1::basic_<...> types since demangled versions are for diagnostics
using pair_t = std::pair<std::string, std::string>;
for(auto&& itr : { pair_t{ demangle<std::string>(), "std::string" },
pair_t{ demangle<std::istream>(), "std::istream" },
pair_t{ demangle<std::ostream>(), "std::ostream" },
pair_t{ demangle<std::stringstream>(), "std::stringstream" },
pair_t{ demangle<std::istringstream>(), "std::istringstream" },
pair_t{ demangle<std::ostringstream>(), "std::ostringstream" } })
_str =
str_transform(_str, itr.first, "", [itr](const std::string&) -> std::string {
return itr.second;
});
return _str;
}
//
std::string
demangle_unw_backtrace(const std::string& _str)
{
return demangle_unw_backtrace(_str.c_str());
}
//
#endif // defined(TIMEMORY_UNIX)
//
std::vector<std::string>
read_command_line(pid_t _pid)
{
std::vector<std::string> _cmdline;
#if defined(TIMEMORY_LINUX)
std::stringstream fcmdline;
fcmdline << "/proc/" << _pid << "/cmdline";
std::ifstream ifs(fcmdline.str().c_str());
if(ifs)
{
char cstr;
std::string sarg;
while(!ifs.eof())
{
ifs >> cstr;
if(!ifs.eof())
{
if(cstr != '\0')
{
sarg += cstr;
}
else
{
_cmdline.push_back(sarg);
sarg = "";
}
}
}
ifs.close();
}
#else
consume_parameters(_pid);
#endif
return _cmdline;
}
//
namespace utility
{
//
path::path(const std::string& _path)
: std::string(osrepr(_path))
{}
path::path(char* _path)
: std::string(osrepr(std::string(_path)))
{}
path::path(const path& rhs)
: std::string(osrepr(rhs))
{}
path::path(const char* _path)
: std::string(osrepr(std::string(const_cast<char*>(_path))))
{}
path&
path::operator=(const std::string& rhs)
{
std::string::operator=(osrepr(rhs));
return *this;
}
path&
path::operator=(const path& rhs)
{
if(this != &rhs)
std::string::operator=(osrepr(rhs));
return *this;
}
path&
path::insert(size_type __pos, const std::string& __s)
{
std::string::operator=(osrepr(std::string::insert(__pos, __s)));
return *this;
}
path&
path::insert(size_type __pos, const path& __s)
{
std::string::operator=(osrepr(std::string::insert(__pos, __s)));
return *this;
}
TIMEMORY_UTILITY_INLINE std::string
path::os()
{
#if defined(TIMEMORY_WINDOWS)
return "\\";
#elif defined(TIMEMORY_UNIX)
return "/";
#endif
}
TIMEMORY_UTILITY_INLINE std::string
path::inverse()
{
#if defined(TIMEMORY_WINDOWS)
return "/";
#elif defined(TIMEMORY_UNIX)
return "\\";
#endif
}
// OS-dependent representation
TIMEMORY_UTILITY_INLINE std::string
path::osrepr(std::string _path)
{
#if defined(TIMEMORY_WINDOWS)
while(_path.find('/') != std::string::npos)
_path.replace(_path.find('/'), 1, "\\");
#elif defined(TIMEMORY_UNIX)
while(_path.find("\\\\") != std::string::npos)
_path.replace(_path.find("\\\\"), 2, "/");
while(_path.find('\\') != std::string::npos)
_path.replace(_path.find('\\'), 1, "/");
#endif
return _path;
}
//
} // namespace utility
} // namespace tim
//
#endif // !defined(TIMEMORY_UTILITY_UTILITY_CPP_)
+882
Просмотреть файл
@@ -0,0 +1,882 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
//
/** \file utility/utility.hpp
* \headerfile utility/utility.hpp "timemory/utility/utility.hpp"
* General utility functions
*
*/
#pragma once
#include "timemory/api.hpp"
#include "timemory/macros/compiler.hpp"
#include "timemory/macros/language.hpp"
#include "timemory/macros/os.hpp"
#include "timemory/utility/macros.hpp"
#include "timemory/utility/transient_function.hpp"
#include "timemory/utility/types.hpp"
#if defined(TIMEMORY_WINDOWS)
// Without this include on windows launch_process is needed by makedir but is
// missing at link time. With this include on linux there is a problem with
// delimit not being defined before it is used in popen.hpp. I think including
// popen.hpp at the end of this header would be portable and not need the ifdef,
// but that would be too weird, so we may have to live with the ifdef. (At
// least until makedir is implemented using std::filesystem.)
# include "timemory/utility/popen.hpp"
#endif
#if defined(TIMEMORY_USE_LIBUNWIND)
# include <libunwind.h>
#endif
// C library
#include <cctype>
#include <cerrno>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
// I/O
#include <fstream>
#include <iomanip>
#include <iosfwd>
#include <iostream>
#include <sstream>
#include <string>
// general
#include <functional>
#include <limits>
#include <regex>
#include <typeindex>
#include <utility>
// container
#include <vector>
// threading
#include <atomic>
#include <mutex>
#include <thread>
#if defined(TIMEMORY_UNIX)
# include <cxxabi.h>
# include <execinfo.h>
# include <sys/stat.h>
# include <sys/types.h>
#elif defined(TIMEMORY_WINDOWS)
# include <direct.h>
using pid_t = int;
#endif
#if !defined(DEFAULT_UMASK)
# define DEFAULT_UMASK 0777
#endif
//--------------------------------------------------------------------------------------//
namespace tim
{
// alias here for common string type
// there is also a string_view_t alias in macros/language.hpp which is std::string in
// c++14 and std::string_view in c++17 and newer
using string_t = std::string;
/// \typedef std::recursive_mutex mutex_t
/// \brief Recursive mutex is used for convenience since the
/// performance penalty vs. a regular mutex is not really an issue since there are not
/// many locks in general.
using mutex_t = std::recursive_mutex;
/// \typedef std::unique_lock<std::recursive_mutex> auto_lock_t
/// \brief Unique lock type around \ref mutex_t
using auto_lock_t = std::unique_lock<mutex_t>;
//--------------------------------------------------------------------------------------//
// definition in popen.hpp
bool
launch_process(const char* cmd, const std::string& extra = "",
std::ostream* os = nullptr);
//--------------------------------------------------------------------------------------//
template <typename Tp>
inline bool
isfinite(const Tp& arg)
{
#if defined(TIMEMORY_WINDOWS)
// Windows seems to be missing std::isfinite
return (arg == arg && arg != std::numeric_limits<Tp>::infinity() &&
arg != -std::numeric_limits<Tp>::infinity())
? true
: false;
#else
return std::isfinite(arg);
#endif
}
//======================================================================================//
//
// General functions
//
//======================================================================================//
/// \fn mutex_t& type_mutex(uint64_t)
/// \tparam Tp data type for lock
/// \tparam ApiT API for lock
/// \tparam N max size
///
/// \brief A simple way to get a mutex for a class or common behavior, e.g.
/// `type_mutex<decltype(std::cout)>()` provides a mutex for synchronizing output streams.
/// Recommend using in conjunction with auto-lock:
/// `tim::auto_lock_t _lk{ type_mutex<Foo>() }`.
template <typename Tp, typename ApiT = TIMEMORY_API, size_t N = 4>
mutex_t&
type_mutex(uint64_t _n = 0)
{
static std::array<mutex_t, N> _mutexes{};
return _mutexes.at(_n % N);
}
//--------------------------------------------------------------------------------------//
inline std::string
demangle(const char* _mangled_name, int* _status = nullptr)
{
#if defined(TIMEMORY_ENABLE_DEMANGLE)
// return the mangled since there is no buffer
if(!_mangled_name)
return std::string{};
int _ret = 0;
std::string _demangled_name{ _mangled_name };
if(!_status)
_status = &_ret;
// PARAMETERS to __cxa_demangle
// mangled_name:
// A NULL-terminated character string containing the name to be demangled.
// buffer:
// A region of memory, allocated with malloc, of *length bytes, into which the
// demangled name is stored. If output_buffer is not long enough, it is expanded
// using realloc. output_buffer may instead be NULL; in that case, the demangled
// name is placed in a region of memory allocated with malloc.
// _buflen:
// If length is non-NULL, the length of the buffer containing the demangled name
// is placed in *length.
// status:
// *status is set to one of the following values
char* _demang = abi::__cxa_demangle(_mangled_name, nullptr, nullptr, _status);
switch(*_status)
{
// 0 : The demangling operation succeeded.
// -1 : A memory allocation failiure occurred.
// -2 : mangled_name is not a valid name under the C++ ABI mangling rules.
// -3 : One of the arguments is invalid.
case 0:
{
if(_demang)
_demangled_name = std::string{ _demang };
break;
}
case -1:
{
char _msg[1024];
::memset(_msg, '\0', 1024 * sizeof(char));
::snprintf(_msg, 1024, "memory allocation failure occurred demangling %s",
_mangled_name);
::perror(_msg);
break;
}
case -2: break;
case -3:
{
char _msg[1024];
::memset(_msg, '\0', 1024 * sizeof(char));
::snprintf(_msg, 1024, "Invalid argument in: (\"%s\", nullptr, nullptr, %p)",
_mangled_name, (void*) _status);
::perror(_msg);
break;
}
default: break;
};
// free allocated buffer
::free(_demang);
return _demangled_name;
#else
(void) _status;
return _mangled_name;
#endif
}
//--------------------------------------------------------------------------------------//
inline std::string
demangle(const std::string& _str, int* _status = nullptr)
{
return demangle(_str.c_str(), _status);
}
//--------------------------------------------------------------------------------------//
template <typename Tp>
inline auto
try_demangle()
{
// static because a type demangle will always be the same
static auto _val = []() {
// wrap the type in type_list and then extract ... from tim::type_list<...>
auto _tmp = ::tim::demangle(typeid(type_list<Tp>).name());
auto _key = std::string{ "type_list" };
auto _idx = _tmp.find(_key);
_idx = _tmp.find('<', _idx);
_tmp = _tmp.substr(_idx + 1);
_idx = _tmp.find_last_of('>');
_tmp = _tmp.substr(0, _idx);
// strip trailing whitespaces
while((_idx = _tmp.find_last_of(' ')) == _tmp.length() - 1)
_tmp = _tmp.substr(0, _idx);
return _tmp;
}();
return _val;
}
//--------------------------------------------------------------------------------------//
template <typename Tp>
inline auto
demangle()
{
// static because a type demangle will always be the same
static auto _val = demangle(typeid(Tp).name());
return _val;
}
//--------------------------------------------------------------------------------------//
namespace internal
{
template <typename Tp, typename Up = Tp>
inline auto
typeid_hash(int) -> decltype(demangle<Tp>(), size_t{})
{
return std::type_index(typeid(Tp)).hash_code();
}
//
template <typename Tp, typename Up = Tp>
inline auto
typeid_hash(long)
{
return 0;
}
} // namespace internal
template <typename Tp>
inline auto
typeid_hash()
{
return internal::typeid_hash<Tp>(0);
}
//--------------------------------------------------------------------------------------//
template <typename T>
inline T
from_string(const std::string& str)
{
std::stringstream ss;
ss << str;
T val{};
ss >> val;
return val;
}
//--------------------------------------------------------------------------------------//
template <typename T>
inline T
from_string(const char* cstr)
{
std::stringstream ss;
ss << cstr;
T val{};
ss >> val;
return val;
}
//--------------------------------------------------------------------------------------//
TIMEMORY_UTILITY_INLINE std::string
dirname(std::string _fname);
//--------------------------------------------------------------------------------------//
TIMEMORY_UTILITY_INLINE int
makedir(std::string _dir, int umask = DEFAULT_UMASK);
//--------------------------------------------------------------------------------------//
TIMEMORY_UTILITY_INLINE bool
get_bool(const std::string& strbool, bool _default = false) noexcept;
//--------------------------------------------------------------------------------------//
//
#if defined(TIMEMORY_UNIX)
//
TIMEMORY_UTILITY_INLINE std::string
demangle_backtrace(const char* cstr);
//
TIMEMORY_UTILITY_INLINE std::string
demangle_backtrace(const std::string& str);
//
TIMEMORY_UTILITY_INLINE std::string
demangle_unw_backtrace(const char* cstr);
//
TIMEMORY_UTILITY_INLINE std::string
demangle_unw_backtrace(const std::string& str);
//
template <size_t Depth, size_t Offset = 1>
TIMEMORY_NOINLINE auto
get_backtrace()
{
static_assert(Depth > 0, "Error !(Depth > 0)");
static_assert(Offset >= 0, "Error !(Offset >= 0)");
// destination
std::array<char[512], Depth> btrace{};
for(auto& itr : btrace)
itr[0] = '\0';
// plus one for this stack-frame
std::array<void*, Depth + Offset> buffer{};
buffer.fill(nullptr);
// size of returned buffer
auto sz = backtrace(buffer.data(), Depth + Offset);
// size of relevant data
auto n = sz - Offset;
// skip ahead (Offset + 1) stack frames
char** bsym = backtrace_symbols(buffer.data() + Offset, n);
// report errors
if(bsym == nullptr)
{
perror("backtrace_symbols");
}
else
{
for(decltype(n) i = 0; i < n; ++i)
{
snprintf(btrace[i], sizeof(btrace[i]), "%s", bsym[i]);
}
}
return btrace;
}
//
template <size_t Depth, size_t Offset = 1>
TIMEMORY_NOINLINE auto
get_unw_backtrace()
{
# if defined(TIMEMORY_USE_LIBUNWIND)
static_assert(Depth > 0, "Error !(Depth > 0)");
static_assert(Offset >= 0, "Error !(Offset >= 0)");
unw_cursor_t cursor;
unw_context_t context;
// destination
std::array<char[512], Depth> btrace{};
for(auto& itr : btrace)
itr[0] = '\0';
// Initialize cursor to current frame for local unwinding.
unw_getcontext(&context);
if(unw_init_local(&cursor, &context) < 0)
{
return btrace;
}
size_t tot_idx = 0;
while(unw_step(&cursor) > 0)
{
unw_word_t ip; // stack pointer
unw_word_t off; // offset
auto _idx = ++tot_idx;
if(_idx >= Depth + Offset)
break;
unw_get_reg(&cursor, UNW_REG_IP, &ip);
if(ip == 0)
break;
char name[496];
name[0] = '\0';
if(unw_get_proc_name(&cursor, name, sizeof(name), &off) == 0)
{
if(_idx >= Offset)
{
auto _lidx = _idx - Offset;
if(off)
snprintf(btrace[_lidx], sizeof(btrace[_lidx]), "%s +0x%lx", name,
(long) off);
else
snprintf(btrace[_lidx], sizeof(btrace[_lidx]), "%s", name);
}
}
}
# else
std::array<char[512], Depth> btrace{};
throw std::runtime_error("[timemory]> libunwind not available");
# endif
return btrace;
}
//
template <size_t Depth, size_t Offset = 1, typename Func>
TIMEMORY_NOINLINE auto
get_backtrace(Func&& func)
{
static_assert(Depth > 0, "Error !(Depth > 0)");
static_assert(Offset >= 0, "Error !(Offset >= 0)");
using type = std::result_of_t<Func(const char[512])>;
// destination
std::array<type, Depth> btrace{};
auto&& _data = ::tim::get_backtrace<Depth, Offset + 1>();
auto _n = _data.size();
for(decltype(_n) i = 0; i < _n; ++i)
btrace[i] = func(_data[i]);
return btrace;
}
//
template <size_t Depth, size_t Offset = 1, typename Func>
TIMEMORY_NOINLINE auto
get_unw_backtrace(Func&& func)
{
static_assert(Depth > 0, "Error !(Depth > 0)");
static_assert(Offset >= 0, "Error !(Offset >= 0)");
using type = std::result_of_t<Func(const char[512])>;
// destination
std::array<type, Depth> btrace{};
auto&& _data = ::tim::get_unw_backtrace<Depth, Offset + 1>();
auto _n = _data.size();
for(decltype(_n) i = 0; i < _n; ++i)
btrace[i] = func(_data[i]);
return btrace;
}
//
//--------------------------------------------------------------------------------------//
//
template <size_t Depth, size_t Offset = 1>
TIMEMORY_NOINLINE auto
get_demangled_backtrace()
{
auto demangle_bt = [](const char cstr[512]) { return demangle_backtrace(cstr); };
return get_backtrace<Depth, Offset + 1>(demangle_bt);
}
//
//--------------------------------------------------------------------------------------//
//
template <size_t Depth, size_t Offset = 1>
TIMEMORY_NOINLINE auto
get_demangled_unw_backtrace()
{
auto demangle_bt = [](const char cstr[512]) { return demangle_unw_backtrace(cstr); };
return get_unw_backtrace<Depth, Offset + 1>(demangle_bt);
}
//
//--------------------------------------------------------------------------------------//
//
template <size_t Depth, size_t Offset = 2>
TIMEMORY_NOINLINE std::ostream&
print_backtrace(std::ostream& os = std::cerr, std::string _prefix = "",
const std::string& _info = "", const std::string& _indent = " ")
{
os << _indent.substr(0, _indent.length() / 2) << "Backtrace";
if(!_info.empty())
os << " " << _info;
os << ":\n" << std::flush;
auto bt = tim::get_backtrace<Depth, Offset>();
if(!_prefix.empty() && _prefix.find_last_of(" \t") != _prefix.length() - 1)
_prefix += " ";
for(const auto& itr : bt)
{
if(strlen(itr) > 0)
os << _indent << _prefix << itr << "\n";
}
os << std::flush;
return os;
}
//
//--------------------------------------------------------------------------------------//
//
template <size_t Depth, size_t Offset = 2>
TIMEMORY_NOINLINE std::ostream&
print_demangled_backtrace(std::ostream& os = std::cerr, std::string _prefix = "",
const std::string& _info = "",
const std::string& _indent = " ")
{
os << _indent.substr(0, _indent.length() / 2) << "Backtrace";
if(!_info.empty())
os << " " << _info;
os << ":\n" << std::flush;
auto bt = tim::get_demangled_backtrace<Depth, Offset>();
if(!_prefix.empty() && _prefix.find_last_of(" \t") != _prefix.length() - 1)
_prefix += " ";
for(const auto& itr : bt)
{
if(itr.length() > 0)
os << _indent << _prefix << itr << "\n";
}
os << std::flush;
return os;
}
//
//--------------------------------------------------------------------------------------//
//
template <size_t Depth, size_t Offset = 2>
TIMEMORY_NOINLINE std::ostream&
print_unw_backtrace(std::ostream& os = std::cerr, std::string _prefix = "",
const std::string& _info = "", const std::string& _indent = " ")
{
os << _indent.substr(0, _indent.length() / 2) << "Backtrace";
if(!_info.empty())
os << " " << _info;
os << ":\n" << std::flush;
auto bt = tim::get_unw_backtrace<Depth, Offset>();
if(!_prefix.empty() && _prefix.find_last_of(" \t") != _prefix.length() - 1)
_prefix += " ";
for(const auto& itr : bt)
{
if(strlen(itr) > 0)
os << _indent << _prefix << itr << "\n";
}
os << std::flush;
return os;
}
//
//--------------------------------------------------------------------------------------//
//
template <size_t Depth, size_t Offset = 3>
TIMEMORY_NOINLINE std::ostream&
print_demangled_unw_backtrace(std::ostream& os = std::cerr, std::string _prefix = "",
const std::string& _info = "",
const std::string& _indent = " ")
{
os << _indent.substr(0, _indent.length() / 2) << "Backtrace";
if(!_info.empty())
os << " " << _info;
os << ":\n" << std::flush;
auto bt = tim::get_demangled_unw_backtrace<Depth, Offset>();
if(!_prefix.empty() && _prefix.find_last_of(" \t") != _prefix.length() - 1)
_prefix += " ";
for(const auto& itr : bt)
{
if(itr.length() > 0)
os << _indent << _prefix << itr << "\n";
}
os << std::flush;
return os;
}
//
#else
//
// define these dummy functions since they are used in operation::decode
//
static inline auto
demangle_backtrace(const char* cstr)
{
return std::string{ cstr };
}
//
static inline auto
demangle_backtrace(const std::string& str)
{
return str;
}
//
template <size_t Depth, size_t Offset = 2>
static inline std::ostream&
print_backtrace(std::ostream& os = std::cerr, std::string = {}, std::string = {},
std::string = {})
{
os << "[timemory]> Backtrace not supported on this platform\n";
return os;
}
//
template <size_t Depth, size_t Offset = 3>
static inline std::ostream&
print_demangled_backtrace(std::ostream& os = std::cerr, std::string = {},
std::string = {}, std::string = {})
{
os << "[timemory]> Backtrace not supported on this platform\n";
return os;
}
//
template <size_t Depth, size_t Offset = 2>
static inline std::ostream&
print_unw_backtrace(std::ostream& os = std::cerr, std::string = {}, std::string = {},
std::string = {})
{
os << "[timemory]> libunwind backtrace not supported on this platform\n";
return os;
}
//
template <size_t Depth, size_t Offset = 3>
static inline std::ostream&
print_demangled_unw_backtrace(std::ostream& os = std::cerr, std::string = {},
std::string = {}, std::string = {})
{
os << "[timemory]> libunwind backtrace not supported on this platform\n";
return os;
}
//
#endif
//
//--------------------------------------------------------------------------------------//
// delimit a string into a set
//
template <typename ContainerT = std::vector<std::string>,
typename PredicateT = std::function<std::string(const std::string&)>>
inline ContainerT
delimit(const std::string& line, const std::string& delimiters = "\"',;: ",
PredicateT&& predicate = [](const std::string& s) -> std::string { return s; })
{
ContainerT _result{};
size_t _beginp = 0; // position that is the beginning of the new string
size_t _delimp = 0; // position of the delimiter in the string
while(_beginp < line.length() && _delimp < line.length())
{
// find the first character (starting at _delimp) that is not a delimiter
_beginp = line.find_first_not_of(delimiters, _delimp);
// if no a character after or at _end that is not a delimiter is not found
// then we are done
if(_beginp == std::string::npos)
break;
// starting at the position of the new string, find the next delimiter
_delimp = line.find_first_of(delimiters, _beginp);
std::string _tmp{};
try
{
// starting at the position of the new string, get the characters
// between this position and the next delimiter
_tmp = line.substr(_beginp, _delimp - _beginp);
} catch(std::exception& e)
{
// print the exception but don't fail, unless maybe it should?
fprintf(stderr, "%s\n", e.what());
}
// don't add empty strings
if(!_tmp.empty())
{
_result.insert(_result.end(), predicate(_tmp));
}
}
return _result;
}
//
//--------------------------------------------------------------------------------------//
/// \brief apply a string transformation to substring inbetween a common delimiter.
/// e.g.
//
template <typename PredicateT = std::function<std::string(const std::string&)>>
inline std::string
str_transform(const std::string& input, const std::string& _begin,
const std::string& _end, PredicateT&& predicate)
{
size_t _beg_pos = 0; // position that is the beginning of the new string
size_t _end_pos = 0; // position of the delimiter in the string
std::string _result = input;
while(_beg_pos < _result.length() && _end_pos < _result.length())
{
// find the first sequence of characters after the end-position
_beg_pos = _result.find(_begin, _end_pos);
// if sequence wasn't found, we are done
if(_beg_pos == std::string::npos)
break;
// starting after the position of the first delimiter, find the end sequence
if(!_end.empty())
_end_pos = _result.find(_end, _beg_pos + 1);
else
_end_pos = _beg_pos + _begin.length();
// break if not found
if(_end_pos == std::string::npos)
break;
// length of the substr being operated on
auto _len = _end_pos - _beg_pos;
// get the substring between the two delimiters (including first delimiter)
auto _sub = _result.substr(_beg_pos, _len);
// apply the transform
auto _transformed = predicate(_sub);
// only replace if necessary
if(_sub != _transformed)
{
_result = _result.replace(_beg_pos, _len, _transformed);
// move end to the end of transformed string
_end_pos = _beg_pos + _transformed.length();
}
}
return _result;
}
//--------------------------------------------------------------------------------------//
//
TIMEMORY_UTILITY_INLINE std::vector<std::string>
read_command_line(pid_t _pid);
//======================================================================================//
//
// path
//
//======================================================================================//
namespace utility
{
class path : public std::string
{
public:
using size_type = std::string::size_type;
public:
TIMEMORY_UTILITY_INLINE path(const std::string& _path);
TIMEMORY_UTILITY_INLINE path(char* _path);
TIMEMORY_UTILITY_INLINE path(const path& rhs);
TIMEMORY_UTILITY_INLINE path(const char* _path);
TIMEMORY_UTILITY_INLINE path& operator=(const std::string& rhs);
TIMEMORY_UTILITY_INLINE path& operator=(const path& rhs);
TIMEMORY_UTILITY_INLINE path& insert(size_type __pos, const std::string& __s);
TIMEMORY_UTILITY_INLINE path& insert(size_type __pos, const path& __s);
// OS-dependent representation
static std::string osrepr(std::string _path);
static std::string os();
static std::string inverse();
};
} // namespace utility
//--------------------------------------------------------------------------------------//
template <typename T>
TIMEMORY_INLINE size_t
get_hash(T&& obj)
{
return std::hash<decay_t<T>>()(std::forward<T>(obj));
}
//--------------------------------------------------------------------------------------//
TIMEMORY_INLINE size_t
get_hash(const string_view_t& str)
{
return std::hash<string_view_t>{}(str);
}
//--------------------------------------------------------------------------------------//
TIMEMORY_INLINE size_t
get_hash(const char* cstr)
{
return std::hash<string_view_t>{}(cstr);
}
//--------------------------------------------------------------------------------------//
template <typename T>
struct hasher
{
inline size_t operator()(T&& val) const { return get_hash(std::forward<T>(val)); }
inline size_t operator()(const T& val) const { return get_hash(val); }
};
//--------------------------------------------------------------------------------------//
/*
#if defined(TIMEMORY_UNIX) && \ (defined(TIMEMORY_UTILITY_SOURCE) ||
defined(TIMEMORY_USE_UTILITY_EXTERN))
//
extern template auto
get_backtrace<2, 1>();
extern template auto
get_backtrace<3, 1>();
extern template auto
get_backtrace<4, 1>();
extern template auto
get_backtrace<8, 1>();
extern template auto
get_backtrace<16, 1>();
extern template auto
get_backtrace<32, 1>();
//
extern template auto
get_demangled_backtrace<3, 2>();
extern template auto
get_demangled_backtrace<4, 2>();
extern template auto
get_demangled_backtrace<8, 2>();
extern template auto
get_demangled_backtrace<16, 2>();
extern template auto
get_demangled_backtrace<32, 2>();
//
extern template auto
get_backtrace<3, 2>();
extern template auto
get_backtrace<4, 2>();
extern template auto
get_backtrace<8, 2>();
extern template auto
get_backtrace<16, 2>();
extern template auto
get_backtrace<32, 2>();
//
extern template auto
get_demangled_backtrace<4, 3>();
extern template auto
get_demangled_backtrace<8, 3>();
extern template auto
get_demangled_backtrace<16, 3>();
extern template auto
get_demangled_backtrace<32, 3>();
//
#endif
*/
//--------------------------------------------------------------------------------------//
} // namespace tim
//--------------------------------------------------------------------------------------//
#if defined(TIMEMORY_UTILITY_HEADER_MODE)
# include "timemory/utility/utility.cpp"
#endif
+349
Просмотреть файл
@@ -0,0 +1,349 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
/** \file timemory/variadic/auto_macros.hpp
* \headerfile timemory/variadic/auto_macros.hpp "timemory/variadic/macros.hpp"
* Generic macros that are intended to be building-blocks for other macros, e.g.
* TIMEMORY_MARKER, TIMEMORY_HANDLE, TIMEMORY_CALIPER, etc.
*
*/
#pragma once
#include <cstdint>
#include <string>
#include "timemory/compat/macros.h"
#include "timemory/general/source_location.hpp"
#include "timemory/macros/os.hpp"
#include "timemory/mpl/apply.hpp"
#include "timemory/utility/macros.hpp"
#include "timemory/utility/utility.hpp"
//======================================================================================//
//
// CXX variadic macros
//
//======================================================================================//
namespace tim
{
// e.g. tim::string::join(...)
using string = tim::mpl::apply<std::string>;
} // namespace tim
//--------------------------------------------------------------------------------------//
#if !defined(TIMEMORY_MACROS)
# define TIMEMORY_MACROS
//======================================================================================//
//
// HELPER MACROS
//
//======================================================================================//
# if !defined(TIMEMORY_WINDOWS)
# define TIMEMORY_OS_PATH_DELIMITER '/'
# else
# define TIMEMORY_OS_PATH_DELIMITER '\\'
# endif
//--------------------------------------------------------------------------------------//
# if defined(__FILE_NAME__)
# define _TIM_FILESTR __FILE_NAME__
# else
# define _TIM_FILESTR \
std::string(__FILE__).substr( \
std::string(__FILE__).find_last_of(TIMEMORY_OS_PATH_DELIMITER) + 1)
# endif
//--------------------------------------------------------------------------------------//
# define _TIM_FILELINE ::tim::string::join(':', _TIM_FILESTR, _TIM_LINESTR)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_JOIN(delim, ...) ::tim::string::join(delim, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_BLANK_LABEL(...) ::tim::string::join("", __VA_ARGS__)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_BASIC_LABEL(...) ::tim::string::join("", _TIM_FUNC, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_FULL_LABEL ::tim::string::join('/', _TIM_FUNC, _TIM_FILELINE)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_LABEL(...) TIMEMORY_JOIN("", TIMEMORY_FULL_LABEL, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_AUTO_TYPE(TYPE) ::tim::concepts::auto_type_t<TYPE>
//--------------------------------------------------------------------------------------//
# define TIMEMORY_COMP_TYPE(TYPE) ::tim::concepts::component_type_t<TYPE>
//======================================================================================//
//
// MARKER MACROS
//
//======================================================================================//
# define TIMEMORY_BLANK_MARKER(TYPE, ...) \
_TIM_STATIC_SRC_LOCATION(blank, __VA_ARGS__); \
TIMEMORY_AUTO_TYPE(TYPE) \
_TIM_VARIABLE(__LINE__)(TIMEMORY_CAPTURE_ARGS(__VA_ARGS__))
//--------------------------------------------------------------------------------------//
# define TIMEMORY_BASIC_MARKER(TYPE, ...) \
_TIM_STATIC_SRC_LOCATION(basic, __VA_ARGS__); \
TIMEMORY_AUTO_TYPE(TYPE) \
_TIM_VARIABLE(__LINE__)(TIMEMORY_CAPTURE_ARGS(__VA_ARGS__))
//--------------------------------------------------------------------------------------//
# define TIMEMORY_MARKER(TYPE, ...) \
_TIM_STATIC_SRC_LOCATION(full, __VA_ARGS__); \
TIMEMORY_AUTO_TYPE(TYPE) \
_TIM_VARIABLE(__LINE__)(TIMEMORY_CAPTURE_ARGS(__VA_ARGS__))
//======================================================================================//
//
// CONDITIONAL MARKER MACROS
//
//======================================================================================//
# define TIMEMORY_CONDITIONAL_BLANK_MARKER(COND, TYPE, ...) \
_TIM_STATIC_SRC_LOCATION(blank, __VA_ARGS__); \
std::unique_ptr<TIMEMORY_AUTO_TYPE(TYPE)> _TIM_VARIABLE(__LINE__) = \
std::unique_ptr<TIMEMORY_AUTO_TYPE(TYPE)>( \
((COND)) \
? new TIMEMORY_AUTO_TYPE(TYPE)(TIMEMORY_CAPTURE_ARGS(__VA_ARGS__)) \
: nullptr)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_CONDITIONAL_BASIC_MARKER(COND, TYPE, ...) \
_TIM_STATIC_SRC_LOCATION(basic, __VA_ARGS__); \
std::unique_ptr<TIMEMORY_AUTO_TYPE(TYPE)> _TIM_VARIABLE(__LINE__) = \
std::unique_ptr<TIMEMORY_AUTO_TYPE(TYPE)>( \
((COND)) \
? new TIMEMORY_AUTO_TYPE(TYPE)(TIMEMORY_CAPTURE_ARGS(__VA_ARGS__)) \
: nullptr)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_CONDITIONAL_MARKER(COND, TYPE, ...) \
_TIM_STATIC_SRC_LOCATION(full, __VA_ARGS__); \
std::unique_ptr<TIMEMORY_AUTO_TYPE(TYPE)> _TIM_VARIABLE(__LINE__) = \
std::unique_ptr<TIMEMORY_AUTO_TYPE(TYPE)>( \
((COND)) \
? new TIMEMORY_AUTO_TYPE(TYPE)(TIMEMORY_CAPTURE_ARGS(__VA_ARGS__)) \
: nullptr)
//======================================================================================//
//
// POINTER MACROS
//
//======================================================================================//
# define TIMEMORY_BLANK_POINTER(TYPE, ...) \
TIMEMORY_CONDITIONAL_BLANK_MARKER(::tim::settings::enabled(), TYPE, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_BASIC_POINTER(TYPE, ...) \
TIMEMORY_CONDITIONAL_BASIC_MARKER(::tim::settings::enabled(), TYPE, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_POINTER(TYPE, ...) \
TIMEMORY_CONDITIONAL_MARKER(::tim::settings::enabled(), TYPE, __VA_ARGS__)
//======================================================================================//
//
// CALIPER MACROS
//
//======================================================================================//
# define TIMEMORY_BLANK_CALIPER(ID, TYPE, ...) \
_TIM_STATIC_SRC_LOCATION(blank, __VA_ARGS__); \
TYPE _TIM_VARIABLE(ID)(TIMEMORY_CAPTURE_ARGS(__VA_ARGS__))
//--------------------------------------------------------------------------------------//
# define TIMEMORY_BASIC_CALIPER(ID, TYPE, ...) \
_TIM_STATIC_SRC_LOCATION(basic, __VA_ARGS__); \
TYPE _TIM_VARIABLE(ID)(TIMEMORY_CAPTURE_ARGS(__VA_ARGS__))
//--------------------------------------------------------------------------------------//
# define TIMEMORY_CALIPER(ID, TYPE, ...) \
_TIM_STATIC_SRC_LOCATION(full, __VA_ARGS__); \
TYPE _TIM_VARIABLE(ID)(TIMEMORY_CAPTURE_ARGS(__VA_ARGS__))
//--------------------------------------------------------------------------------------//
# define TIMEMORY_STATIC_BLANK_CALIPER(ID, TYPE, ...) \
_TIM_STATIC_SRC_LOCATION(blank, __VA_ARGS__); \
static TYPE _TIM_VARIABLE(ID)(TIMEMORY_CAPTURE_ARGS(__VA_ARGS__))
//--------------------------------------------------------------------------------------//
# define TIMEMORY_STATIC_BASIC_CALIPER(ID, TYPE, ...) \
_TIM_STATIC_SRC_LOCATION(basic, __VA_ARGS__); \
static TYPE _TIM_VARIABLE(ID)(TIMEMORY_CAPTURE_ARGS(__VA_ARGS__))
//--------------------------------------------------------------------------------------//
# define TIMEMORY_STATIC_CALIPER(ID, TYPE, ...) \
_TIM_STATIC_SRC_LOCATION(full, __VA_ARGS__); \
static TYPE _TIM_VARIABLE(ID)(TIMEMORY_CAPTURE_ARGS(__VA_ARGS__))
//--------------------------------------------------------------------------------------//
# define TIMEMORY_CALIPER_REFERENCE(ID) std::ref(_TIM_VARIABLE(ID)).get()
//--------------------------------------------------------------------------------------//
# define TIMEMORY_CALIPER_APPLY(ID, FUNC, ...) _TIM_VARIABLE(ID).FUNC(__VA_ARGS__)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_CALIPER_TYPE_APPLY(ID, TYPE, FUNC, ...) \
_TIM_VARIABLE(ID).type_apply<TYPE>(FUNC, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_CALIPER_APPLY0(ID, FUNC) _TIM_VARIABLE(ID).FUNC()
//--------------------------------------------------------------------------------------//
# define TIMEMORY_CALIPER_TYPE_APPLY0(ID, TYPE, FUNC) \
_TIM_VARIABLE(ID).type_apply<TYPE>(FUNC)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_CALIPER_LAMBDA(ID, LAMBDA, ...) \
LAMBDA(_TIM_VARIABLE(ID), __VA_ARGS__)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_CALIPER_TYPE_LAMBDA(ID, TYPE, LAMBDA, ...) \
LAMBDA(_TIM_VARIABLE(ID).get<TYPE>(), __VA_ARGS__)
//======================================================================================//
//
// HANDLE MACROS
//
//======================================================================================//
# define TIMEMORY_BLANK_HANDLE(TYPE, ...) \
TYPE(TIMEMORY_INLINE_SOURCE_LOCATION(blank, __VA_ARGS__))
//--------------------------------------------------------------------------------------//
# define TIMEMORY_BASIC_HANDLE(TYPE, ...) \
TYPE(TIMEMORY_INLINE_SOURCE_LOCATION(basic, __VA_ARGS__))
//--------------------------------------------------------------------------------------//
# define TIMEMORY_HANDLE(TYPE, ...) \
TYPE(TIMEMORY_INLINE_SOURCE_LOCATION(full, __VA_ARGS__))
//--------------------------------------------------------------------------------------//
# define TIMEMORY_BLANK_RAW_POINTER(TYPE, ...) \
(::tim::settings::enabled()) \
? new TYPE(TIMEMORY_INLINE_SOURCE_LOCATION(blank, __VA_ARGS__)) \
: nullptr
//--------------------------------------------------------------------------------------//
# define TIMEMORY_BASIC_RAW_POINTER(TYPE, ...) \
(::tim::settings::enabled()) \
? new TYPE(TIMEMORY_INLINE_SOURCE_LOCATION(basic, __VA_ARGS__)) \
: nullptr
//--------------------------------------------------------------------------------------//
# define TIMEMORY_RAW_POINTER(TYPE, ...) \
(::tim::settings::enabled()) \
? new TYPE(TIMEMORY_INLINE_SOURCE_LOCATION(full, __VA_ARGS__)) \
: nullptr
//======================================================================================//
//
// DEBUG MACROS
//
//======================================================================================//
# if defined(DEBUG)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_DEBUG_BLANK_MARKER(TYPE, ...) \
TIMEMORY_BASIC_MARKER(TYPE, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_DEBUG_BASIC_MARKER(TYPE, ...) \
TIMEMORY_BASIC_MARKER(TYPE, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
# define TIMEMORY_DEBUG_MARKER(TYPE, ...) TIMEMORY_MARKER(TYPE, __VA_ARGS__)
//--------------------------------------------------------------------------------------//
# else
# define TIMEMORY_DEBUG_BLANK_MARKER(TYPE, ...)
# define TIMEMORY_DEBUG_BASIC_MARKER(TYPE, ...)
# define TIMEMORY_DEBUG_MARKER(TYPE, ...)
# endif
//--------------------------------------------------------------------------------------//
# define TIMEMORY_CONFIGURE(TYPE, ...) TYPE::configure(__VA_ARGS__)
//--------------------------------------------------------------------------------------//
// deprecated macros
# include "timemory/utility/bits/macros.hpp"
//--------------------------------------------------------------------------------------//
#endif // !defined(TIMEMORY_MACROS)
//--------------------------------------------------------------------------------------//
+23
Просмотреть файл
@@ -0,0 +1,23 @@
# perfetto --out OUTPUT_FILE --txt -c roctrace.cfg
# 2 minute trace, but can be stopped prematurely.
duration_ms: 120000
write_into_file: true
file_write_period_ms: 100
flush_period_ms: 100
# One buffer allocated within the central tracing binary for the entire trace,
# shared by the two data sources below.
buffers {
size_kb: 102400000
fill_policy: RING_BUFFER
}
data_sources {
config {
name: "track_event"
track_event_config {
enabled_categories: "kernels,hosttrace"
}
}
}
Исполняемый файл
+37
Просмотреть файл
@@ -0,0 +1,37 @@
#!/bin/bash
SOURCE_DIR=..
BUILD_DIR=.
if [ -n "$1" ]; then SOURCE_DIR=$1; shift; fi
if [ -n "$1" ]; then BUILD_DIR=$1; shift; fi
echo "Testing 'cmake --build ${BUILD_DIR} --target all'..."
cmake --build ${BUILD_DIR} --target all
RET=$?
echo -n "Testing whether ${SOURCE_DIR}/include/timemory is a valid path... "
if [ ! -d ${SOURCE_DIR}/include/timemory ]; then
RET=1;
fi
echo " Done"
if [ "${RET}" -ne 0 ]; then
echo "Run from build directory within the source tree"
exit 1
fi
for i in $(find ${SOURCE_DIR}/include/timemory -type f | egrep '\.(h|hpp|c|cpp)$')
do
echo -n "Attempting to remove ${i}... "
rm $i
cmake --build ${BUILD_DIR} --target all &> /dev/null
RET=$?
if [ "${RET}" -ne 0 ]; then
git checkout ${i} &> /dev/null
echo "Failed"
else
git add ${i} &> /dev/null
echo "Success"
fi
done
+542
Просмотреть файл
@@ -0,0 +1,542 @@
// 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.
//
// 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
// 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.
//
// 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
// 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.
#include "hosttrace.hpp"
//======================================================================================//
//
// For selective instrumentation (unused)
//
bool
are_file_include_exclude_lists_empty()
{
return true;
}
//======================================================================================//
//
// Gets information (line number, filename, and column number) about
// the instrumented loop and formats it properly.
//
function_signature
get_loop_file_line_info(module_t* mutatee_module, procedure_t* f, flow_graph_t* cfGraph,
basic_loop_t* loopToInstrument)
{
if(!cfGraph || !loopToInstrument || !f)
return function_signature("", "", "");
char fname[MUTNAMELEN];
char mname[MUTNAMELEN];
const char* typeName = nullptr;
mutatee_module->getName(mname, MUTNAMELEN);
bpvector_t<point_t*>* loopStartInst =
cfGraph->findLoopInstPoints(BPatch_locLoopStartIter, loopToInstrument);
bpvector_t<point_t*>* loopExitInst =
cfGraph->findLoopInstPoints(BPatch_locLoopEndIter, loopToInstrument);
if(!loopStartInst || !loopExitInst)
return function_signature("", "", "");
unsigned long baseAddr = (unsigned long) (*loopStartInst)[0]->getAddress();
unsigned long lastAddr =
(unsigned long) (*loopExitInst)[loopExitInst->size() - 1]->getAddress();
verbprintf(3, "Loop: size of lastAddr = %lu: baseAddr = %lu, lastAddr = %lu\n",
(unsigned long) loopExitInst->size(), (unsigned long) baseAddr,
(unsigned long) lastAddr);
f->getName(fname, MUTNAMELEN);
auto* returnType = f->getReturnType();
if(returnType)
{
typeName = returnType->getName();
}
else
typeName = "void";
auto params = f->getParams();
std::vector<string_t> _params;
if(params)
{
for(auto itr : *params)
{
string_t _name = itr->getType()->getName();
if(_name.empty())
_name = itr->getName();
_params.push_back(_name);
}
}
bpvector_t<BPatch_statement> lines;
bpvector_t<BPatch_statement> linesEnd;
bool info1 = mutatee_module->getSourceLines(baseAddr, lines);
string_t filename = mname;
if(info1)
{
// filename = lines[0].fileName();
auto row1 = lines[0].lineNumber();
auto col1 = lines[0].lineOffset();
if(col1 < 0)
col1 = 0;
// This following section is attempting to remedy the limitations of
// getSourceLines for loops. As the program goes through the loop, the resulting
// lines go from the loop head, through the instructions present in the loop, to
// the last instruction in the loop, back to the loop head, then to the next
// instruction outside of the loop. What this section does is starts at the last
// instruction in the loop, then goes through the addresses until it reaches the
// next instruction outside of the loop. We then bump back a line. This is not a
// perfect solution, but we will work with the Dyninst team to find something
// better.
bool info2 = mutatee_module->getSourceLines((unsigned long) lastAddr, linesEnd);
verbprintf(3, "size of linesEnd = %lu\n", (unsigned long) linesEnd.size());
if(info2)
{
auto row2 = linesEnd[0].lineNumber();
auto col2 = linesEnd[0].lineOffset();
if(col2 < 0)
col2 = 0;
if(row2 < row1)
row1 = row2; /* Fix for wrong line numbers*/
return function_signature(typeName, fname, filename, _params, { row1, row2 },
{ col1, col2 }, true, info1, info2);
}
else
{
return function_signature(typeName, fname, filename, _params, { row1, 0 },
{ col1, 0 }, true, info1, info2);
}
}
else
{
return function_signature(typeName, fname, filename, _params);
}
}
//======================================================================================//
//
// We create a new name that embeds the file and line information in the name
//
function_signature
get_func_file_line_info(module_t* mutatee_module, procedure_t* f)
{
bool info1, info2;
unsigned long baseAddr, lastAddr;
char fname[MUTNAMELEN];
char mname[MUTNAMELEN];
int row1, col1, row2, col2;
string_t filename;
string_t typeName;
mutatee_module->getName(mname, MUTNAMELEN);
baseAddr = (unsigned long) (f->getBaseAddr());
f->getAddressRange(baseAddr, lastAddr);
bpvector_t<BPatch_statement> lines;
f->getName(fname, MUTNAMELEN);
auto* returnType = f->getReturnType();
if(returnType)
{
typeName = returnType->getName();
}
else
typeName = "void";
auto params = f->getParams();
std::vector<string_t> _params;
if(params)
{
for(auto itr : *params)
{
string_t _name = itr->getType()->getName();
if(_name.empty())
_name = itr->getName();
_params.push_back(_name);
}
}
info1 = mutatee_module->getSourceLines((unsigned long) baseAddr, lines);
filename = mname;
if(info1)
{
// filename = lines[0].fileName();
row1 = lines[0].lineNumber();
col1 = lines[0].lineOffset();
if(col1 < 0)
col1 = 0;
info2 = mutatee_module->getSourceLines((unsigned long) (lastAddr - 1), lines);
if(info2)
{
row2 = lines[1].lineNumber();
col2 = lines[1].lineOffset();
if(col2 < 0)
col2 = 0;
if(row2 < row1)
row1 = row2;
return function_signature(typeName, fname, filename, _params, { row1, 0 },
{ 0, 0 }, false, info1, info2);
}
else
{
return function_signature(typeName, fname, filename, _params, { row1, 0 },
{ 0, 0 }, false, info1, info2);
}
}
else
{
return function_signature(typeName, fname, filename, _params, { 0, 0 }, { 0, 0 },
false, false, false);
}
}
//======================================================================================//
//
// Error callback routine.
//
void
errorFunc(error_level_t level, int num, const char** params)
{
char line[256];
const char* msg = bpatch->getEnglishErrorString(num);
bpatch->formatErrorString(line, sizeof(line), msg, params);
if(num != expect_error)
{
printf("Error #%d (level %d): %s\n", num, level, line);
// We consider some errors fatal.
if(num == 101)
exit(-1);
}
}
//======================================================================================//
//
// For compatibility purposes
//
procedure_t*
find_function(image_t* app_image, const std::string& _name, strset_t _extra)
{
if(_name.empty())
return nullptr;
auto _find = [app_image](const string_t& _f) -> procedure_t* {
// Extract the vector of functions
bpvector_t<procedure_t*> _found;
auto ret = app_image->findFunction(_f.c_str(), _found, false, true, true);
if(ret == nullptr || _found.empty())
return nullptr;
return _found.at(0);
};
procedure_t* _func = _find(_name);
auto itr = _extra.begin();
while(!_func && itr != _extra.end())
{
_func = _find(*itr);
++itr;
}
if(!_func)
verbprintf(0, "timemory-run: Unable to find function %s\n", _name.c_str());
return _func;
}
//======================================================================================//
//
void
error_func_real(error_level_t level, int num, const char* const* params)
{
if(num == 0)
{
// conditional reporting of warnings and informational messages
if(error_print)
{
if(level == BPatchInfo)
{
if(error_print > 1)
printf("%s\n", params[0]);
}
else
printf("%s", params[0]);
}
}
else
{
// reporting of actual errors
char line[256];
const char* msg = bpatch->getEnglishErrorString(num);
bpatch->formatErrorString(line, sizeof(line), msg, params);
if(num != expect_error)
{
printf("Error #%d (level %d): %s\n", num, level, line);
// We consider some errors fatal.
if(num == 101)
exit(-1);
}
}
}
//======================================================================================//
//
// We've a null error function when we don't want to display an error
//
void
error_func_fake(error_level_t level, int num, const char* const* params)
{
consume_parameters(level, num, params);
// It does nothing.
}
//======================================================================================//
//
bool
find_func_or_calls(std::vector<const char*> names, bpvector_t<point_t*>& points,
image_t* app_image, procedure_loc_t loc)
{
using function_t = procedure_t;
using function_vec_t = bpvector_t<function_t*>;
using point_vec_t = bpvector_t<point_t*>;
function_t* func = nullptr;
for(auto nitr = names.begin(); nitr != names.end(); ++nitr)
{
function_t* f = find_function(app_image, *nitr);
if(f && f->getModule()->isSharedLib())
{
func = f;
break;
}
}
if(func)
{
point_vec_t* fpoints = func->findPoint(loc);
if(fpoints && fpoints->size())
{
for(auto pitr = fpoints->begin(); pitr != fpoints->end(); ++pitr)
points.push_back(*pitr);
return true;
}
}
// Moderately expensive loop here. Perhaps we should make a name->point map first
// and just do lookups through that.
function_vec_t* all_funcs = app_image->getProcedures();
auto initial_points_size = points.size();
for(auto nitr = names.begin(); nitr != names.end(); ++nitr)
{
for(auto fitr = all_funcs->begin(); fitr != all_funcs->end(); ++fitr)
{
function_t* f = *fitr;
if(f->getModule()->isSharedLib())
continue;
point_vec_t* fpoints = f->findPoint(BPatch_locSubroutine);
if(!fpoints || fpoints->empty())
continue;
for(auto pitr = fpoints->begin(); pitr != fpoints->end(); pitr++)
{
std::string callee = (*pitr)->getCalledFunctionName();
if(callee == std::string(*nitr))
points.push_back(*pitr);
}
}
if(points.size() != initial_points_size)
return true;
}
return false;
}
//======================================================================================//
//
bool
find_func_or_calls(const char* name, bpvector_t<point_t*>& points, image_t* image,
procedure_loc_t loc)
{
std::vector<const char*> v;
v.push_back(name);
return find_func_or_calls(v, points, image, loc);
}
//======================================================================================//
//
bool
c_stdlib_module_constraint(const std::string& _file)
{
static std::regex _pattern(
"^(a64l|accept4|alphasort|argp-help|argp-parse|asprintf|atof|atoi|atol|atoll|"
"auth_des|auth_none|auth_unix|backtrace|backtracesyms|backtracesymsfd|c16rtomb|"
"cacheinfo|canonicalize|carg|cargf|cargf128|cargl|"
"catgets|cfmakeraw|cfsetspeed|check_pf|chflags|"
"clearerr|clearerr_u|clnt_perr|clnt_raw|clnt_tcp|clnt_udp|clnt_unix"
"settime|copy_file_range|"
"creat64|ctermid|ctime|ctime_r|ctype|ctype-c99|ctype-c99_l|ctype-extn|ctype_l|"
"cuserid|daemon|dcigettext|difftime|dirname|div|dl-error|dl-libc|dl-sym|dlerror|"
"duplocale|dysize|endutxent|envz|epoll_wait|"
"ether_aton|ether_aton_r|ether_hton|ether_line|ether_ntoa|ether_ntoh|eventfd_"
"read|eventfd_write|execlp|execv|execvp|explicit_bzero|faccessat|fallocate64|"
"fattach|fchflags|fchmodat|fdatasync|fdetach|fdopendir|fedisblxcpt|feenablxcpt|"
"fegetexcept|fegetmode|feholdexcpt|feof_u|ferror_u|fesetenv|fesetexcept|"
"fesetmode|fesetround|fetestexceptflag|fexecve|ffsll|fgetexcptflg|fgetgrent|"
"fgetpwent|fgetsgent|fgetspent|fileno|fmemopen|fmtmsg|fnmatch|fprintf|fputc|"
"fputc_u|fputwc|fputwc_u|freopen|freopen64|fscanf|fseeko|fsetexcptflg|fstab|"
"fsync|ftello|ftime|ftok|fts|ftw|futimens|futimesat|fwide|fxprintf|gconv_conf|"
"gconv_db|gconv_dl|genops|getaddrinfo|getaliasent|getaliasent_r|getaliasname|"
"getauxval|getc|getchar|getchar_u|getdate|getdirentries|getdirname|getentropy|"
"getenv|getgrent|getgrent_r|getgrgid|getgrnam|gethostid|gethstbyad|gethstbynm|"
"gethstbynm2|gethstent|gethstent_r|getipv4sourcefilter|getloadavg|getlogin|"
"getlogin_r|getmsg|getnameinfo|getnetbyad|getnetbynm|getnetent|getnetent_r|"
"getnetgrent|getnetgrent_r|getopt|getopt1|getpass|getproto|getprtent|getprtent_r|"
"getprtname|getpwent|getpwent_r|getpwnam|getpwnam_r|getpwuid|getrandom|"
"getrpcbyname|getrpcbynumber|getrpcent|getrpcent_r|getrpcport|getservent|"
"getservent_r|getsgent|getsgent_r|getsgnam|getsourcefilter|getspent|getspent_r|"
"getspnam|getsrvbynm|getsrvbynm_r|getsrvbypt|getsubopt|getsysstats|getttyent|"
"getusershell|getutent_r|getutline|getutmp|getutxent|getutxid|getutxline|getw|"
"getwchar|getwchar_u|getwd|glob|gmon|gmtime|grantpt|group_member|gtty|herror|"
"hsearch|hsearch_r|htons|iconv|iconv_close|iconv_open|idn-stub|if_index|ifaddrs|"
"inet6_|inet_|inet_|initgroups|insremque|iofgets|iofgetws|iofgetws_u|iofputws|"
"iofwide|iopopen|ioungetwc|isastream|isctype|isfdtype|key_call|key_prot|killpg|"
"l64a|labs|lchmod|lckpwdf|lcong48|ldiv|llabs|lldiv|lockf|longjmp|lsearch|lutimes|"
"makedev|malloc|mblen|mbrtoc16|mbsinit|mbstowcs|mbtowc|mcheck|memccpy|"
"memchr|memcmp|memfrob|memmem|memset|memstream|mkdtemp|mkfifo|mkfifoat|mkostemp|"
"mkostemps|mkstemp|mkstemps|mktemp|mlock2|mntent|mntent_r|mpa|"
"msgctl|msgget|msgsnd|msort|msync|mtrace|netname|nice|nl_langinfo|nsap_addr|nscd_"
"getgr_r|nscd_gethst_r|nscd_getpw_r|nscd_getserv_r|nscd_helper|"
"nsswitch|ntp_gettime|ntp_gettimex|obprintf|obstack|oldfmemopen|open_by_handle_"
"at|opendir|pathconf|pclose|perror|pkey_mprotect|pm_getmaps|pmap_prot|pmap_rmt|"
"posix_fallocate|posix_fallocate64|preadv64|preadv64v2|printf-prs|printf_fp|"
"printf_size|profil|psiginfo|psignal|ptrace|ptsname|putc_u|putchar|putchar_u|"
"putenv|putgrent|putmsg|putpwent|putsgent|putspent|pututxline|putw|putwc_u|"
"putwchar|putwchar_u|pwritev64|pwritev64v2|raise|rcmd|readv|"
"reboot|recvfrom|recvmmsg|regex|regexp|remove|rename|renameat|res-close|res_"
"hconf|res_init|resolv_conf|rexec|rpc_thread|rpmatch|ruserpass|scandir|sched_"
"cpucount|sched_getaffinity|sched_getcpu|seed48|seekdir|semget|semop|semtimedop|"
"sendmsg|setbuf|setegid|seteuid|sethostid|setipv4sourcefilter|setlinebuf|"
"setlogin|setpgrp|setresuid|setrlimit64|setsourcefilter|setutxent|sgetsgent|"
"sgetspent|shmat|shmdt|shmget|sigandset|sigdelset|siggetmask|sighold|sigignore|"
"sigintr|sigisempty|signalfd|sigorset|sigpause|sigpending|sigrelse|sigset|"
"sigstack|sockatmark|speed|splice|sprofil|sscanf|sstk|stime|strcasecmp|"
"strcasestr|strcat|strchr|strcmp|strcpy|strcspn|strerror|strerror_l|strfmon|"
"strfromd|strfromf|strfromf128|strfroml|strfry|strlen|strncase|strncat|strncmp|"
"strncpy|strpbrk|strrchr|strsignal|strspn|strstr|strtod_l|strtof|strtof128_l|"
"strtof_l|strtoimax|strtok|strtol_l|strtold_l|strtoul|strtoumax|strxfrm|stty|svc|"
"svc_raw|svc_simple|svc_tcp|svc_udp|svc_unix|swab|sync_file_range|syslog|system|"
"tcflow|tcflush|tcgetattr|tcgetsid|tcsendbrk|tcsetpgrp|tee|telldir|tempnam|"
"tmpnam|tmpnam_r|tsearch|ttyname|ttyname_r|ttyslot|tzset|ualarm|ulimit|umount|"
"unlockpt|updwtmpx|ustat|utimensat|utmp_file|utmpxname|version|"
"versionsort|vfprintf|vfscanf|vfwscanf|vlimit|vmsplice|vprintf|vtimes|wait[0-9]|"
"wcfuncs|wcfuncs_l|wcscpy|wcscspn|wcsdup|wcsncat|wcsncmp|wcsnrtombs|wcspbrk|"
"wcsrchr|wcsstr|wcstod_l|wcstof|wcstoimax|wcstok|wcstold_l|wcstombs|wcstoumax|"
"wcswidth|wcsxfrm|wctob|wctype_l|wcwidth|wfileops|wgenops|wmemcmp|wmemstream|"
"wordexp|wstrops|x2y2m1l|xcrypt|xdr|xdr_float|xdr_intXX_t|xdr_mem|xdr_rec|xdr_"
"ref|xdr_sizeof|xdr_stdio|mq_notify|aio_|timer_routines|nptl-|shm-|sem_close|"
"setuid|pt-raise|x2y2)",
regex_opts);
return std::regex_search(_file, _pattern);
}
//======================================================================================//
//
bool
c_stdlib_function_constraint(const std::string& _func)
{
static std::regex _pattern(
"^(malloc|calloc|free|buffer|fscan|fstab|internal|gnu|fprint|isalnum|isalpha|"
"isascii|isastream|isblank|isblank_l|iscntrl|isctype|isdigit|isdigit_l|isfdtype|"
"isgraph|islower|islower_l|isprint|isprint_l|ispunct|isspace|isupper|isupper_l|"
"iswprint|isxdigit|asprintf|atof|atoi|atol|atoll|memalign|memccpy|memcpy|memchr|"
"memcmp|memfrob|memset|mkdtemp|mkfifo|mkfifoat|mkostemp64|mkostemps64|mkstemp|"
"mkstemps64|mktemp|mlock2|monstartup|mprobe|mremap_chunk|get_current_dir_name|"
"get_free_list|getaliasbyname|getaliasent|getauxval|getchar|getchar_unlocked|"
"getdate|getdirentries|getentropy|getenv|getfs|getgrent|getgrgid|"
"getgrnam|getgrouplist|gethostbyaddr|gethostbyname|gethostbyname2|gethostent|"
"gethostid|getifaddrs|getifaddrs_internal|getipv4sourcefilter|getkeyserv_handle|"
"getloadavg|getlogin|getlogin_fd0|getlogin_r_fd0|getmntent|getmsg|getnetbyaddr|"
"getnetbyname|getnetent|getnetgrent|getopt|getopt_long|getopt_long_only|getpass|"
"getprotobyname|getprotobynumber|getprotoent|getpwent|getpwnam|getpwnam_r|"
"getpwuid|getrandom|getrpcbyname|getrpcbynumber|getrpcent|getrpcport|"
"getservbyname|getservbyname_r|getservbyport|getservent|getsgent|getsgnam|"
"getsourcefilter|getspent|getspnam|getsubopt|getttyname|getttyname_r|"
"getusershell|getutent_r_file|getutent_r_unknown|getutid_r_file|getutid_r_"
"unknown|getutline|getutline_r_file|getutline_r_unknown|getutmp|getutxent|"
"getutxid|getutxline|getw|psiginfo|psignal|ptmalloc_init|ptrace|ptsname|putc_"
"unlocked|putchar|putchar_unlocked|putenv|putgrent|putmsg|putpwent|putsgent|"
"putspent|pututline_file|pututxline|putw|pw_map_free|pwritev|pwritev2|"
"qsort|raise|rcmd|re_acquire_state|re_acquire_state_context|re_"
"comp|re_compile_internal|re_dfa_add_node|re_exec|re_node_set_init_union|re_node_"
"set_insert|re_node_set_merge|re_search_internal|re_search_stub|re_string_"
"context_at|re_string_reconstruct|readtcp|readunix|readv|realloc|realpath|str_to_"
"mpn|strcasecmp|strcat|strcmp|strcpy|strcspn|strerror|strerror_l|strerror_thread_"
"freeres|strfmon|strfromd|strfromf|strfromf128|strfroml|strfry|strlen|"
"strncasecmp|strncat|strncmp|strncpy|strpbrk|strrchr|strsignal|strspn|strtof32|"
"strtoimax|strtok|strtol_l|strtold_l|strtoull|strtoumax|strxfrm|xdrstdio|xdrmem|"
"inet_|inet6_|clock_|backtrace_|dummy_|fts_|fts64_|fexecv|execv|stime|ftime|"
"gmtime|wcs|envz_|fmem|fputc|fgetc|fputwc|fgetwc|vprintf|feget|fetest|feenable|"
"feset|fedisable|nscd_|fork|execl|tzset|ntp_|mtrace|tr_[a-z]+hook|mcheck_[a-z_]+"
"ftell|fputs|fgets|siglongjmp|sigdelset|killpg|tolower|toupper|daemon|"
"iconv_[a-z_]+|catopen|catgets|catclose|check_add_mapping$|sem_open|sem_close|"
"sem_unlink|do_futex_wait|sem_timedwait|unwind_stop|unwind_cleanup|longjmp_"
"compat|vfork_|elision_init|cr_|cri_|aio_|mq_|sem_init|waitpid$|sigcancel_"
"handler|sighandler_setxid|start_thread$|clock$|semctl$|shm_open$|shm_unlink$|"
"printf|dprintf|walker$|clear_once_control$|libcr_|sem_wait$|sem_trywait$|vfork|"
"pause$|wait$|msgrcv$|sigwait$|sigsuspend$|recvmsg$|sendmsg$|ftrylockfile$|"
"funlockfile$|tee$|setbuf$|setbuffer$|enlarge_userbuf$|convert_and_print$|"
"feraise|lio_|atomic_|err$|errx$|print_errno_message$|error_tail$|clntunix_|"
"sem_destroy|setxid_mark_thread|feupdate|send$|connect$|longjmp|pwrite|accept$|"
"stpncpy$|writeunix$|xflowf$|mbrlen$)",
regex_opts);
return std::regex_search(_func, _pattern);
}
//======================================================================================//
//
inline void
consume()
{
consume_parameters(initialize_expr, bpatch, use_mpi, stl_func_instr, cstd_func_instr,
werror, loop_level_instr, error_print, binary_rewrite, debug_print,
expect_error, is_static_exe, available_module_functions,
instrumented_module_functions);
}
//
namespace
{
static auto _consumed = (consume(), true);
}
Разница между файлами не показана из-за своего большого размера Загрузить разницу
+241
Просмотреть файл
@@ -0,0 +1,241 @@
#include <cstdint>
#include <cstdio>
#include <fstream>
#include <memory>
#include <perfetto.h>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <utility>
#include <vector>
#include "timemory/backends/process.hpp"
#include "timemory/environment.hpp"
#include "timemory/mpl/apply.hpp"
#if !defined(JOIN)
# define JOIN(...) tim::mpl::apply<std::string>::join(__VA_ARGS__)
#endif
PERFETTO_DEFINE_CATEGORIES(
perfetto::Category("hosttrace").SetDescription("Function trace"));
extern "C" void
hosttrace_trace_finalize();
namespace
{
bool
get_debug()
{
static bool _v = tim::get_env("HOSTTRACE_DEBUG", false);
return _v;
}
auto
ensure_finalization()
{
if(get_debug())
fprintf(stderr, "[%s]\n", __FUNCTION__);
return tim::scope::destructor{ []() { hosttrace_trace_finalize(); } };
}
auto&
get_trace_session()
{
static std::unique_ptr<perfetto::TracingSession> _session{};
return _session;
}
enum class State : unsigned short
{
PreInit = 0,
Active,
Finalized
};
auto&
get_state()
{
static State _v{ State::PreInit };
return _v;
}
auto&
get_output_filename()
{
static auto _v = []() {
auto _tmp = tim::get_env<std::string>(
"HOSTTRACE_OUTPUT_FILE",
JOIN('/', tim::get_env<std::string>("PWD", ".", false),
"hosttrace.perfetto-trace-%p"));
auto _pos = _tmp.find("%p");
if(_pos != std::string::npos)
_tmp.replace(_pos, 2, std::to_string(tim::process::get_id()));
return _tmp;
}();
return _v;
}
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()
{
// if get_backend() returns 'system' or 'all', this is true
return (get_backend() != "inprocess");
}
bool
hosttrace_init_perfetto()
{
if(get_debug())
fprintf(stderr, "[%s]\n", __FUNCTION__);
if(get_state() != State::PreInit)
return false;
// 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);
perfetto::TracingInitArgs args{};
perfetto::TraceConfig cfg{};
perfetto::protos::gen::TrackEventConfig track_event_cfg{};
cfg.add_buffers()->set_size_kb(buffer_size);
auto* ds_cfg = cfg.add_data_sources()->mutable_config();
ds_cfg->set_name("track_event");
ds_cfg->set_track_event_config_raw(track_event_cfg.SerializeAsString());
args.shmem_size_hint_kb = shmem_size_hint;
if(get_backend() != "inprocess")
args.backends |= perfetto::kSystemBackend;
if(get_backend() != "system")
args.backends |= perfetto::kInProcessBackend;
perfetto::Tracing::Initialize(args);
perfetto::TrackEvent::Register();
(void) get_output_filename();
tim::print_env(std::cerr);
if(!is_system_backend())
{
auto& tracing_session = get_trace_session();
tracing_session = perfetto::Tracing::NewTrace();
tracing_session->Setup(cfg);
tracing_session->StartBlocking();
}
get_state() = State::Active;
// if static objects are destroyed in the inverse order of when they are
// created this should ensure that finalization is called before perfetto
// ends the tracing session
static auto _ensure_finalization = ensure_finalization();
return true;
}
} // namespace
extern "C"
{
void hosttrace_push_trace(const char* name)
{
if(get_debug())
fprintf(stderr, "[%s] %s\n", __FUNCTION__, name);
// return if not active
if(get_state() != State::Active && !hosttrace_init_perfetto())
return;
TRACE_EVENT_BEGIN("hosttrace", perfetto::StaticString(name));
}
void hosttrace_pop_trace(const char* name)
{
if(get_debug())
fprintf(stderr, "[%s] %s\n", __FUNCTION__, name);
// return if not active
if(get_state() != State::Active)
return;
TRACE_EVENT_END("hosttrace");
}
void hosttrace_trace_init(const char*, bool, const char*)
{
if(get_debug())
fprintf(stderr, "[%s]\n", __FUNCTION__);
hosttrace_init_perfetto();
}
void hosttrace_trace_finalize(void)
{
if(get_debug())
fprintf(stderr, "[%s]\n", __FUNCTION__);
if(get_state() != State::Active)
return;
get_state() = State::Finalized;
if(!is_system_backend())
{
// Make sure the last event is closed for this example.
perfetto::TrackEvent::Flush();
auto& tracing_session = get_trace_session();
tracing_session->StopBlocking();
std::vector<char> trace_data{ tracing_session->ReadTraceBlocking() };
if(trace_data.empty())
{
fprintf(stderr,
"[%s]> trace data is empty. File '%s' will not be written...\n",
__FUNCTION__, get_output_filename().c_str());
return;
}
// Write the trace into a file.
fprintf(stderr, "[%s]> Outputting '%s'. Trace data: %lu bytes...\n",
__FUNCTION__, get_output_filename().c_str(),
(unsigned long) trace_data.size());
std::ofstream output{};
output.open(get_output_filename(), std::ios::out | std::ios::binary);
if(!output)
fprintf(stderr, "[%s]> Error opening '%s'...\n", __FUNCTION__,
get_output_filename().c_str());
else
output.write(&trace_data[0], trace_data.size());
output.close();
}
}
void hosttrace_trace_set_env(const char* env_name, const char* env_val)
{
if(get_debug())
fprintf(stderr, "[%s] Setting env: %s=%s\n", __FUNCTION__, env_name, env_val);
tim::set_env(env_name, env_val, 0);
}
}
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_perfetto is more likely
auto _ensure_finalization = ensure_finalization();
} // namespace
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
+36
Просмотреть файл
@@ -0,0 +1,36 @@
if(TARGET transpose)
add_test(
NAME transpose-binary-rewrite
COMMAND $<TARGET_FILE:hosttrace-exe> -o transpose.inst -- ${CMAKE_BINARY_DIR}/transpose/transpose
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tests
)
add_test(
NAME transpose-binary-rewrite-run
COMMAND ./transpose.inst
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tests
)
add_test(
NAME transpose-runtime-instrumentation
COMMAND $<TARGET_FILE:hosttrace-exe> -- ${CMAKE_BINARY_DIR}/transpose/transpose
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tests
)
set_tests_properties(
transpose-binary-rewrite-run
PROPERTIES
DEPENDS transpose-binary-rewrite
)
get_filename_component(DYNINST_LIB_DIR "${DYNINST_API_RT}" DIRECTORY CACHE)
set_tests_properties(
transpose-binary-rewrite
transpose-binary-rewrite-run
transpose-runtime-instrumentation
PROPERTIES
ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}:${DYNINST_LIB_DIR}:$ENV{LD_LIBRARY_PATH}"
TIMEOUT 600
)
endif()