diff --git a/.github/workflows/ubuntu-focal.yml b/.github/workflows/ubuntu-focal.yml index e4490fd3..9d8b9aa8 100644 --- a/.github/workflows/ubuntu-focal.yml +++ b/.github/workflows/ubuntu-focal.yml @@ -573,4 +573,3 @@ jobs: -DOMNITRACE_MAX_THREADS=32 -DOMNITRACE_DISABLE_EXAMPLES="transpose;rccl" -DOMNITRACE_BUILD_NUMBER=${{ github.run_attempt }} - -DMPI_HEADERS_ALLOW_MPICH=ON diff --git a/cmake/Packages.cmake b/cmake/Packages.cmake index 193b82d4..e1d50a68 100644 --- a/cmake/Packages.cmake +++ b/cmake/Packages.cmake @@ -49,8 +49,10 @@ set(OMNITRACE_EXTENSION_LIBRARIES omnitrace::omnitrace-perfetto) target_include_directories( - omnitrace-headers INTERFACE ${PROJECT_SOURCE_DIR}/source/lib/omnitrace - ${PROJECT_BINARY_DIR}/source/lib/omnitrace) + omnitrace-headers + INTERFACE ${PROJECT_BINARY_DIR}/source/lib ${PROJECT_BINARY_DIR}/source/lib/omnitrace + ${PROJECT_SOURCE_DIR}/source/lib ${PROJECT_SOURCE_DIR}/source/lib/omnitrace + ${PROJECT_SOURCE_DIR}/source/lib/omnitrace-user) # include threading because of rooflines target_link_libraries(omnitrace-headers INTERFACE omnitrace::omnitrace-threading) @@ -372,7 +374,7 @@ else() OMNITRACE_DYNINST_API_RT dyninstAPI_RT HINTS ${Dyninst_ROOT_DIR} ${Dyninst_DIR} PATHS ${Dyninst_ROOT_DIR} ${Dyninst_DIR} - PATH_SUFFIXES lib) + PATH_SUFFIXES lib NO_CACHE) if(OMNITRACE_DYNINST_API_RT) omnitrace_target_compile_definitions( diff --git a/examples/python/builtin.py b/examples/python/builtin.py index d075ebf0..19c71f1a 100755 --- a/examples/python/builtin.py +++ b/examples/python/builtin.py @@ -18,7 +18,7 @@ def inefficient(n): a += i for j in range(n): a += j - _len = a * n * n * n + _len = a * n * n _arr = [random.random() for _ in range(_len)] _sum = sum(_arr) print(f"[{_prefix}] ... sum of {_len} random elements: {_sum}") diff --git a/examples/python/external.py b/examples/python/external.py index 97b78cbd..99879d32 100755 --- a/examples/python/external.py +++ b/examples/python/external.py @@ -18,7 +18,7 @@ def inefficient(n): a += i for j in range(n): a += j - _len = a * n * n * n + _len = a * n * n _arr = [random.random() for _ in range(_len)] _sum = sum(_arr) print(f"[{_prefix}] ... sum of {_len} random elements: {_sum}") diff --git a/examples/python/noprofile.py b/examples/python/noprofile.py index db0aed2f..f2566f23 100755 --- a/examples/python/noprofile.py +++ b/examples/python/noprofile.py @@ -20,7 +20,7 @@ def inefficient(n): a += i for j in range(n): a += j - _len = a * n * n * n + _len = a * n * n _arr = [random.random() for _ in range(_len)] _sum = sum(_arr) print(f"[{_prefix}] ... sum of {_len} random elements: {_sum}") diff --git a/examples/python/source.py b/examples/python/source.py index c498af8f..2bef32b7 100755 --- a/examples/python/source.py +++ b/examples/python/source.py @@ -23,7 +23,7 @@ def inefficient(n): a += i for j in range(n): a += j - _len = a * n * n * n + _len = a * n * n _ret = np.random.rand(_len).sum() print(f"[{_prefix}] ... sum of {_len} random elements: {_ret}") return _ret @@ -41,7 +41,7 @@ def inefficient(n): a += i for j in range(n): a += j - _len = a * n * n * n + _len = a * n * n _arr = [random.random() for _ in range(_len)] _ret = _sum(_arr) print(f"[{_prefix}] ... sum of {_len} random elements: {_ret}") diff --git a/examples/user-api/user-api.cpp b/examples/user-api/user-api.cpp index 33df3822..e6908f64 100644 --- a/examples/user-api/user-api.cpp +++ b/examples/user-api/user-api.cpp @@ -1,10 +1,14 @@ +#include "omnitrace/categories.h" +#include "omnitrace/types.h" #include #include #include +#include #include #include +#include #include #include #include @@ -22,19 +26,16 @@ custom_push_region(const char* name); namespace { -int (*omnitrace_push_region_f)(const char*) = nullptr; -} +omnitrace_user_callbacks_t custom_callbacks = OMNITRACE_USER_CALLBACKS_INIT; +omnitrace_user_callbacks_t original_callbacks = OMNITRACE_USER_CALLBACKS_INIT; +} // namespace int main(int argc, char** argv) { - // get the internal callback to start a user-defined region - omnitrace_user_get_callbacks(OMNITRACE_USER_REGION, (void**) &omnitrace_push_region_f, - nullptr); - // assign the custom callback to start a user-defined region - if(omnitrace_push_region_f) - omnitrace_user_configure(OMNITRACE_USER_REGION, (void*) &custom_push_region, - nullptr); + custom_callbacks.push_region = &custom_push_region; + omnitrace_user_configure(OMNITRACE_USER_UNION_CONFIG, custom_callbacks, + &original_callbacks); omnitrace_user_push_region(argv[0]); omnitrace_user_push_region("initialization"); @@ -100,6 +101,26 @@ run(size_t nitr, long n) int custom_push_region(const char* name) { + if(!original_callbacks.push_region || !original_callbacks.push_annotated_region) + return OMNITRACE_USER_ERROR_NO_BINDING; + printf("Pushing custom region :: %s\n", name); - return (*omnitrace_push_region_f)(name); + + if(original_callbacks.push_annotated_region) + { + int32_t _err = errno; + char* _msg = nullptr; + char _buff[1024]; + if(_err != 0) _msg = strerror_r(_err, _buff, sizeof(_buff)); + + omnitrace_annotation_t _annotations[] = { + { "errno", OMNITRACE_INT32, &_err }, { "strerror", OMNITRACE_STRING, _msg } + }; + + errno = 0; // reset errno + return (*original_callbacks.push_annotated_region)( + name, _annotations, sizeof(_annotations) / sizeof(omnitrace_annotation_t)); + } + + return (*original_callbacks.push_region)(name); } diff --git a/external/timemory b/external/timemory index 7a6a361e..04045617 160000 --- a/external/timemory +++ b/external/timemory @@ -1 +1 @@ -Subproject commit 7a6a361eb895c30d29cf0652ea26f37c0f7525b4 +Subproject commit 040456175a81d50beb2ed55d62c2a39f7644776e diff --git a/source/lib/common/defines.h.in b/source/lib/common/defines.h.in index 9ac4e7fa..72f0bf84 100644 --- a/source/lib/common/defines.h.in +++ b/source/lib/common/defines.h.in @@ -74,6 +74,7 @@ #define OMNITRACE_INLINE OMNITRACE_ATTRIBUTE(always_inline) inline #define OMNITRACE_NOINLINE OMNITRACE_ATTRIBUTE(noinline) #define OMNITRACE_HOT OMNITRACE_ATTRIBUTE(hot) +#define OMNITRACE_COLD OMNITRACE_ATTRIBUTE(cold) #define OMNITRACE_CONST OMNITRACE_ATTRIBUTE(const) #define OMNITRACE_PURE OMNITRACE_ATTRIBUTE(pure) #define OMNITRACE_WEAK OMNITRACE_ATTRIBUTE(weak) diff --git a/source/lib/omnitrace-dl/dl.cpp b/source/lib/omnitrace-dl/dl.cpp index c46c9054..ed700872 100644 --- a/source/lib/omnitrace-dl/dl.cpp +++ b/source/lib/omnitrace-dl/dl.cpp @@ -39,6 +39,8 @@ #include "common/join.hpp" #include "common/setup.hpp" #include "dl.hpp" +#include "omnitrace/categories.h" +#include "omnitrace/types.h" #include #include @@ -256,6 +258,10 @@ struct OMNITRACE_HIDDEN_API indirect OMNITRACE_DLSYM(omnitrace_pop_trace_f, m_omnihandle, "omnitrace_pop_trace"); OMNITRACE_DLSYM(omnitrace_push_region_f, m_omnihandle, "omnitrace_push_region"); OMNITRACE_DLSYM(omnitrace_pop_region_f, m_omnihandle, "omnitrace_pop_region"); + OMNITRACE_DLSYM(omnitrace_push_category_region_f, m_omnihandle, + "omnitrace_push_category_region"); + OMNITRACE_DLSYM(omnitrace_pop_category_region_f, m_omnihandle, + "omnitrace_pop_category_region"); OMNITRACE_DLSYM(omnitrace_register_source_f, m_omnihandle, "omnitrace_register_source"); OMNITRACE_DLSYM(omnitrace_register_coverage_f, m_omnihandle, @@ -330,37 +336,43 @@ struct OMNITRACE_HIDDEN_API indirect if(omnitrace_user_configure_f) { - (*omnitrace_user_configure_f)( - OMNITRACE_USER_START_STOP, - reinterpret_cast(&omnitrace_user_start_trace_dl), - reinterpret_cast(&omnitrace_user_stop_trace_dl)); - (*omnitrace_user_configure_f)( - OMNITRACE_USER_START_STOP_THREAD, - reinterpret_cast(&omnitrace_user_start_thread_trace_dl), - reinterpret_cast(&omnitrace_user_stop_thread_trace_dl)); - (*omnitrace_user_configure_f)( - OMNITRACE_USER_REGION, - reinterpret_cast(&omnitrace_user_push_region_dl), - reinterpret_cast(&omnitrace_user_pop_region_dl)); + omnitrace_user_callbacks_t _cb = {}; + _cb.start_trace = &omnitrace_user_start_trace_dl; + _cb.stop_trace = &omnitrace_user_stop_trace_dl; + _cb.start_thread_trace = &omnitrace_user_start_thread_trace_dl; + _cb.stop_thread_trace = &omnitrace_user_stop_thread_trace_dl; + _cb.push_region = &omnitrace_user_push_region_dl; + _cb.pop_region = &omnitrace_user_pop_region_dl; + _cb.push_annotated_region = &omnitrace_user_push_annotated_region_dl; + _cb.pop_annotated_region = &omnitrace_user_pop_annotated_region_dl; + (*omnitrace_user_configure_f)(OMNITRACE_USER_REPLACE_CONFIG, _cb, nullptr); } } public: - // omnitrace functions - void (*omnitrace_init_library_f)(void) = nullptr; - void (*omnitrace_init_tooling_f)(void) = nullptr; - void (*omnitrace_init_f)(const char*, bool, const char*) = nullptr; - void (*omnitrace_finalize_f)(void) = nullptr; - void (*omnitrace_set_env_f)(const char*, const char*) = nullptr; - void (*omnitrace_set_mpi_f)(bool, bool) = nullptr; + using user_cb_t = omnitrace_user_callbacks_t; + + // libomnitrace functions + void (*omnitrace_init_library_f)(void) = nullptr; + void (*omnitrace_init_tooling_f)(void) = nullptr; + void (*omnitrace_init_f)(const char*, bool, const char*) = nullptr; + void (*omnitrace_finalize_f)(void) = nullptr; + void (*omnitrace_set_env_f)(const char*, const char*) = nullptr; + void (*omnitrace_set_mpi_f)(bool, bool) = nullptr; void (*omnitrace_register_source_f)(const char*, const char*, size_t, size_t, - const char*) = nullptr; - void (*omnitrace_register_coverage_f)(const char*, const char*, size_t) = nullptr; - void (*omnitrace_push_trace_f)(const char*) = nullptr; - void (*omnitrace_pop_trace_f)(const char*) = nullptr; - int (*omnitrace_push_region_f)(const char*) = nullptr; - int (*omnitrace_pop_region_f)(const char*) = nullptr; - int (*omnitrace_user_configure_f)(int, void*, void*) = nullptr; + const char*) = nullptr; + void (*omnitrace_register_coverage_f)(const char*, const char*, size_t) = nullptr; + void (*omnitrace_push_trace_f)(const char*) = nullptr; + void (*omnitrace_pop_trace_f)(const char*) = nullptr; + int (*omnitrace_push_region_f)(const char*) = nullptr; + int (*omnitrace_pop_region_f)(const char*) = nullptr; + int (*omnitrace_push_category_region_f)(omnitrace_category_t, const char*, + omnitrace_annotation_t*, size_t) = nullptr; + int (*omnitrace_pop_category_region_f)(omnitrace_category_t, const char*, + omnitrace_annotation_t*, size_t) = nullptr; + + // libomnitrace-user functions + int (*omnitrace_user_configure_f)(int, user_cb_t, user_cb_t*) = nullptr; // KokkosP functions void (*kokkosp_print_help_f)(char*) = nullptr; @@ -626,30 +638,66 @@ extern "C" } } - void omnitrace_push_region(const char* name) + int omnitrace_push_region(const char* name) { - if(!dl::get_active()) return; + if(!dl::get_active()) return 0; if(dl::get_thread_enabled()) { - OMNITRACE_DL_INVOKE(get_indirect().omnitrace_push_region_f, name); + return OMNITRACE_DL_INVOKE(get_indirect().omnitrace_push_region_f, name); } else { ++dl::get_thread_count(); } + return 0; } - void omnitrace_pop_region(const char* name) + int omnitrace_pop_region(const char* name) { - if(!dl::get_active()) return; + if(!dl::get_active()) return 0; if(dl::get_thread_enabled()) { - OMNITRACE_DL_INVOKE(get_indirect().omnitrace_pop_region_f, name); + return OMNITRACE_DL_INVOKE(get_indirect().omnitrace_pop_region_f, name); } else { if(dl::get_thread_count()-- == 0) omnitrace_user_start_thread_trace_dl(); } + return 0; + } + + int omnitrace_push_category_region(omnitrace_category_t _category, const char* name, + omnitrace_annotation_t* _annotations, + size_t _annotation_count) + { + if(!dl::get_active()) return 0; + if(dl::get_thread_enabled()) + { + return OMNITRACE_DL_INVOKE(get_indirect().omnitrace_push_category_region_f, + _category, name, _annotations, _annotation_count); + } + else + { + ++dl::get_thread_count(); + } + return 0; + } + + int omnitrace_pop_category_region(omnitrace_category_t _category, const char* name, + omnitrace_annotation_t* _annotations, + size_t _annotation_count) + { + if(!dl::get_active()) return 0; + if(dl::get_thread_enabled()) + { + return OMNITRACE_DL_INVOKE(get_indirect().omnitrace_pop_category_region_f, + _category, name, _annotations, _annotation_count); + } + else + { + ++dl::get_thread_count(); + } + return 0; } void omnitrace_set_env(const char* a, const char* b) @@ -724,6 +772,26 @@ extern "C" return OMNITRACE_DL_INVOKE(get_indirect().omnitrace_pop_region_f, name); } + int omnitrace_user_push_annotated_region_dl(const char* name, + omnitrace_annotation_t* _annotations, + size_t _annotation_count) + { + if(!dl::get_active()) return 0; + return OMNITRACE_DL_INVOKE(get_indirect().omnitrace_push_category_region_f, + OMNITRACE_CATEGORY_USER, name, _annotations, + _annotation_count); + } + + int omnitrace_user_pop_annotated_region_dl(const char* name, + omnitrace_annotation_t* _annotations, + size_t _annotation_count) + { + if(!dl::get_active()) return 0; + return OMNITRACE_DL_INVOKE(get_indirect().omnitrace_pop_category_region_f, + OMNITRACE_CATEGORY_USER, name, _annotations, + _annotation_count); + } + //----------------------------------------------------------------------------------// // // KokkosP diff --git a/source/lib/omnitrace-dl/dl.hpp b/source/lib/omnitrace-dl/dl.hpp index c3e4b5aa..bf60b0ec 100644 --- a/source/lib/omnitrace-dl/dl.hpp +++ b/source/lib/omnitrace-dl/dl.hpp @@ -21,7 +21,7 @@ // SOFTWARE. #ifndef OMNITRACE_DL_HPP_ -#define OMNITRACE_DL_HPP_ 1 +#define OMNITRACE_DL_HPP_ #if defined(OMNITRACE_DL_SOURCE) && (OMNITRACE_DL_SOURCE > 0) # include "common/defines.h" @@ -78,8 +78,15 @@ extern "C" void omnitrace_set_mpi(bool use, bool attached) OMNITRACE_PUBLIC_API; void omnitrace_push_trace(const char* name) OMNITRACE_PUBLIC_API; void omnitrace_pop_trace(const char* name) OMNITRACE_PUBLIC_API; - void omnitrace_push_region(const char*) OMNITRACE_PUBLIC_API; - void omnitrace_pop_region(const char*) OMNITRACE_PUBLIC_API; + int omnitrace_push_region(const char*) OMNITRACE_PUBLIC_API; + int omnitrace_pop_region(const char*) OMNITRACE_PUBLIC_API; + int omnitrace_push_category_region(omnitrace_category_t, const char*, + omnitrace_annotation_t*, + size_t) OMNITRACE_PUBLIC_API; + int omnitrace_pop_category_region(omnitrace_category_t, const char*, + omnitrace_annotation_t*, + size_t) OMNITRACE_PUBLIC_API; + void omnitrace_register_source(const char* file, const char* func, size_t line, size_t address, const char* source) OMNITRACE_PUBLIC_API; @@ -99,6 +106,11 @@ extern "C" int omnitrace_user_push_region_dl(const char*) OMNITRACE_HIDDEN_API; int omnitrace_user_pop_region_dl(const char*) OMNITRACE_HIDDEN_API; + int omnitrace_user_push_annotated_region_dl(const char*, omnitrace_annotation_t*, + size_t) OMNITRACE_HIDDEN_API; + int omnitrace_user_pop_annotated_region_dl(const char*, omnitrace_annotation_t*, + size_t) OMNITRACE_HIDDEN_API; + // KokkosP struct OMNITRACE_HIDDEN_API SpaceHandle { diff --git a/source/lib/omnitrace-user/CMakeLists.txt b/source/lib/omnitrace-user/CMakeLists.txt index 9c9ef6ee..0d668c94 100644 --- a/source/lib/omnitrace-user/CMakeLists.txt +++ b/source/lib/omnitrace-user/CMakeLists.txt @@ -35,9 +35,11 @@ set_target_properties( omnitrace_strip_target(omnitrace-user-library) -install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/omnitrace/user.h - ${CMAKE_CURRENT_SOURCE_DIR}/omnitrace/types.h - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/omnitrace) +install( + FILES ${CMAKE_CURRENT_SOURCE_DIR}/omnitrace/user.h + ${CMAKE_CURRENT_SOURCE_DIR}/omnitrace/types.h + ${CMAKE_CURRENT_SOURCE_DIR}/omnitrace/categories.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/omnitrace) install( TARGETS omnitrace-user-library diff --git a/source/lib/omnitrace-user/omnitrace/categories.h b/source/lib/omnitrace-user/omnitrace/categories.h new file mode 100644 index 00000000..d71a2b96 --- /dev/null +++ b/source/lib/omnitrace-user/omnitrace/categories.h @@ -0,0 +1,188 @@ +// MIT License +// +// Copyright (c) 2022 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. + +#ifndef OMNITRACE_CATEGORIES_H_ +#define OMNITRACE_CATEGORIES_H_ + +#include +#include + +#if defined(__cplusplus) +extern "C" +{ +#endif + + /// @typedef omnitrace_category_t + /// @brief Identifier for categories + /// + typedef enum OMNITRACE_CATEGORIES + { + // Do not use first enum value + OMNITRACE_CATEGORY_NONE = 0, + // arrange these in the order most likely to + // be used since they have to be iterated over + OMNITRACE_CATEGORY_PYTHON, + OMNITRACE_CATEGORY_USER, + OMNITRACE_CATEGORY_HOST, + OMNITRACE_CATEGORY_DEVICE_HIP, + OMNITRACE_CATEGORY_DEVICE_HSA, + OMNITRACE_CATEGORY_ROCM_HIP, + OMNITRACE_CATEGORY_ROCM_HSA, + OMNITRACE_CATEGORY_ROCM_ROCTX, + OMNITRACE_CATEGORY_ROCM_SMI, + OMNITRACE_CATEGORY_ROCM_SMI_BUSY, + OMNITRACE_CATEGORY_ROCM_SMI_TEMP, + OMNITRACE_CATEGORY_ROCM_SMI_POWER, + OMNITRACE_CATEGORY_ROCM_SMI_MEMORY_USAGE, + OMNITRACE_CATEGORY_ROCM_RCCL, + OMNITRACE_CATEGORY_ROCTRACER, + OMNITRACE_CATEGORY_ROCPROFILER, + OMNITRACE_CATEGORY_SAMPLING, + OMNITRACE_CATEGORY_PTHREAD, + OMNITRACE_CATEGORY_KOKKOS, + OMNITRACE_CATEGORY_MPI, + OMNITRACE_CATEGORY_OMPT, + OMNITRACE_CATEGORY_PROCESS_SAMPLING, + OMNITRACE_CATEGORY_COMM_DATA, + OMNITRACE_CATEGORY_CRITICAL_TRACE, + OMNITRACE_CATEGORY_HOST_CRITICAL_TRACE, + OMNITRACE_CATEGORY_DEVICE_CRITICAL_TRACE, + OMNITRACE_CATEGORY_CAUSAL, + OMNITRACE_CATEGORY_CPU_FREQ, + OMNITRACE_CATEGORY_PROCESS_PAGE, + OMNITRACE_CATEGORY_PROCESS_VIRT, + OMNITRACE_CATEGORY_PROCESS_PEAK, + OMNITRACE_CATEGORY_PROCESS_CONTEXT_SWITCH, + OMNITRACE_CATEGORY_PROCESS_PAGE_FAULT, + OMNITRACE_CATEGORY_PROCESS_USER_MODE_TIME, + OMNITRACE_CATEGORY_PROCESS_KERNEL_MODE_TIME, + OMNITRACE_CATEGORY_THREAD_PAGE_FAULT, + OMNITRACE_CATEGORY_THREAD_PEAK_MEMORY, + OMNITRACE_CATEGORY_THREAD_CONTEXT_SWITCH, + OMNITRACE_CATEGORY_THREAD_HARDWARE_COUNTER, + OMNITRACE_CATEGORY_KERNEL_HARDWARE_COUNTER, + OMNITRACE_CATEGORY_NUMA, + OMNITRACE_CATEGORY_LAST + // the value of below enum is used for iterating + // over the enum in C++ templates. It MUST + // be the last enumerated id + } omnitrace_category_t; + + /// @typedef omnitrace_annotation_type_t + /// @brief Identifier for the data type of the annotation. + /// if the data type is not a pointer, pass the address of + /// data. + typedef enum OMNITRACE_ANNOTATION_TYPE + { + // Do not use first enum value + OMNITRACE_VALUE_NONE = 0, + // arrange these in the order most likely to + // be used since they have to be iterated over + OMNITRACE_VALUE_CSTR = 1, + OMNITRACE_STRING = OMNITRACE_VALUE_CSTR, + OMNITRACE_VALUE_SIZE_T = 2, + OMNITRACE_SIZE_T = OMNITRACE_VALUE_SIZE_T, + OMNITRACE_VALUE_INT64 = 3, + OMNITRACE_INT64 = OMNITRACE_VALUE_INT64, + OMNITRACE_I64 = OMNITRACE_VALUE_INT64, + OMNITRACE_VALUE_UINT64 = 4, + OMNITRACE_UINT64 = OMNITRACE_VALUE_UINT64, + OMNITRACE_U64 = OMNITRACE_VALUE_UINT64, + OMNITRACE_VALUE_FLOAT64 = 5, + OMNITRACE_FLOAT64 = OMNITRACE_VALUE_FLOAT64, + OMNITRACE_FP64 = OMNITRACE_VALUE_FLOAT64, + OMNITRACE_VALUE_VOID_P = 6, + OMNITRACE_VOID_P = OMNITRACE_VALUE_VOID_P, + OMNITRACE_PTR = OMNITRACE_VALUE_VOID_P, + OMNITRACE_VALUE_INT32 = 7, + OMNITRACE_INT32 = OMNITRACE_VALUE_INT32, + OMNITRACE_I32 = OMNITRACE_VALUE_INT32, + OMNITRACE_VALUE_UINT32 = 8, + OMNITRACE_UINT32 = OMNITRACE_VALUE_UINT32, + OMNITRACE_U32 = OMNITRACE_VALUE_UINT32, + OMNITRACE_VALUE_FLOAT32 = 9, + OMNITRACE_FLOAT32 = OMNITRACE_VALUE_FLOAT32, + OMNITRACE_FP32 = OMNITRACE_VALUE_FLOAT32, + OMNITRACE_VALUE_INT16 = 10, + OMNITRACE_INT16 = OMNITRACE_VALUE_INT16, + OMNITRACE_I16 = OMNITRACE_VALUE_INT16, + OMNITRACE_VALUE_UINT16 = 11, + OMNITRACE_UINT16 = OMNITRACE_VALUE_UINT16, + OMNITRACE_U16 = OMNITRACE_VALUE_UINT16, + // the value of below enum is used for iterating + // over the enum in C++ templates. It MUST + // be the last enumerated id + OMNITRACE_VALUE_LAST + } omnitrace_annotation_type_t; + + /// @typedef omnitrace_annotation + /// @brief A struct containing annotation data to be included in the perfetto trace. + /// + /// @code{.cpp} + /// #include + /// #include + /// + /// #include + /// + /// double + /// compute_residual(size_t n, double* data); + /// + /// double + /// compute(size_t n, double* data, size_t nitr, double tolerance) + /// { + /// omnitrace_annotation_t _annotations[] = { + /// { "iteration", OMNITRACE_VALUE_SIZE_T, nullptr }, + /// { "residual", OMNITRACE_VALUE_FLOAT64, nullptr }, + /// { "data", OMNITRACE_VALUE_PTR, data }, + /// { "size", OMNITRACE_VALUE_SIZE_T, &n }, + /// { "tolerance", OMNITRACE_VALUE_FLOAT64, &tolerance }, + /// nullptr + /// }; + /// + /// double residual = tolerance; + /// for(size_t i = 0; i < nitr; ++i) + /// { + /// omnitrace_user_push_annotated_region("compute", &_annotations); + /// + /// residual = compute_residual(n, data); + /// + /// _annotations[0].value = &i; + /// _annotations[1].value = &residual; + /// omnitrace_user_pop_annotated_region("compute", &_annotations); + /// } + /// + /// return residual; + /// } + /// @endcode + /// + typedef struct omnitrace_annotation + { + const char* name; + uintptr_t type; + void* value; + } omnitrace_annotation_t; + +#if defined(__cplusplus) +} +#endif + +#endif // OMNITRACE_TYPES_H_ diff --git a/source/lib/omnitrace-user/omnitrace/types.h b/source/lib/omnitrace-user/omnitrace/types.h index 4432134f..ba9f5506 100644 --- a/source/lib/omnitrace-user/omnitrace/types.h +++ b/source/lib/omnitrace-user/omnitrace/types.h @@ -21,8 +21,9 @@ // SOFTWARE. #ifndef OMNITRACE_TYPES_H_ -#define OMNITRACE_TYPES_H_ 1 +#define OMNITRACE_TYPES_H_ +#include #include #if defined(__cplusplus) @@ -30,59 +31,98 @@ extern "C" { #endif - /// @enum OMNITRACE_USER_ERROR - /// @brief Identifier for errors - /// - typedef enum OMNITRACE_USER_ERROR - { - OMNITRACE_USER_SUCCESS = 0, ///< No error - OMNITRACE_USER_ERROR_NO_BINDING, ///< Function pointer was not assigned - OMNITRACE_USER_ERROR_BAD_VALUE, ///< Provided value was invalid - OMNITRACE_USER_ERROR_INVALID_CATEGORY, ///< Invalid user binding category - OMNITRACE_USER_ERROR_INTERNAL, ///< Internal error occurred within libomnitrace - OMNITRACE_USER_ERROR_LAST - } omnitrace_user_error_t; + struct omnitrace_annotation; + typedef int (*omnitrace_trace_func_t)(void); + typedef int (*omnitrace_region_func_t)(const char*); + typedef int (*omnitrace_annotated_region_func_t)(const char*, omnitrace_annotation*, + size_t); - /// @enum OMNITRACE_USER_BINDINGS - /// @brief Identifier for function pointer categories + /// @typedef omnitrace_user_callbacks_t + /// @brief Struct containing the callbacks for the user API /// @code{.cpp} - /// int (*omnitrace_push_region_f)(const char*) = nullptr; /// - /// int custom_push_region(const char* name) + /// #include + /// #include + /// + /// omnitrace_user_callbacks_t custom_callbacks = OMNITRACE_USER_CALLBACKS_INIT; + /// omnitrace_user_callbacks_t original_callbacks = OMNITRACE_USER_CALLBACKS_INIT; + /// + /// // in our custom push region, we are going to redirect the unannotated user push + /// // region to annotate the trace entries with the global errno and if errno is + /// // non-zero, store the message + /// int + /// custom_push_region(const char* name) /// { - /// // custom push region prints message before calling internal callback - /// printf("Pushing region %s\n", name); - /// return (*omnitrace_push_region_f)(name); + /// if(!original_callbacks.push_annotated_region) + /// return OMNITRACE_USER_ERROR_NO_BINDING; + /// + /// int32_t _err = errno; + /// const char* _msg = nullptr; + /// char _buff[1024]; + /// if(_err != 0) _msg = strerror_r(_err, _buff, sizeof(_buff)); + /// + /// omnitrace_annotation_t _annotates[] = { { "errno", OMNITRACE_INT32, &_err }, + /// { "msg", OMNITRACE_STRING, _msg } }; + /// return (*original_callbacks.push_annotated_region)(name, &_annotations, 2); /// } /// - /// int main(int argc, char** argv) + /// int + /// main(int argc, char** argv) /// { - /// // get the internal callback to start a user-defined region - /// omnitrace_user_get_callbacks(OMNITRACE_USER_REGION, - /// (void**) &omnitrace_push_region_f, - /// nullptr); - /// // assign the custom callback to start a user-defined region - /// if(omnitrace_push_region_f) - /// omnitrace_user_configure(OMNITRACE_USER_REGION, - /// (void*) &custom_push_region, - /// nullptr); + /// custom_callbacks.push_region = &custom_push_region; + /// omnitrace_user_configure(OMNITRACE_USER_UNION_CONFIG, custom_callbacks, + /// &original_callbacks); /// // ... /// } /// /// @endcode - typedef enum OMNITRACE_USER_BINDINGS + typedef struct omnitrace_user_callbacks { - OMNITRACE_USER_START_STOP = - 0, ///< Function pointers which control global start/stop - OMNITRACE_USER_START_STOP_THREAD, ///< Function pointers which control per-thread - ///< start/stop - OMNITRACE_USER_REGION, ///< Function pointers which generate user-defined regions - OMNITRACE_USER_SAMPLE, ///< Function pointer which generate samples - OMNITRACE_USER_BINDINGS_LAST - } omnitrace_user_bindings_t; + omnitrace_trace_func_t start_trace; + omnitrace_trace_func_t stop_trace; + omnitrace_trace_func_t start_thread_trace; + omnitrace_trace_func_t stop_thread_trace; + omnitrace_region_func_t push_region; + omnitrace_region_func_t pop_region; + omnitrace_annotated_region_func_t push_annotated_region; + omnitrace_annotated_region_func_t pop_annotated_region; + } omnitrace_user_callbacks_t; + + /// @typedef omnitrace_user_configure_mode_t + /// @brief Identifier for errors + /// + typedef enum OMNITRACE_USER_CONFIGURE_MODE + { + // clang-format off + OMNITRACE_USER_UNION_CONFIG = 0, ///< Replace the callbacks in the current config with the non-null callbacks in the provided config + OMNITRACE_USER_REPLACE_CONFIG, ///< Replace the entire config even if the provided config has null callbacks + OMNITRACE_USER_INTERSECT_CONFIG, ///< Produce a config which is the intersection of the current config and the provided config + OMNITRACE_USER_CONFIGURE_MODE_LAST + // clang-format on + } omnitrace_user_configure_mode_t; + + /// @typedef omnitrace_user_error_t + /// @brief Identifier for errors + /// + typedef enum OMNITRACE_USER_ERROR + { + OMNITRACE_USER_SUCCESS = 0, ///< No error + OMNITRACE_USER_ERROR_NO_BINDING, ///< Function pointer was not assigned + OMNITRACE_USER_ERROR_BAD_VALUE, ///< Provided value was invalid + OMNITRACE_USER_ERROR_INVALID_CATEGORY, ///< Invalid user binding category + OMNITRACE_USER_ERROR_INTERNAL, ///< Internal error occurred within libomnitrace + OMNITRACE_USER_ERROR_LAST + } omnitrace_user_error_t; #if defined(__cplusplus) } #endif +#ifndef OMNITRACE_USER_CALLBACKS_INIT +# define OMNITRACE_USER_CALLBACKS_INIT \ + { \ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL \ + } +#endif + #endif // OMNITRACE_TYPES_H_ diff --git a/source/lib/omnitrace-user/omnitrace/user.h b/source/lib/omnitrace-user/omnitrace/user.h index 8fb263a0..bdb7f390 100644 --- a/source/lib/omnitrace-user/omnitrace/user.h +++ b/source/lib/omnitrace-user/omnitrace/user.h @@ -21,7 +21,7 @@ // SOFTWARE. #ifndef OMNITRACE_USER_H_ -#define OMNITRACE_USER_H_ 1 +#define OMNITRACE_USER_H_ #if defined(OMNITRACE_USER_SOURCE) && (OMNITRACE_USER_SOURCE > 0) # if !defined(OMNITRACE_PUBLIC_API) @@ -33,6 +33,7 @@ # endif #endif +#include "omnitrace/categories.h" #include "omnitrace/types.h" #if defined(__cplusplus) @@ -79,16 +80,47 @@ extern "C" /// results in timemory vs. perfetto. extern int omnitrace_user_pop_region(const char*) OMNITRACE_PUBLIC_API; - /// @fn int omnitrace_user_configure(int category, void* begin_func, void* end_func) - /// @param category An @ref OMNITRACE_USER_BINDINGS value - /// @param begin_func The pointer to the function which corresponds to "starting" the - /// category, e.g. omnitrace_user_start_trace or omnitrace_user_push_region - /// @param end_func The pointer to the function which corresponds to "ending" the - /// category, e.g. omnitrace_user_stop_trace or omnitrace_user_pop_region + /// @fn int omnitrace_user_push_annotated_region(const char* id, + /// omnitrace_annotation_t* annotations, + /// size_t num_annotations) + /// @param id The string identifier for the region + /// @param annotations Array of @ref omnitrace_annotation_t instances + /// @param num_annotations Number of annotations + /// @return @ref OMNITRACE_USER_ERROR value + /// @brief Start a user defined region and adds the annotations to the perfetto trace. + extern int omnitrace_user_push_annotated_region(const char*, omnitrace_annotation_t*, + size_t) OMNITRACE_PUBLIC_API; + + /// @fn int omnitrace_user_pop_annotated_region(const char* id, + /// omnitrace_annotation_t* annotations, + /// size_t num_annotations) + /// @param id The string identifier for the region + /// @param annotations Array of @ref omnitrace_annotation_t instances + /// @param num_annotations Number of annotations /// @return @ref OMNITRACE_USER_ERROR value - /// @brief Configure the function pointers for a given category. This is handled by - /// omnitrace-dl at start up but the user can specify their own if desired. - extern int omnitrace_user_configure(int, void*, void*) OMNITRACE_PUBLIC_API; + /// @brief Stop a user defined region and adds the annotations to the perfetto trace. + extern int omnitrace_user_pop_annotated_region(const char*, omnitrace_annotation_t*, + size_t) OMNITRACE_PUBLIC_API; + + /// @fn int omnitrace_user_configure(omnitrace_user_configure_mode_t cfg, + /// omnitrace_user_callbacks_t new_callbacks, + /// omnitrace_user_callbacks_t* old_callbacks) + /// @param[in] config Specifies how the new callbacks are merged with the old callbacks + /// @param[in] new_callbacks An @ref omnitrace_user_callbacks_t instance specifying + /// the callbacks which should be invoked by the user API. + /// @param[out] old_callbacks Pointer to @ref omnitrace_user_callbacks_t which, + /// when non-NULL, will be assigned the former callbacks. + /// @return @ref omnitrace_user_error_t value + /// @brief Configure the function pointers invoked by the omnitrace user API. + /// The initial callbacks are set via the omnitrace-dl library when it is loaded but + /// the user can user this feature to turn on/off the user API or customize how the + /// the user callbacks occur. For example, the user could maintain one set of + /// callbacks which discard any annotation data or redirect all unannotated user + /// regions to the annotated user regions with annotations about some global state. + /// Changing the callbacks is thread-safe but not thread-local. + extern int omnitrace_user_configure( + omnitrace_user_configure_mode_t, omnitrace_user_callbacks_t new_callbacks, + omnitrace_user_callbacks_t* old_callbacks) OMNITRACE_PUBLIC_API; /// @fn int omnitrace_user_get_callbacks(int category, void** begin_func, void** /// end_func) @@ -100,7 +132,8 @@ extern "C" /// @return @ref OMNITRACE_USER_ERROR value /// @brief Get the current function pointers for a given category. The initial values /// are assigned by omnitrace-dl at start up. - extern int omnitrace_user_get_callbacks(int, void**, void**) OMNITRACE_PUBLIC_API; + extern int omnitrace_user_get_callbacks(omnitrace_user_callbacks_t*) + OMNITRACE_PUBLIC_API; /// @fn const char* omnitrace_user_error_string(int error_category) /// @param error_category OMNITRACE_USER_ERROR value diff --git a/source/lib/omnitrace-user/user.cpp b/source/lib/omnitrace-user/user.cpp index f1ec0391..ea16eb73 100644 --- a/source/lib/omnitrace-user/user.cpp +++ b/source/lib/omnitrace-user/user.cpp @@ -25,41 +25,24 @@ #endif #include "omnitrace/user.h" +#include "omnitrace/categories.h" #include "omnitrace/types.h" +#include #include #include +#include + +using annotation_t = omnitrace_annotation_t; namespace { -using trace_func_t = int (*)(void); -using region_func_t = int (*)(const char*); - -trace_func_t _start_trace = nullptr; -trace_func_t _stop_trace = nullptr; -trace_func_t _start_thread_trace = nullptr; -trace_func_t _stop_thread_trace = nullptr; -region_func_t _push_region = nullptr; -region_func_t _pop_region = nullptr; - -const char* -as_string(OMNITRACE_USER_BINDINGS _category) -{ - switch(_category) - { - case OMNITRACE_USER_START_STOP: return "OMNITRACE_USER_START_STOP"; - case OMNITRACE_USER_START_STOP_THREAD: return "OMNITRACE_USER_START_STOP_THREAD"; - case OMNITRACE_USER_REGION: return "OMNITRACE_USER_REGION"; - default: - { - fprintf(stderr, "[omnitrace][user] Unknown user binding category: %i\n", - static_cast(_category)); - fflush(stderr); - break; - } - } - return "OMNITRACE_USER_BINDINGS_unknown"; -} +using trace_func_t = omnitrace_trace_func_t; +using region_func_t = omnitrace_region_func_t; +using annotated_region_func_t = omnitrace_annotated_region_func_t; +using user_callbacks_t = omnitrace_user_callbacks_t; + +user_callbacks_t _callbacks = OMNITRACE_USER_CALLBACKS_INIT; template inline auto @@ -73,74 +56,106 @@ invoke(int (*_func)(Args...), Args... args) extern "C" { - int omnitrace_user_start_trace(void) { return invoke(_start_trace); } - int omnitrace_user_stop_trace(void) { return invoke(_stop_trace); } - int omnitrace_user_start_thread_trace(void) { return invoke(_start_thread_trace); } - int omnitrace_user_stop_thread_trace(void) { return invoke(_stop_thread_trace); } - int omnitrace_user_push_region(const char* id) { return invoke(_push_region, id); } - int omnitrace_user_pop_region(const char* id) { return invoke(_pop_region, id); } - - int omnitrace_user_configure(int category, void* begin_func, void* end_func) + int omnitrace_user_start_trace(void) { return invoke(_callbacks.start_trace); } + + int omnitrace_user_stop_trace(void) { return invoke(_callbacks.stop_trace); } + + int omnitrace_user_start_thread_trace(void) { - switch(category) - { - case OMNITRACE_USER_START_STOP: - { - if(begin_func) _start_trace = reinterpret_cast(begin_func); - if(end_func) _stop_trace = reinterpret_cast(end_func); - break; - } - case OMNITRACE_USER_START_STOP_THREAD: - { - if(begin_func) - _start_thread_trace = reinterpret_cast(begin_func); - if(end_func) - _stop_thread_trace = reinterpret_cast(end_func); - break; - } - case OMNITRACE_USER_REGION: - { - if(begin_func) _push_region = reinterpret_cast(begin_func); - if(end_func) _pop_region = reinterpret_cast(end_func); - break; - } - default: - { - return OMNITRACE_USER_ERROR_INVALID_CATEGORY; - } - } + return invoke(_callbacks.start_thread_trace); + } - return OMNITRACE_USER_SUCCESS; + int omnitrace_user_stop_thread_trace(void) + { + return invoke(_callbacks.stop_thread_trace); + } + + int omnitrace_user_push_region(const char* id) + { + return invoke(_callbacks.push_region, id); + } + + int omnitrace_user_pop_region(const char* id) + { + return invoke(_callbacks.pop_region, id); + } + + int omnitrace_user_push_annotated_region(const char* id, annotation_t* _annotations, + size_t _annotation_count) + { + return invoke(_callbacks.push_annotated_region, id, _annotations, + _annotation_count); + } + + int omnitrace_user_pop_annotated_region(const char* id, annotation_t* _annotations, + size_t _annotation_count) + { + return invoke(_callbacks.pop_annotated_region, id, _annotations, + _annotation_count); } - int omnitrace_user_get_callbacks(int category, void** begin_func, void** end_func) + int omnitrace_user_configure(omnitrace_user_configure_mode_t _mode, + omnitrace_user_callbacks_t _inp, + omnitrace_user_callbacks_t* _out) { - switch(category) + auto _former = _callbacks; + + switch(_mode) { - case OMNITRACE_USER_START_STOP: + case OMNITRACE_USER_REPLACE_CONFIG: { - if(begin_func) *begin_func = reinterpret_cast(_start_trace); - if(end_func) *end_func = reinterpret_cast(_stop_trace); + _callbacks = _inp; break; } - case OMNITRACE_USER_START_STOP_THREAD: + case OMNITRACE_USER_UNION_CONFIG: { - if(begin_func) *begin_func = reinterpret_cast(_start_thread_trace); - if(end_func) *end_func = reinterpret_cast(_stop_thread_trace); + auto _update = [](auto& _lhs, auto _rhs) { + if(_rhs) _lhs = _rhs; + }; + + user_callbacks_t _v = _callbacks; + + _update(_v.start_trace, _inp.start_trace); + _update(_v.stop_trace, _inp.stop_trace); + _update(_v.start_thread_trace, _inp.start_thread_trace); + _update(_v.stop_thread_trace, _inp.stop_thread_trace); + _update(_v.push_region, _inp.push_region); + _update(_v.pop_region, _inp.pop_region); + _update(_v.push_annotated_region, _inp.push_annotated_region); + _update(_v.pop_annotated_region, _inp.pop_annotated_region); + + _callbacks = _v; break; } - case OMNITRACE_USER_REGION: + case OMNITRACE_USER_INTERSECT_CONFIG: { - if(begin_func) *begin_func = reinterpret_cast(_push_region); - if(end_func) *end_func = reinterpret_cast(_pop_region); + auto _update = [](auto& _lhs, auto _rhs) { + if(_lhs != _rhs) _lhs = nullptr; + }; + + user_callbacks_t _v = _callbacks; + + _update(_v.start_trace, _inp.start_trace); + _update(_v.stop_trace, _inp.stop_trace); + _update(_v.start_thread_trace, _inp.start_thread_trace); + _update(_v.stop_thread_trace, _inp.stop_thread_trace); + _update(_v.push_region, _inp.push_region); + _update(_v.pop_region, _inp.pop_region); + _update(_v.push_annotated_region, _inp.push_annotated_region); + _update(_v.pop_annotated_region, _inp.pop_annotated_region); + + _callbacks = _v; break; } default: { + if(_out) *_out = _former; return OMNITRACE_USER_ERROR_INVALID_CATEGORY; } } + if(_out) *_out = _former; + return OMNITRACE_USER_SUCCESS; } diff --git a/source/lib/omnitrace/api.cpp b/source/lib/omnitrace/api.cpp index 793369d7..4a1062ee 100644 --- a/source/lib/omnitrace/api.cpp +++ b/source/lib/omnitrace/api.cpp @@ -66,6 +66,40 @@ omnitrace_pop_region(const char* _name) return 0; } +extern "C" int +omnitrace_push_category_region(omnitrace_category_t _category, const char* _name, + omnitrace_annotation_t* _annotations, + size_t _annotation_count) +{ + try + { + omnitrace_push_category_region_hidden(_category, _name, _annotations, + _annotation_count); + } catch(std::exception& _e) + { + OMNITRACE_VERBOSE_F(1, "Exception caught: %s\n", _e.what()); + return -1; + } + return 0; +} + +extern "C" int +omnitrace_pop_category_region(omnitrace_category_t _category, const char* _name, + omnitrace_annotation_t* _annotations, + size_t _annotation_count) +{ + try + { + omnitrace_pop_category_region_hidden(_category, _name, _annotations, + _annotation_count); + } catch(std::exception& _e) + { + OMNITRACE_VERBOSE_F(1, "Exception caught: %s\n", _e.what()); + return -1; + } + return 0; +} + extern "C" void omnitrace_init_library(void) { diff --git a/source/lib/omnitrace/api.hpp b/source/lib/omnitrace/api.hpp index 226b29b6..483ce730 100644 --- a/source/lib/omnitrace/api.hpp +++ b/source/lib/omnitrace/api.hpp @@ -23,6 +23,7 @@ #pragma once #include "library/defines.hpp" +#include "omnitrace/categories.h" // in omnitrace-user #include @@ -47,23 +48,34 @@ extern "C" void omnitrace_reset_preload(void) OMNITRACE_PUBLIC_API; /// sets an environment variable - void omnitrace_set_env(const char* env_name, - const char* env_val) OMNITRACE_PUBLIC_API; + void omnitrace_set_env(const char*, const char*) OMNITRACE_PUBLIC_API; /// sets whether MPI should be used - void omnitrace_set_mpi(bool use, bool attached) OMNITRACE_PUBLIC_API; + void omnitrace_set_mpi(bool, bool) OMNITRACE_PUBLIC_API; /// starts an instrumentation region - void omnitrace_push_trace(const char* name) OMNITRACE_PUBLIC_API; + void omnitrace_push_trace(const char*) OMNITRACE_PUBLIC_API; /// stops an instrumentation region - void omnitrace_pop_trace(const char* name) OMNITRACE_PUBLIC_API; + void omnitrace_pop_trace(const char*) OMNITRACE_PUBLIC_API; /// starts an instrumentation region (user-defined) - int omnitrace_push_region(const char* name) OMNITRACE_PUBLIC_API; + int omnitrace_push_region(const char*) OMNITRACE_PUBLIC_API; /// stops an instrumentation region (user-defined) - int omnitrace_pop_region(const char* name) OMNITRACE_PUBLIC_API; + int omnitrace_pop_region(const char*) OMNITRACE_PUBLIC_API; + + /// starts an instrumentation region in a user-defined category and (optionally) + /// adds annotations to the perfetto trace. + int omnitrace_push_category_region(omnitrace_category_t, const char*, + omnitrace_annotation_t*, + size_t) OMNITRACE_PUBLIC_API; + + /// stops an instrumentation region in a user-defined category and (optionally) + /// adds annotations to the perfetto trace. + int omnitrace_pop_category_region(omnitrace_category_t, const char*, + omnitrace_annotation_t*, + size_t) OMNITRACE_PUBLIC_API; /// stores source code information void omnitrace_register_source(const char* file, const char* func, size_t line, @@ -80,16 +92,20 @@ extern "C" void omnitrace_init_hidden(const char*, bool, const char*) OMNITRACE_HIDDEN_API; void omnitrace_finalize_hidden(void) OMNITRACE_HIDDEN_API; void omnitrace_reset_preload_hidden(void) OMNITRACE_HIDDEN_API; - void omnitrace_set_env_hidden(const char* env_name, - const char* env_val) OMNITRACE_HIDDEN_API; - void omnitrace_set_mpi_hidden(bool use, bool attached) OMNITRACE_HIDDEN_API; - void omnitrace_push_trace_hidden(const char* name) OMNITRACE_HIDDEN_API; - void omnitrace_pop_trace_hidden(const char* name) OMNITRACE_HIDDEN_API; - void omnitrace_push_region_hidden(const char* name) OMNITRACE_HIDDEN_API; - void omnitrace_pop_region_hidden(const char* name) OMNITRACE_HIDDEN_API; - void omnitrace_register_source_hidden(const char* file, const char* func, size_t line, - size_t address, - const char* source) OMNITRACE_HIDDEN_API; - void omnitrace_register_coverage_hidden(const char* file, const char* func, - size_t address) OMNITRACE_HIDDEN_API; + void omnitrace_set_env_hidden(const char*, const char*) OMNITRACE_HIDDEN_API; + void omnitrace_set_mpi_hidden(bool, bool) OMNITRACE_HIDDEN_API; + void omnitrace_push_trace_hidden(const char*) OMNITRACE_HIDDEN_API; + void omnitrace_pop_trace_hidden(const char*) OMNITRACE_HIDDEN_API; + void omnitrace_push_region_hidden(const char*) OMNITRACE_HIDDEN_API; + void omnitrace_pop_region_hidden(const char*) OMNITRACE_HIDDEN_API; + void omnitrace_push_category_region_hidden(omnitrace_category_t, const char*, + omnitrace_annotation_t*, + size_t) OMNITRACE_HIDDEN_API; + void omnitrace_pop_category_region_hidden(omnitrace_category_t, const char*, + omnitrace_annotation_t*, + size_t) OMNITRACE_HIDDEN_API; + void omnitrace_register_source_hidden(const char*, const char*, size_t, size_t, + const char*) OMNITRACE_HIDDEN_API; + void omnitrace_register_coverage_hidden(const char*, const char*, + size_t) OMNITRACE_HIDDEN_API; } diff --git a/source/lib/omnitrace/library.cpp b/source/lib/omnitrace/library.cpp index 885d072d..17cd6e13 100644 --- a/source/lib/omnitrace/library.cpp +++ b/source/lib/omnitrace/library.cpp @@ -50,6 +50,8 @@ #include "library/thread_info.hpp" #include "library/timemory.hpp" #include "library/tracing.hpp" +#include "library/utility.hpp" +#include "omnitrace/categories.h" // in omnitrace-user #include #include @@ -65,6 +67,7 @@ #include #include #include +#include using namespace omnitrace; @@ -187,6 +190,100 @@ omnitrace_pop_region_hidden(const char* name) /// //======================================================================================// +namespace omnitrace +{ +namespace +{ +template +void +invoke_category_region_start(omnitrace_category_t _category, const char* name, + omnitrace_annotation_t* _annotations, + size_t _annotation_count, std::index_sequence) +{ + static_assert(Idx > OMNITRACE_CATEGORY_NONE && Idx < OMNITRACE_CATEGORY_LAST, + "Error! index sequence should only contain values which are greater " + "than OMNITRACE_CATEGORY_NONE and less than OMNITRACE_CATEGORY_LAST"); + + if(_category == Idx) + { + using category_type = category_type_id_t; + component::category_region::start( + name, [&](::perfetto::EventContext ctx) { + if(_annotations) + { + for(size_t i = 0; i < _annotation_count; ++i) + tracing::add_perfetto_annotation(ctx, _annotations[i]); + } + }); + } + else + { + constexpr size_t remaining = sizeof...(Tail); + if constexpr(remaining > 0) + invoke_category_region_start(_category, name, _annotations, _annotation_count, + std::index_sequence{}); + } +} +} // namespace + +template +void +invoke_category_region_stop(omnitrace_category_t _category, const char* name, + omnitrace_annotation_t* _annotations, + size_t _annotation_count, std::index_sequence) +{ + static_assert(Idx > OMNITRACE_CATEGORY_NONE && Idx < OMNITRACE_CATEGORY_LAST, + "Error! index sequence should only contain values which are greater " + "than OMNITRACE_CATEGORY_NONE and less than OMNITRACE_CATEGORY_LAST"); + + if(_category == Idx) + { + using category_type = category_type_id_t; + component::category_region::stop( + name, [&](::perfetto::EventContext ctx) { + if(_annotations) + { + for(size_t i = 0; i < _annotation_count; ++i) + tracing::add_perfetto_annotation(ctx, _annotations[i]); + } + }); + } + else + { + constexpr size_t remaining = sizeof...(Tail); + if constexpr(remaining > 0) + invoke_category_region_stop(_category, name, _annotations, _annotation_count, + std::index_sequence{}); + } +} +} // namespace omnitrace + +extern "C" void +omnitrace_push_category_region_hidden(omnitrace_category_t _category, const char* name, + omnitrace_annotation_t* _annotations, + size_t _annotation_count) +{ + invoke_category_region_start( + _category, name, _annotations, _annotation_count, + utility::make_index_sequence_range<1, OMNITRACE_CATEGORY_LAST>{}); +} + +extern "C" void +omnitrace_pop_category_region_hidden(omnitrace_category_t _category, const char* name, + omnitrace_annotation_t* _annotations, + size_t _annotation_count) +{ + invoke_category_region_stop( + _category, name, _annotations, _annotation_count, + utility::make_index_sequence_range<1, OMNITRACE_CATEGORY_LAST>{}); +} + +//======================================================================================// +/// +/// +/// +//======================================================================================// + namespace { struct set_env_s // NOLINT diff --git a/source/lib/omnitrace/library/CMakeLists.txt b/source/lib/omnitrace/library/CMakeLists.txt index b99c95f6..518af62a 100644 --- a/source/lib/omnitrace/library/CMakeLists.txt +++ b/source/lib/omnitrace/library/CMakeLists.txt @@ -82,4 +82,6 @@ if(OMNITRACE_USE_ROCM_SMI) endif() add_subdirectory(components) +add_subdirectory(coverage) add_subdirectory(rocm) +add_subdirectory(tracing) diff --git a/source/lib/omnitrace/library/categories.hpp b/source/lib/omnitrace/library/categories.hpp index e6ea8034..65bf5d59 100644 --- a/source/lib/omnitrace/library/categories.hpp +++ b/source/lib/omnitrace/library/categories.hpp @@ -24,6 +24,7 @@ #include "common/join.hpp" #include "library/defines.hpp" +#include "omnitrace/categories.h" // in omnitrace-user #if defined(TIMEMORY_PERFETTO_CATEGORIES) # error "TIMEMORY_PERFETTO_CATEGORIES is already defined. Please include \"" __FILE__ "\" before including any timemory files" @@ -48,57 +49,87 @@ } \ } -#define OMNITRACE_DECLARE_CATEGORY(NS, VALUE, NAME, DESC) \ +namespace omnitrace +{ +template +struct category_type_id; + +template +struct category_enum_id; + +template +using category_type_id_t = typename category_type_id::type; +} // namespace omnitrace + +#define OMNITRACE_DEFINE_CATEGORY_TRAIT(TYPE, ENUM) \ + namespace omnitrace \ + { \ + template <> \ + struct category_type_id \ + { \ + using type = TYPE; \ + }; \ + template <> \ + struct category_enum_id \ + { \ + static constexpr auto value = ENUM; \ + }; \ + } + +#define OMNITRACE_DECLARE_CATEGORY(NS, VALUE, ENUM, NAME, DESC) \ TIMEMORY_DECLARE_NS_API(NS, VALUE) \ - OMNITRACE_DEFINE_NAME_TRAIT(NAME, DESC, NS::VALUE) -#define OMNITRACE_DEFINE_CATEGORY(NS, VALUE, NAME, DESC) \ + OMNITRACE_DEFINE_NAME_TRAIT(NAME, DESC, NS::VALUE) \ + OMNITRACE_DEFINE_CATEGORY_TRAIT(::tim::NS::VALUE, ENUM) +#define OMNITRACE_DEFINE_CATEGORY(NS, VALUE, ENUM, NAME, DESC) \ TIMEMORY_DEFINE_NS_API(NS, VALUE) \ - OMNITRACE_DEFINE_NAME_TRAIT(NAME, DESC, NS::VALUE) + OMNITRACE_DEFINE_NAME_TRAIT(NAME, DESC, NS::VALUE) \ + OMNITRACE_DEFINE_CATEGORY_TRAIT(::tim::NS::VALUE, ENUM) // clang-format off // these are defined by omnitrace -OMNITRACE_DEFINE_CATEGORY(project, omnitrace, "omnitrace", "Omnitrace project") -OMNITRACE_DEFINE_CATEGORY(category, host, "host", "Host-side function tracing") -OMNITRACE_DEFINE_CATEGORY(category, user, "user", "User-defined regions") -OMNITRACE_DEFINE_CATEGORY(category, device_hip, "device_hip", "Device-side functions submitted via HIP API") -OMNITRACE_DEFINE_CATEGORY(category, device_hsa, "device_hsa", "Device-side functions submitted via HSA API") -OMNITRACE_DEFINE_CATEGORY(category, rocm_hip, "rocm_hip", "Host-side HIP functions") -OMNITRACE_DEFINE_CATEGORY(category, rocm_hsa, "rocm_hsa", "Host-side HSA functions") -OMNITRACE_DEFINE_CATEGORY(category, rocm_roctx, "rocm_roctx", "ROCTx labels") -OMNITRACE_DEFINE_CATEGORY(category, rocm_smi, "rocm_smi", "rocm-smi data") -OMNITRACE_DEFINE_CATEGORY(category, rocm_smi_busy, "device_busy", "Busy percentage of a GPU device") -OMNITRACE_DEFINE_CATEGORY(category, rocm_smi_temp, "device_temp", "Temperature of a GPU device") -OMNITRACE_DEFINE_CATEGORY(category, rocm_smi_power, "device_power", "Power consumption of a GPU device") -OMNITRACE_DEFINE_CATEGORY(category, rocm_smi_memory_usage, "device_memory_usage", "Memory usage of a GPU device") -OMNITRACE_DEFINE_CATEGORY(category, rocm_rccl, "rccl", "ROCm Communication Collectives Library (RCCL) regions") -OMNITRACE_DEFINE_CATEGORY(category, roctracer, "roctracer", "Kernel tracing provided by roctracer") -OMNITRACE_DEFINE_CATEGORY(category, rocprofiler, "rocprofiler", "HW counter data provided by rocprofiler") -OMNITRACE_DEFINE_CATEGORY(category, pthread, "pthread", "POSIX threading functions") -OMNITRACE_DEFINE_CATEGORY(category, kokkos, "kokkos", "KokkosTools regions") -OMNITRACE_DEFINE_CATEGORY(category, mpi, "mpi", "MPI regions") -OMNITRACE_DEFINE_CATEGORY(category, ompt, "ompt", "OpenMP tools regions") -OMNITRACE_DEFINE_CATEGORY(category, process_sampling, "process_sampling", "Process-level data") -OMNITRACE_DEFINE_CATEGORY(category, comm_data, "comm_data", "MPI/RCCL counters for tracking amount of data sent or received") -OMNITRACE_DEFINE_CATEGORY(category, critical_trace, "critical-trace", "Critical trace data") -OMNITRACE_DEFINE_CATEGORY(category, host_critical_trace, "host-critical-trace", "Host-side critical trace data") -OMNITRACE_DEFINE_CATEGORY(category, device_critical_trace, "device-critical-trace", "Device-side critical trace data") -OMNITRACE_DEFINE_CATEGORY(category, causal, "causal", "Causal profiling data") -OMNITRACE_DEFINE_CATEGORY(category, cpu_freq, "cpu_frequency", "CPU frequency (collected in background thread)") -OMNITRACE_DEFINE_CATEGORY(category, process_page, "process_page_fault", "Memory page faults in process (collected in background thread)") -OMNITRACE_DEFINE_CATEGORY(category, process_virt, "process_virtual_memory", "Virtual memory usage in process in MB (collected in background thread)") -OMNITRACE_DEFINE_CATEGORY(category, process_peak, "process_memory_hwm", "Memory High-Water Mark i.e. peak memory usage (collected in background thread)") -OMNITRACE_DEFINE_CATEGORY(category, process_context_switch, "process_context_switch", "Context switches in process (collected in background thread)") -OMNITRACE_DEFINE_CATEGORY(category, process_page_fault, "process_page_fault", "Memory page faults in process (collected in background thread)") -OMNITRACE_DEFINE_CATEGORY(category, process_user_mode_time, "process_user_cpu_time", "CPU time of functions executing in user-space in process in seconds (collected in background thread)") -OMNITRACE_DEFINE_CATEGORY(category, process_kernel_mode_time, "process_kernel_cpu_time", "CPU time of functions executing in kernel-space in process in seconds (collected in background thread)") -OMNITRACE_DEFINE_CATEGORY(category, thread_page_fault, "thread_page_fault", "Memory page faults on thread (derived from sampling)") -OMNITRACE_DEFINE_CATEGORY(category, thread_peak_memory, "thread_peak_memory", "Peak memory usage on thread in MB (derived from sampling)") -OMNITRACE_DEFINE_CATEGORY(category, thread_context_switch, "thread_context_switch", "Context switches on thread (derived from sampling)") -OMNITRACE_DEFINE_CATEGORY(category, thread_hardware_counter, "thread_hardware_counter", "Hardware counter value on thread (derived from sampling)") -OMNITRACE_DEFINE_CATEGORY(category, kernel_hardware_counter, "kernel_hardware_counter", "Hardware counter value for kernel (deterministic)") -OMNITRACE_DEFINE_CATEGORY(category, numa, "numa", "Non-unified memory architecture") - -OMNITRACE_DECLARE_CATEGORY(category, sampling, "sampling", "Host-side call-stack sampling") +OMNITRACE_DEFINE_CATEGORY(project, omnitrace, OMNITRACE_CATEGORY_NONE, "omnitrace", "Omnitrace project") +OMNITRACE_DEFINE_CATEGORY(category, host, OMNITRACE_CATEGORY_HOST, "host", "Host-side function tracing") +OMNITRACE_DEFINE_CATEGORY(category, user, OMNITRACE_CATEGORY_USER, "user", "User-defined regions") +OMNITRACE_DEFINE_CATEGORY(category, python, OMNITRACE_CATEGORY_PYTHON, "python", "Python regions") +OMNITRACE_DEFINE_CATEGORY(category, device_hip, OMNITRACE_CATEGORY_DEVICE_HIP, "device_hip", "Device-side functions submitted via HIP API") +OMNITRACE_DEFINE_CATEGORY(category, device_hsa, OMNITRACE_CATEGORY_DEVICE_HSA, "device_hsa", "Device-side functions submitted via HSA API") +OMNITRACE_DEFINE_CATEGORY(category, rocm_hip, OMNITRACE_CATEGORY_ROCM_HIP, "rocm_hip", "Host-side HIP functions") +OMNITRACE_DEFINE_CATEGORY(category, rocm_hsa, OMNITRACE_CATEGORY_ROCM_HSA, "rocm_hsa", "Host-side HSA functions") +OMNITRACE_DEFINE_CATEGORY(category, rocm_roctx, OMNITRACE_CATEGORY_ROCM_ROCTX, "rocm_roctx", "ROCTx labels") +OMNITRACE_DEFINE_CATEGORY(category, rocm_smi, OMNITRACE_CATEGORY_ROCM_SMI, "rocm_smi", "rocm-smi data") +OMNITRACE_DEFINE_CATEGORY(category, rocm_smi_busy, OMNITRACE_CATEGORY_ROCM_SMI_BUSY, "device_busy", "Busy percentage of a GPU device") +OMNITRACE_DEFINE_CATEGORY(category, rocm_smi_temp, OMNITRACE_CATEGORY_ROCM_SMI_TEMP, "device_temp", "Temperature of a GPU device") +OMNITRACE_DEFINE_CATEGORY(category, rocm_smi_power, OMNITRACE_CATEGORY_ROCM_SMI_POWER, "device_power", "Power consumption of a GPU device") +OMNITRACE_DEFINE_CATEGORY(category, rocm_smi_memory_usage, OMNITRACE_CATEGORY_ROCM_SMI_MEMORY_USAGE, "device_memory_usage", "Memory usage of a GPU device") +OMNITRACE_DEFINE_CATEGORY(category, rocm_rccl, OMNITRACE_CATEGORY_ROCM_RCCL, "rccl", "ROCm Communication Collectives Library (RCCL) regions") +OMNITRACE_DEFINE_CATEGORY(category, roctracer, OMNITRACE_CATEGORY_ROCTRACER, "roctracer", "Kernel tracing provided by roctracer") +OMNITRACE_DEFINE_CATEGORY(category, rocprofiler, OMNITRACE_CATEGORY_ROCPROFILER, "rocprofiler", "HW counter data provided by rocprofiler") +OMNITRACE_DEFINE_CATEGORY(category, pthread, OMNITRACE_CATEGORY_PTHREAD, "pthread", "POSIX threading functions") +OMNITRACE_DEFINE_CATEGORY(category, kokkos, OMNITRACE_CATEGORY_KOKKOS, "kokkos", "KokkosTools regions") +OMNITRACE_DEFINE_CATEGORY(category, mpi, OMNITRACE_CATEGORY_MPI, "mpi", "MPI regions") +OMNITRACE_DEFINE_CATEGORY(category, ompt, OMNITRACE_CATEGORY_OMPT, "ompt", "OpenMP tools regions") +OMNITRACE_DEFINE_CATEGORY(category, process_sampling, OMNITRACE_CATEGORY_PROCESS_SAMPLING, "process_sampling", "Process-level data") +OMNITRACE_DEFINE_CATEGORY(category, comm_data, OMNITRACE_CATEGORY_COMM_DATA, "comm_data", "MPI/RCCL counters for tracking amount of data sent or received") +OMNITRACE_DEFINE_CATEGORY(category, critical_trace, OMNITRACE_CATEGORY_CRITICAL_TRACE, "critical-trace", "Critical trace data") +OMNITRACE_DEFINE_CATEGORY(category, host_critical_trace, OMNITRACE_CATEGORY_HOST_CRITICAL_TRACE, "host-critical-trace", "Host-side critical trace data") +OMNITRACE_DEFINE_CATEGORY(category, device_critical_trace, OMNITRACE_CATEGORY_DEVICE_CRITICAL_TRACE, "device-critical-trace", "Device-side critical trace data") +OMNITRACE_DEFINE_CATEGORY(category, causal, OMNITRACE_CATEGORY_CAUSAL, "causal", "Causal profiling data") +OMNITRACE_DEFINE_CATEGORY(category, cpu_freq, OMNITRACE_CATEGORY_CPU_FREQ, "cpu_frequency", "CPU frequency (collected in background thread)") +OMNITRACE_DEFINE_CATEGORY(category, process_page, OMNITRACE_CATEGORY_PROCESS_PAGE, "process_page_fault", "Memory page faults in process (collected in background thread)") +OMNITRACE_DEFINE_CATEGORY(category, process_virt, OMNITRACE_CATEGORY_PROCESS_VIRT, "process_virtual_memory", "Virtual memory usage in process in MB (collected in background thread)") +OMNITRACE_DEFINE_CATEGORY(category, process_peak, OMNITRACE_CATEGORY_PROCESS_PEAK, "process_memory_hwm", "Memory High-Water Mark i.e. peak memory usage (collected in background thread)") +OMNITRACE_DEFINE_CATEGORY(category, process_context_switch, OMNITRACE_CATEGORY_PROCESS_CONTEXT_SWITCH, "process_context_switch", "Context switches in process (collected in background thread)") +OMNITRACE_DEFINE_CATEGORY(category, process_page_fault, OMNITRACE_CATEGORY_PROCESS_PAGE_FAULT, "process_page_fault", "Memory page faults in process (collected in background thread)") +OMNITRACE_DEFINE_CATEGORY(category, process_user_mode_time, OMNITRACE_CATEGORY_PROCESS_USER_MODE_TIME, "process_user_cpu_time", "CPU time of functions executing in user-space in process in seconds (collected in background thread)") +OMNITRACE_DEFINE_CATEGORY(category, process_kernel_mode_time, OMNITRACE_CATEGORY_PROCESS_KERNEL_MODE_TIME, "process_kernel_cpu_time", "CPU time of functions executing in kernel-space in process in seconds (collected in background thread)") +OMNITRACE_DEFINE_CATEGORY(category, thread_page_fault, OMNITRACE_CATEGORY_THREAD_PAGE_FAULT, "thread_page_fault", "Memory page faults on thread (derived from sampling)") +OMNITRACE_DEFINE_CATEGORY(category, thread_peak_memory, OMNITRACE_CATEGORY_THREAD_PEAK_MEMORY, "thread_peak_memory", "Peak memory usage on thread in MB (derived from sampling)") +OMNITRACE_DEFINE_CATEGORY(category, thread_context_switch, OMNITRACE_CATEGORY_THREAD_CONTEXT_SWITCH, "thread_context_switch", "Context switches on thread (derived from sampling)") +OMNITRACE_DEFINE_CATEGORY(category, thread_hardware_counter, OMNITRACE_CATEGORY_THREAD_HARDWARE_COUNTER, "thread_hardware_counter", "Hardware counter value on thread (derived from sampling)") +OMNITRACE_DEFINE_CATEGORY(category, kernel_hardware_counter, OMNITRACE_CATEGORY_KERNEL_HARDWARE_COUNTER, "kernel_hardware_counter", "Hardware counter value for kernel (deterministic)") +OMNITRACE_DEFINE_CATEGORY(category, numa, OMNITRACE_CATEGORY_NUMA, "numa", "Non-unified memory architecture") + +OMNITRACE_DECLARE_CATEGORY(category, sampling, OMNITRACE_CATEGORY_SAMPLING, "sampling", "Host-side call-stack sampling") // clang-format on namespace tim @@ -117,6 +148,7 @@ using name = perfetto_category; #define OMNITRACE_PERFETTO_CATEGORIES \ OMNITRACE_PERFETTO_CATEGORY(category::host), \ OMNITRACE_PERFETTO_CATEGORY(category::user), \ + OMNITRACE_PERFETTO_CATEGORY(category::python), \ OMNITRACE_PERFETTO_CATEGORY(category::sampling), \ OMNITRACE_PERFETTO_CATEGORY(category::device_hip), \ OMNITRACE_PERFETTO_CATEGORY(category::device_hsa), \ diff --git a/source/lib/omnitrace/library/components/category_region.hpp b/source/lib/omnitrace/library/components/category_region.hpp index 4b765e37..f89f3e28 100644 --- a/source/lib/omnitrace/library/components/category_region.hpp +++ b/source/lib/omnitrace/library/components/category_region.hpp @@ -28,6 +28,7 @@ #include "library/runtime.hpp" #include "library/timemory.hpp" #include "library/tracing.hpp" +#include "library/tracing/annotation.hpp" #include #include diff --git a/source/lib/omnitrace/library/config.cpp b/source/lib/omnitrace/library/config.cpp index 9477e1a7..38f20c24 100644 --- a/source/lib/omnitrace/library/config.cpp +++ b/source/lib/omnitrace/library/config.cpp @@ -2051,25 +2051,4 @@ get_tmp_file(std::string _basename, std::string _ext) return _existing_files.at(_fname); } } // namespace config - -State& -get_state() -{ - static State _v{ State::PreInit }; - return _v; -} - -State -set_state(State _n) -{ - auto _o = get_state(); - OMNITRACE_CONDITIONAL_PRINT_F(get_debug_init(), "Setting state :: %s -> %s\n", - std::to_string(_o).c_str(), std::to_string(_n).c_str()); - // state should always be increased, not decreased - OMNITRACE_CI_BASIC_THROW(_n < _o, - "State is being assigned to a lesser value :: %s -> %s", - std::to_string(_o).c_str(), std::to_string(_n).c_str()); - get_state() = _n; - return _o; -} } // namespace omnitrace diff --git a/source/lib/omnitrace/library/config.hpp b/source/lib/omnitrace/library/config.hpp index 060bfd32..9ea9f730 100644 --- a/source/lib/omnitrace/library/config.hpp +++ b/source/lib/omnitrace/library/config.hpp @@ -355,13 +355,4 @@ struct tmp_file std::shared_ptr get_tmp_file(std::string _basename, std::string _ext = "dat"); } // namespace config - -// -// Runtime configuration data -// -State& -get_state() TIMEMORY_HOT; - -/// returns old state -State set_state(State); } // namespace omnitrace diff --git a/source/lib/omnitrace/library/coverage.cpp b/source/lib/omnitrace/library/coverage.cpp index ce163145..e3257446 100644 --- a/source/lib/omnitrace/library/coverage.cpp +++ b/source/lib/omnitrace/library/coverage.cpp @@ -23,8 +23,8 @@ #include "library/coverage.hpp" #include "api.hpp" #include "library/config.hpp" +#include "library/coverage/impl.hpp" #include "library/debug.hpp" -#include "library/impl/coverage.hpp" #include "library/thread_data.hpp" #include diff --git a/source/lib/omnitrace/library/coverage/CMakeLists.txt b/source/lib/omnitrace/library/coverage/CMakeLists.txt new file mode 100644 index 00000000..bd8a386c --- /dev/null +++ b/source/lib/omnitrace/library/coverage/CMakeLists.txt @@ -0,0 +1,5 @@ +# +set(coverage_sources) +set(coverage_headers ${CMAKE_CURRENT_LIST_DIR}/impl.hpp) + +target_sources(omnitrace-object-library PRIVATE ${coverage_sources} ${coverage_headers}) diff --git a/source/lib/omnitrace/library/impl/coverage.hpp b/source/lib/omnitrace/library/coverage/impl.hpp similarity index 100% rename from source/lib/omnitrace/library/impl/coverage.hpp rename to source/lib/omnitrace/library/coverage/impl.hpp diff --git a/source/lib/omnitrace/library/runtime.cpp b/source/lib/omnitrace/library/runtime.cpp index 62c5239d..d420eaa3 100644 --- a/source/lib/omnitrace/library/runtime.cpp +++ b/source/lib/omnitrace/library/runtime.cpp @@ -244,55 +244,6 @@ get_preinit_bundle() return _v; } -namespace -{ -auto& -get_thread_state_history(int64_t _idx = utility::get_thread_index()) -{ - static auto _v = utility::get_filled_array( - []() { return utility::get_reserved_vector(32); }); - - return _v.at(_idx); -} -} // namespace - -ThreadState& -get_thread_state() -{ - static thread_local ThreadState _v{ ThreadState::Enabled }; - return _v; -} - -ThreadState -set_thread_state(ThreadState _n) -{ - auto _o = get_thread_state(); - get_thread_state() = _n; - return _o; -} - -ThreadState -push_thread_state(ThreadState _v) -{ - if(get_thread_state() >= ThreadState::Completed) return get_thread_state(); - - return get_thread_state_history().emplace_back(set_thread_state(_v)); -} - -ThreadState -pop_thread_state() -{ - if(get_thread_state() >= ThreadState::Completed) return get_thread_state(); - - auto& _hist = get_thread_state_history(); - if(!_hist.empty()) - { - set_thread_state(_hist.back()); - _hist.pop_back(); - } - return get_thread_state(); -} - bool sampling_enabled_on_child_threads() { diff --git a/source/lib/omnitrace/library/runtime.hpp b/source/lib/omnitrace/library/runtime.hpp index ca9c8a3c..295f708b 100644 --- a/source/lib/omnitrace/library/runtime.hpp +++ b/source/lib/omnitrace/library/runtime.hpp @@ -107,23 +107,6 @@ get_cpu_cid_entry(uint64_t _cid, int64_t _tid = threading::get_id()) TIMEMORY_HO tim::mutex_t& get_cpu_cid_stack_lock(int64_t _tid = threading::get_id()) TIMEMORY_HOT; -ThreadState& -get_thread_state() TIMEMORY_HOT; - -/// returns old state -ThreadState set_thread_state(ThreadState) TIMEMORY_HOT; - -ThreadState push_thread_state(ThreadState) TIMEMORY_HOT; - -ThreadState -pop_thread_state() TIMEMORY_HOT; - -struct scoped_thread_state -{ - scoped_thread_state(ThreadState _v) { push_thread_state(_v); } - ~scoped_thread_state() { pop_thread_state(); } -}; - // query current value bool sampling_enabled_on_child_threads(); @@ -147,12 +130,6 @@ struct scoped_child_sampling }; } // namespace omnitrace -#define OMNITRACE_SCOPED_THREAD_STATE(STATE) \ - ::omnitrace::scoped_thread_state OMNITRACE_VARIABLE(_scoped_thread_state_, __LINE__) \ - { \ - ::omnitrace::STATE \ - } - #define OMNITRACE_SCOPED_SAMPLING_ON_CHILD_THREADS(VALUE) \ ::omnitrace::scoped_child_sampling OMNITRACE_VARIABLE(_scoped_child_sampling_, \ __LINE__) \ diff --git a/source/lib/omnitrace/library/sampling.cpp b/source/lib/omnitrace/library/sampling.cpp index 6d36427e..da58f7e4 100644 --- a/source/lib/omnitrace/library/sampling.cpp +++ b/source/lib/omnitrace/library/sampling.cpp @@ -33,6 +33,7 @@ #include "library/thread_data.hpp" #include "library/thread_info.hpp" #include "library/tracing.hpp" +#include "library/tracing/annotation.hpp" #include "library/utility.hpp" #include diff --git a/source/lib/omnitrace/library/state.cpp b/source/lib/omnitrace/library/state.cpp index c5c7596b..8ef5c933 100644 --- a/source/lib/omnitrace/library/state.cpp +++ b/source/lib/omnitrace/library/state.cpp @@ -21,9 +21,96 @@ // SOFTWARE. #include "library/state.hpp" +#include "library/config.hpp" +#include "library/debug.hpp" +#include "library/utility.hpp" #include +namespace omnitrace +{ +namespace +{ +auto& +get_state_value() +{ + static State _v{ State::PreInit }; + return _v; +} + +ThreadState& +get_thread_state_value() +{ + static thread_local ThreadState _v{ ThreadState::Enabled }; + return _v; +} + +auto& +get_thread_state_history(int64_t _idx = utility::get_thread_index()) +{ + static auto _v = utility::get_filled_array( + []() { return utility::get_reserved_vector(32); }); + + return _v.at(_idx); +} +} // namespace + +State +get_state() +{ + return get_state_value(); +} + +ThreadState +get_thread_state() +{ + return get_thread_state_value(); +} + +State +set_state(State _n) +{ + OMNITRACE_CONDITIONAL_PRINT_F(get_debug_init(), "Setting state :: %s -> %s\n", + std::to_string(get_state()).c_str(), + std::to_string(_n).c_str()); + // state should always be increased, not decreased + OMNITRACE_CI_BASIC_THROW( + _n < get_state(), "State is being assigned to a lesser value :: %s -> %s", + std::to_string(get_state()).c_str(), std::to_string(_n).c_str()); + std::swap(get_state_value(), _n); + return _n; +} + +ThreadState +set_thread_state(ThreadState _n) +{ + std::swap(get_thread_state_value(), _n); + return _n; +} + +ThreadState +push_thread_state(ThreadState _v) +{ + if(get_thread_state() >= ThreadState::Completed) return get_thread_state(); + + return get_thread_state_history().emplace_back(set_thread_state(_v)); +} + +ThreadState +pop_thread_state() +{ + if(get_thread_state() >= ThreadState::Completed) return get_thread_state(); + + auto& _hist = get_thread_state_history(); + if(!_hist.empty()) + { + set_thread_state(_hist.back()); + _hist.pop_back(); + } + return get_thread_state(); +} +} // namespace omnitrace + namespace std { std::string diff --git a/source/lib/omnitrace/library/state.hpp b/source/lib/omnitrace/library/state.hpp index 91f17856..7eb86c34 100644 --- a/source/lib/omnitrace/library/state.hpp +++ b/source/lib/omnitrace/library/state.hpp @@ -24,6 +24,8 @@ #include "library/defines.hpp" +#include + namespace omnitrace { // used for specifying the state of omnitrace @@ -51,9 +53,41 @@ enum class Mode : unsigned short Sampling, Coverage }; + +// +// Runtime configuration data +// +State +get_state() OMNITRACE_HOT; + +ThreadState +get_thread_state() OMNITRACE_HOT; + +/// returns old state +State set_state(State) OMNITRACE_COLD; // does not change often + +/// returns old state +ThreadState set_thread_state(ThreadState) OMNITRACE_HOT; // changes often + +/// return current state (state change may be ignored) +ThreadState push_thread_state(ThreadState) OMNITRACE_HOT; + +/// return current state (state change may be ignored) +ThreadState +pop_thread_state() OMNITRACE_HOT; + +struct scoped_thread_state +{ + OMNITRACE_INLINE scoped_thread_state(ThreadState _v) { push_thread_state(_v); } + OMNITRACE_INLINE ~scoped_thread_state() { pop_thread_state(); } +}; } // namespace omnitrace -#include +#define OMNITRACE_SCOPED_THREAD_STATE(STATE) \ + ::omnitrace::scoped_thread_state OMNITRACE_VARIABLE(_scoped_thread_state_, __LINE__) \ + { \ + ::omnitrace::STATE \ + } namespace std { diff --git a/source/lib/omnitrace/library/tracing.hpp b/source/lib/omnitrace/library/tracing.hpp index 4784451c..add14d71 100644 --- a/source/lib/omnitrace/library/tracing.hpp +++ b/source/lib/omnitrace/library/tracing.hpp @@ -200,76 +200,6 @@ pop_timemory(CategoryT, const char* name, Args&&... args) } } -template -auto -add_perfetto_annotation(perfetto::EventContext& ctx, Np&& _name, Tp&& _val, - int64_t _idx = -1) -{ - using named_type = std::remove_reference_t>>; - using value_type = std::remove_reference_t>>; - - static_assert(concepts::is_string_type::value, - "Error! name is not a string type"); - - auto _get_dbg = [&]() { - auto* _dbg = ctx.event()->add_debug_annotations(); - if(_idx >= 0) - { - auto _arg_name = JOIN("", "arg", _idx, "-", std::forward(_name)); - _dbg->set_name(_arg_name); - } - else - { - _dbg->set_name(std::string_view{ std::forward(_name) }.data()); - } - return _dbg; - }; - - if constexpr(std::is_same::value) - { - _get_dbg()->set_string_value(_val.data()); - } - else if constexpr(concepts::is_string_type::value) - { - _get_dbg()->set_string_value(std::forward(_val)); - } - else if constexpr(std::is_same::value) - { - _get_dbg()->set_bool_value(std::forward(_val)); - } - else if constexpr(std::is_enum::value) - { - _get_dbg()->set_int_value(static_cast(std::forward(_val))); - } - else if constexpr(std::is_floating_point::value) - { - _get_dbg()->set_double_value(std::forward(_val)); - } - else if constexpr(std::is_integral::value) - { - if constexpr(std::is_unsigned::value) - { - _get_dbg()->set_uint_value(std::forward(_val)); - } - else - { - _get_dbg()->set_int_value(std::forward(_val)); - } - } - else if constexpr(std::is_pointer::value) - { - _get_dbg()->set_pointer_value(reinterpret_cast(std::forward(_val))); - } - else if constexpr(concepts::can_stringify::value) - { - _get_dbg()->set_string_value(JOIN("", std::forward(_val))); - } - else - { - static_assert(std::is_empty::value, "Error! unsupported data type"); - } -} - template inline void push_perfetto(CategoryT, const char* name, Args&&... args) diff --git a/source/lib/omnitrace/library/tracing/CMakeLists.txt b/source/lib/omnitrace/library/tracing/CMakeLists.txt new file mode 100644 index 00000000..b9c38d05 --- /dev/null +++ b/source/lib/omnitrace/library/tracing/CMakeLists.txt @@ -0,0 +1,5 @@ +# +set(tracing_sources ${CMAKE_CURRENT_LIST_DIR}/annotation.cpp) +set(tracing_headers ${CMAKE_CURRENT_LIST_DIR}/annotation.hpp) + +target_sources(omnitrace-object-library PRIVATE ${tracing_sources} ${tracing_headers}) diff --git a/source/lib/omnitrace/library/tracing/annotation.cpp b/source/lib/omnitrace/library/tracing/annotation.cpp new file mode 100644 index 00000000..4cbb8baf --- /dev/null +++ b/source/lib/omnitrace/library/tracing/annotation.cpp @@ -0,0 +1,37 @@ +// MIT License +// +// Copyright (c) 2022 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 "library/tracing/annotation.hpp" + +namespace omnitrace +{ +namespace tracing +{ +void +add_perfetto_annotation(perfetto_event_context_t& ctx, + const omnitrace_annotation_t& _annotation) +{ + add_perfetto_annotation( + ctx, _annotation, utility::make_index_sequence_range<1, OMNITRACE_VALUE_LAST>{}); +} +} // namespace tracing +} // namespace omnitrace diff --git a/source/lib/omnitrace/library/tracing/annotation.hpp b/source/lib/omnitrace/library/tracing/annotation.hpp new file mode 100644 index 00000000..f0211187 --- /dev/null +++ b/source/lib/omnitrace/library/tracing/annotation.hpp @@ -0,0 +1,207 @@ +// MIT License +// +// Copyright (c) 2022 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. + +#pragma once + +#include "library/common.hpp" +#include "library/concepts.hpp" +#include "library/debug.hpp" +#include "library/defines.hpp" +#include "library/perfetto.hpp" +#include "library/state.hpp" +#include "library/utility.hpp" +#include "omnitrace/categories.h" // in omnitrace-user + +#include + +#include + +namespace omnitrace +{ +namespace tracing +{ +using perfetto_event_context_t = ::perfetto::EventContext; + +template +struct annotation_value_type; + +template +using annotation_value_type_t = typename annotation_value_type::type; + +#define OMNITRACE_DEFINE_ANNOTATION_TYPE(ENUM, TYPE) \ + template <> \ + struct annotation_value_type \ + { \ + using type = TYPE; \ + }; + +OMNITRACE_DEFINE_ANNOTATION_TYPE(OMNITRACE_VALUE_CSTR, const char*) +OMNITRACE_DEFINE_ANNOTATION_TYPE(OMNITRACE_VALUE_SIZE_T, size_t) +OMNITRACE_DEFINE_ANNOTATION_TYPE(OMNITRACE_VALUE_INT16, int16_t) +OMNITRACE_DEFINE_ANNOTATION_TYPE(OMNITRACE_VALUE_INT32, int32_t) +OMNITRACE_DEFINE_ANNOTATION_TYPE(OMNITRACE_VALUE_INT64, int64_t) +OMNITRACE_DEFINE_ANNOTATION_TYPE(OMNITRACE_VALUE_UINT16, uint16_t) +OMNITRACE_DEFINE_ANNOTATION_TYPE(OMNITRACE_VALUE_UINT32, uint32_t) +OMNITRACE_DEFINE_ANNOTATION_TYPE(OMNITRACE_VALUE_UINT64, uint64_t) +OMNITRACE_DEFINE_ANNOTATION_TYPE(OMNITRACE_VALUE_FLOAT32, float) +OMNITRACE_DEFINE_ANNOTATION_TYPE(OMNITRACE_VALUE_FLOAT64, double) +OMNITRACE_DEFINE_ANNOTATION_TYPE(OMNITRACE_VALUE_VOID_P, void*) + +#undef OMNITRACE_DEFINE_ANNOTATION_TYPE + +template +auto +add_perfetto_annotation( + perfetto_event_context_t& ctx, Np&& _name, Tp&& _val, int64_t _idx = -1, + std::enable_if_t< + !std::is_same>, + omnitrace_annotation_t>::value, + int> = 0) +{ + using named_type = std::remove_reference_t>>; + using value_type = std::remove_reference_t>>; + + static_assert(concepts::is_string_type::value, + "Error! name is not a string type"); + + auto _get_dbg = [&]() { + auto* _dbg = ctx.event()->add_debug_annotations(); + if(_idx >= 0) + { + auto _arg_name = JOIN("", "arg", _idx, "-", std::forward(_name)); + _dbg->set_name(_arg_name); + } + else + { + _dbg->set_name(std::string_view{ std::forward(_name) }.data()); + } + return _dbg; + }; + + if constexpr(std::is_same::value) + { + _get_dbg()->set_string_value(_val.data()); + } + else if constexpr(concepts::is_string_type::value) + { + _get_dbg()->set_string_value(std::forward(_val)); + } + else if constexpr(std::is_same::value) + { + _get_dbg()->set_bool_value(std::forward(_val)); + } + else if constexpr(std::is_enum::value) + { + _get_dbg()->set_int_value(static_cast(std::forward(_val))); + } + else if constexpr(std::is_floating_point::value) + { + _get_dbg()->set_double_value(std::forward(_val)); + } + else if constexpr(std::is_integral::value) + { + if constexpr(std::is_unsigned::value) + { + _get_dbg()->set_uint_value(std::forward(_val)); + } + else + { + _get_dbg()->set_int_value(std::forward(_val)); + } + } + else if constexpr(std::is_pointer::value) + { + _get_dbg()->set_pointer_value(reinterpret_cast(std::forward(_val))); + } + else if constexpr(concepts::can_stringify::value) + { + _get_dbg()->set_string_value(JOIN("", std::forward(_val))); + } + else + { + static_assert(std::is_empty::value, "Error! unsupported data type"); + } +} + +template +void +add_perfetto_annotation(perfetto_event_context_t& ctx, + const omnitrace_annotation_t& _annotation, + std::index_sequence) +{ + static_assert(Idx > OMNITRACE_VALUE_NONE && Idx < OMNITRACE_VALUE_LAST, + "Error! index sequence should only contain values which are greater " + "than OMNITRACE_VALUE_NONE and less than OMNITRACE_VALUE_LAST"); + + // in some situations the user might want to short circuit by setting + // the name to a null pointer, type to none, or value to a null pointer + if(_annotation.name == nullptr || _annotation.type == 0 || + _annotation.value == nullptr) + return; + + if(_annotation.type == Idx) + { + using type = annotation_value_type_t; + // if the type is a pointer, pass the pointer. otherwise, + // cast to pointer of that type and dereference it + if constexpr(std::is_pointer::value) + { + auto _value = reinterpret_cast(_annotation.value); + add_perfetto_annotation(ctx, _annotation.name, _value); + } + else + { + auto* _value = reinterpret_cast(_annotation.value); + add_perfetto_annotation(ctx, _annotation.name, *_value); + } + } + else + { + // the first "iteration": check whether annotation type has valid range + if constexpr(Idx == OMNITRACE_VALUE_NONE + 1) + { + if(!(_annotation.type > OMNITRACE_VALUE_NONE && + _annotation.type < OMNITRACE_VALUE_LAST)) + { + OMNITRACE_FAIL_F("Error! annotation '%s' has an invalid type designation " + "%lu which is outside of acceptable range [%i, %i]\n", + _annotation.name, _annotation.type, + OMNITRACE_VALUE_NONE + 1, OMNITRACE_VALUE_LAST - 1); + } + } + + if constexpr(sizeof...(Tail) > 0) + { + add_perfetto_annotation(ctx, _annotation, std::index_sequence{}); + } + else + { + throw std::runtime_error("invalid annotation value type"); + } + } +} + +void +add_perfetto_annotation(perfetto_event_context_t& ctx, + const omnitrace_annotation_t& _annotation); +} // namespace tracing +} // namespace omnitrace diff --git a/source/lib/omnitrace/library/utility.hpp b/source/lib/omnitrace/library/utility.hpp index cddaecad..c8156712 100644 --- a/source/lib/omnitrace/library/utility.hpp +++ b/source/lib/omnitrace/library/utility.hpp @@ -63,5 +63,29 @@ get_reserved_vector(size_t _n) _v.reserve(_n); return _v; } + +template +struct offset_index_sequence; + +template +struct offset_index_value +{ + static constexpr size_t value = Idx + Offset; +}; + +template +struct offset_index_sequence, Offset> +{ + using type = std::integer_sequence::value...>; +}; + +template +using make_offset_index_sequence = + offset_index_sequence, OffsetN>; + +template +using make_index_sequence_range = + typename offset_index_sequence, + StartN>::type; } // namespace utility } // namespace omnitrace diff --git a/source/python/libpyomnitrace.cpp b/source/python/libpyomnitrace.cpp index 8e8bfc8e..024ceefb 100644 --- a/source/python/libpyomnitrace.cpp +++ b/source/python/libpyomnitrace.cpp @@ -23,7 +23,8 @@ #include "libpyomnitrace.hpp" #include "dl.hpp" #include "library/coverage.hpp" -#include "library/impl/coverage.hpp" +#include "library/coverage/impl.hpp" +#include "omnitrace/categories.h" #include "omnitrace/user.h" #include @@ -179,6 +180,8 @@ using profiler_vec_t = std::vector; using profiler_label_map_t = std::unordered_map; using profiler_index_map_t = std::unordered_map; using strset_t = std::unordered_set; +using note_t = omnitrace_annotation_t; +using annotations_t = std::array; // namespace { @@ -202,6 +205,7 @@ struct config bool include_line = false; bool include_filename = false; bool full_filepath = false; + bool annotate_trace = false; int32_t ignore_stack_depth = 0; int32_t base_stack_depth = -1; int32_t verbose = 0; @@ -214,6 +218,12 @@ struct config strset_t exclude_functions = default_exclude_functions; strset_t exclude_filenames = default_exclude_filenames; std::vector records = {}; + annotations_t annotations = { note_t{ "file", OMNITRACE_STRING, nullptr }, + note_t{ "line", OMNITRACE_INT32, nullptr }, + note_t{ "lasti", OMNITRACE_INT32, nullptr }, + note_t{ "argcount", OMNITRACE_INT32, nullptr }, + note_t{ "nlocals", OMNITRACE_INT32, nullptr }, + note_t{ "stacksize", OMNITRACE_INT32, nullptr } }; }; // inline config& @@ -233,6 +243,7 @@ get_config() _tmp->include_line = _instance->include_line; _tmp->include_filename = _instance->include_filename; _tmp->full_filepath = _instance->full_filepath; + _tmp->annotate_trace = _instance->annotate_trace; _tmp->base_module_path = _instance->base_module_path; _tmp->restrict_functions = _instance->restrict_functions; _tmp->restrict_filenames = _instance->restrict_filenames; @@ -241,6 +252,7 @@ get_config() _tmp->exclude_functions = _instance->exclude_functions; _tmp->exclude_filenames = _instance->exclude_filenames; _tmp->verbose = _instance->verbose; + _tmp->annotations = _instance->annotations; // if full filepath is specified, include filename is implied if(_tmp->full_filepath && !_tmp->include_filename) _tmp->include_filename = true; return _tmp; @@ -454,12 +466,29 @@ profiler_function(py::object pframe, const char* swhat, py::object arg) static thread_local strset_t _labels{}; const auto& _label_ref = *_labels.emplace(_label).first; + auto _annotate = _config.annotate_trace; // start function auto _profiler_call = [&]() { - _config.records.emplace_back( - [&_label_ref]() { omnitrace_pop_region(_label_ref.c_str()); }); - omnitrace_push_region(_label_ref.c_str()); + if(_annotate) + { + _config.annotations.at(0).value = const_cast(_full.c_str()); + _config.annotations.at(1).value = &frame->f_lineno; + _config.annotations.at(2).value = &frame->f_lasti; + _config.annotations.at(3).value = &frame->f_code->co_argcount; + _config.annotations.at(4).value = &frame->f_code->co_nlocals; + _config.annotations.at(5).value = &frame->f_code->co_stacksize; + } + + _config.records.emplace_back([&_label_ref, _annotate]() { + omnitrace_pop_category_region(OMNITRACE_CATEGORY_PYTHON, _label_ref.c_str(), + (_annotate) ? _config.annotations.data() + : nullptr, + _config.annotations.size()); + }); + omnitrace_push_category_region(OMNITRACE_CATEGORY_PYTHON, _label_ref.c_str(), + (_annotate) ? _config.annotations.data() : nullptr, + _config.annotations.size()); }; // stop function @@ -554,6 +583,10 @@ generate(py::module& _pymod) CONFIGURATION_PROPERTY("full_filepath", bool, "Display the full filepath (instead of file basename)", get_config().full_filepath) + CONFIGURATION_PROPERTY( + "annotate_trace", bool, + "Add detailed annotations to the trace about the executing function", + get_config().annotate_trace) CONFIGURATION_PROPERTY("verbosity", int32_t, "Verbosity of the logging", get_config().verbose) diff --git a/source/python/omnitrace/__main__.py b/source/python/omnitrace/__main__.py index 2af35bc7..1734409a 100644 --- a/source/python/omnitrace/__main__.py +++ b/source/python/omnitrace/__main__.py @@ -220,6 +220,16 @@ def str2bool(v): default=_profiler_config.trace_c, help="Enable profiling C functions", ) + parser.add_argument( + "-a", + "--annotate-trace", + type=str2bool, + nargs="?", + metavar="BOOL", + const=True, + default=_profiler_config.annotate_trace, + help="Enable perfetto debug annotations", + ) return parser.parse_args(args) @@ -322,6 +332,7 @@ def main(): _profiler_config.exclude_modules = opts.module_exclude _profiler_config.restrict_functions = opts.function_restrict _profiler_config.restrict_modules = opts.module_restrict + _profiler_config.annotate_trace = opts.annotate_trace _profiler_config.verbosity = opts.verbosity print("[omnitrace]> profiling: {}".format(argv)) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3042487c..5a69d801 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -513,8 +513,7 @@ function(OMNITRACE_ADD_PYTHON_TEST) if(NOT TEST_COMMAND) list(APPEND TEST_ENVIRONMENT "OMNITRACE_CI=ON" - "OMNITRACE_OUTPUT_PATH=${PROJECT_BINARY_DIR}/omnitrace-tests-output" - "OMNITRACE_OUTPUT_PREFIX=${TEST_NAME}/${TEST_PYTHON_VERSION}/") + "OMNITRACE_OUTPUT_PATH=${PROJECT_BINARY_DIR}/omnitrace-tests-output") get_filename_component(_TEST_FILE "${TEST_FILE}" NAME) set(_TEST_FILE ${PROJECT_BINARY_DIR}/python/tests/${TEST_PYTHON_VERSION}/${_TEST_FILE}) @@ -530,6 +529,11 @@ function(OMNITRACE_ADD_PYTHON_TEST) COMMAND ${TEST_PYTHON_EXECUTABLE} -m omnitrace ${TEST_PROFILE_ARGS} -- ${_TEST_FILE} ${TEST_RUN_ARGS} WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) + add_test( + NAME ${TEST_NAME}-${TEST_PYTHON_VERSION}-annotated + COMMAND ${TEST_PYTHON_EXECUTABLE} -m omnitrace ${TEST_PROFILE_ARGS} + --annotate-trace -- ${_TEST_FILE} ${TEST_RUN_ARGS} + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) endif() else() list(APPEND TEST_LABELS "python-check" "python-${TEST_PYTHON_VERSION}-check") @@ -543,13 +547,20 @@ function(OMNITRACE_ADD_PYTHON_TEST) WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) endif() - foreach(_TEST ${TEST_NAME}-${TEST_PYTHON_VERSION} - ${TEST_NAME}-${TEST_PYTHON_VERSION}-inverse) + foreach( + _TEST + ${TEST_NAME}-${TEST_PYTHON_VERSION} ${TEST_NAME}-${TEST_PYTHON_VERSION}-inverse + ${TEST_NAME}-${TEST_PYTHON_VERSION}-annotated) if(NOT TEST "${_TEST}") continue() endif() + string(REPLACE "${TEST_NAME}-${TEST_PYTHON_VERSION}" "${TEST_NAME}" _TEST_DIR + "${_TEST}") + set(_TEST_ENV "${TEST_ENVIRONMENT}" + "OMNITRACE_OUTPUT_PREFIX=${_TEST_DIR}/${TEST_PYTHON_VERSION}/") + set(_TEST_PROPERTIES "${TEST_PROPERTIES}") if(NOT "${_TEST}" MATCHES "inverse") # assign pass variable to pass regex @@ -568,7 +579,7 @@ function(OMNITRACE_ADD_PYTHON_TEST) set_tests_properties( ${_TEST} PROPERTIES ENVIRONMENT - "${TEST_ENVIRONMENT}" + "${_TEST_ENV}" TIMEOUT ${TEST_TIMEOUT} LABELS @@ -809,6 +820,10 @@ omnitrace_add_test( args RUN_ARGS 10 ${NUM_THREADS} 1000 ENVIRONMENT "${_base_environment};OMNITRACE_CRITICAL_TRACE=OFF" + REWRITE_RUN_PASS_REGEX "Pushing custom region :: run.10. x 1000" + RUNTIME_PASS_REGEX "Pushing custom region :: run.10. x 1000" + PRELOAD_PASS_REGEX "Pushing custom region :: run.10. x 1000" + BASELINE_FAIL_REGEX "Pushing custom region" REWRITE_FAIL_REGEX "0 instrumented loops in procedure") if(OMNITRACE_USE_MPI OR OMNITRACE_USE_MPI_HEADERS)