Hosttrace via Dyninst
- complete with ctest support
Этот коммит содержится в:
@@ -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
|
||||
...
|
||||
@@ -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'
|
||||
...
|
||||
@@ -30,3 +30,4 @@
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
/build*
|
||||
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -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()
|
||||
@@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
|
||||
|
||||
project(hosttrace-dyninst-examples
|
||||
LANGUAGES CXX)
|
||||
|
||||
add_subdirectory(transpose)
|
||||
@@ -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)
|
||||
@@ -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.*
|
||||
|
||||
@@ -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.*
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
*/
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
//======================================================================================//
|
||||
//
|
||||
@@ -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
|
||||
...
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
//
|
||||
//======================================================================================//
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
@@ -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
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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__; \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -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"
|
||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -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
|
||||
@@ -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_
|
||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@@ -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();
|
||||
@@ -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()
|
||||
Ссылка в новой задаче
Block a user