Support external (i.e. user-defined) trace annotations (#195)

* Support external (i.e. user-defined) trace annotations

- tweaked the python examples to be more balanced
- updated the user-api example to conform to user API changes
- moved the get/set for State and ThreadState to state.{hpp,cpp}
- introduced user-provided trace annotations
- added perfetto python category
- moved coverage impl files around
- created enumerations for mapping category enums to category types
- created enumerations for mapping annotation type enums to annotation values
- moved tracing::add_perfetto_annotations to tracing/annotation.hpp
- utility make_index_sequence_range
- libomnitrace-dl: omnitrace_push_category_region
- libomnitrace-dl: omnitrace_pop_category_region
- libomnitrace-user: omnitrace_user_push_annotated_region
- libomnitrace-user: omnitrace_user_pop_annotated_region
- libpyomnitrace: support extra annotations via annotate_trace config value
  - filename
  - line
  - last attempted instr in bytecode (lasti)
  - argcount
  - num local variables
  - stacksize
- omnitrace-python: -a / --annotate-traces option

* tweak ubuntu-focal workflow

* Fix installation of omnitrace-user headers

* ubuntu-focal-codecov workflow update

- Install texinfo

* Update timemory submodule

[ROCm/rocprofiler-systems commit: 642b6b95ca]
This commit is contained in:
Jonathan R. Madsen
2022-11-11 07:31:14 -06:00
committed by GitHub
parent 0e963e47c8
commit 91627797a0
40 changed files with 1280 additions and 430 deletions
@@ -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
@@ -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(
@@ -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}")
@@ -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}")
@@ -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}")
@@ -23,7 +23,7 @@ try:
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 @@ except ImportError:
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}")
@@ -1,10 +1,14 @@
#include "omnitrace/categories.h"
#include "omnitrace/types.h"
#include <omnitrace/user.h>
#include <atomic>
#include <cassert>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <thread>
#include <vector>
@@ -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);
}
Submodule projects/rocprofiler-systems/external/timemory updated: 7a6a361eb8...040456175a
@@ -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)
@@ -39,6 +39,8 @@
#include "common/join.hpp"
#include "common/setup.hpp"
#include "dl.hpp"
#include "omnitrace/categories.h"
#include "omnitrace/types.h"
#include <cassert>
#include <gnu/libc-version.h>
@@ -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<void*>(&omnitrace_user_start_trace_dl),
reinterpret_cast<void*>(&omnitrace_user_stop_trace_dl));
(*omnitrace_user_configure_f)(
OMNITRACE_USER_START_STOP_THREAD,
reinterpret_cast<void*>(&omnitrace_user_start_thread_trace_dl),
reinterpret_cast<void*>(&omnitrace_user_stop_thread_trace_dl));
(*omnitrace_user_configure_f)(
OMNITRACE_USER_REGION,
reinterpret_cast<void*>(&omnitrace_user_push_region_dl),
reinterpret_cast<void*>(&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
@@ -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
{
@@ -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
@@ -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 <stddef.h>
#include <stdint.h>
#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 <cstddef>
/// #include <cstdint>
///
/// #include <omnitrace/user.h>
///
/// 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_
@@ -21,8 +21,9 @@
// SOFTWARE.
#ifndef OMNITRACE_TYPES_H_
#define OMNITRACE_TYPES_H_ 1
#define OMNITRACE_TYPES_H_
#include <stddef.h>
#include <stdint.h>
#if defined(__cplusplus)
@@ -30,7 +31,77 @@ extern "C"
{
#endif
/// @enum OMNITRACE_USER_ERROR
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);
/// @typedef omnitrace_user_callbacks_t
/// @brief Struct containing the callbacks for the user API
/// @code{.cpp}
///
/// #include <cerrno>
/// #include <cstring>
///
/// 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)
/// {
/// 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)
/// {
/// custom_callbacks.push_region = &custom_push_region;
/// omnitrace_user_configure(OMNITRACE_USER_UNION_CONFIG, custom_callbacks,
/// &original_callbacks);
/// // ...
/// }
///
/// @endcode
typedef struct omnitrace_user_callbacks
{
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
@@ -43,46 +114,15 @@ extern "C"
OMNITRACE_USER_ERROR_LAST
} omnitrace_user_error_t;
/// @enum OMNITRACE_USER_BINDINGS
/// @brief Identifier for function pointer categories
/// @code{.cpp}
/// int (*omnitrace_push_region_f)(const char*) = nullptr;
///
/// 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);
/// }
///
/// 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);
/// // ...
/// }
///
/// @endcode
typedef enum OMNITRACE_USER_BINDINGS
{
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;
#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_
@@ -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 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 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 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
@@ -25,41 +25,24 @@
#endif
#include "omnitrace/user.h"
#include "omnitrace/categories.h"
#include "omnitrace/types.h"
#include <atomic>
#include <cstdio>
#include <cstdlib>
#include <optional>
using annotation_t = omnitrace_annotation_t;
namespace
{
using trace_func_t = int (*)(void);
using region_func_t = int (*)(const char*);
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;
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<int>(_category));
fflush(stderr);
break;
}
}
return "OMNITRACE_USER_BINDINGS_unknown";
}
user_callbacks_t _callbacks = OMNITRACE_USER_CALLBACKS_INIT;
template <typename... Args>
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_start_trace(void) { return invoke(_callbacks.start_trace); }
int omnitrace_user_configure(int category, void* begin_func, void* end_func)
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<trace_func_t>(begin_func);
if(end_func) _stop_trace = reinterpret_cast<trace_func_t>(end_func);
break;
}
case OMNITRACE_USER_START_STOP_THREAD:
{
if(begin_func)
_start_thread_trace = reinterpret_cast<trace_func_t>(begin_func);
if(end_func)
_stop_thread_trace = reinterpret_cast<trace_func_t>(end_func);
break;
}
case OMNITRACE_USER_REGION:
{
if(begin_func) _push_region = reinterpret_cast<region_func_t>(begin_func);
if(end_func) _pop_region = reinterpret_cast<region_func_t>(end_func);
break;
}
default:
{
return OMNITRACE_USER_ERROR_INVALID_CATEGORY;
}
}
return OMNITRACE_USER_SUCCESS;
return invoke(_callbacks.start_thread_trace);
}
int omnitrace_user_get_callbacks(int category, void** begin_func, void** end_func)
int omnitrace_user_stop_thread_trace(void)
{
switch(category)
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_configure(omnitrace_user_configure_mode_t _mode,
omnitrace_user_callbacks_t _inp,
omnitrace_user_callbacks_t* _out)
{
auto _former = _callbacks;
switch(_mode)
{
case OMNITRACE_USER_START_STOP:
case OMNITRACE_USER_REPLACE_CONFIG:
{
if(begin_func) *begin_func = reinterpret_cast<void*>(_start_trace);
if(end_func) *end_func = reinterpret_cast<void*>(_stop_trace);
_callbacks = _inp;
break;
}
case OMNITRACE_USER_START_STOP_THREAD:
case OMNITRACE_USER_UNION_CONFIG:
{
if(begin_func) *begin_func = reinterpret_cast<void*>(_start_thread_trace);
if(end_func) *end_func = reinterpret_cast<void*>(_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<void*>(_push_region);
if(end_func) *end_func = reinterpret_cast<void*>(_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;
}
@@ -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)
{
@@ -23,6 +23,7 @@
#pragma once
#include "library/defines.hpp"
#include "omnitrace/categories.h" // in omnitrace-user
#include <timemory/compat/macros.h>
@@ -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;
}
@@ -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 <timemory/signals/signal_handlers.hpp>
#include <timemory/signals/types.hpp>
@@ -65,6 +67,7 @@
#include <cstdio>
#include <mutex>
#include <string_view>
#include <utility>
using namespace omnitrace;
@@ -187,6 +190,100 @@ omnitrace_pop_region_hidden(const char* name)
///
//======================================================================================//
namespace omnitrace
{
namespace
{
template <size_t Idx, size_t... Tail>
void
invoke_category_region_start(omnitrace_category_t _category, const char* name,
omnitrace_annotation_t* _annotations,
size_t _annotation_count, std::index_sequence<Idx, Tail...>)
{
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<Idx>;
component::category_region<category_type>::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<Tail...>{});
}
}
} // namespace
template <size_t Idx, size_t... Tail>
void
invoke_category_region_stop(omnitrace_category_t _category, const char* name,
omnitrace_annotation_t* _annotations,
size_t _annotation_count, std::index_sequence<Idx, Tail...>)
{
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<Idx>;
component::category_region<category_type>::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<Tail...>{});
}
}
} // 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
@@ -82,4 +82,6 @@ if(OMNITRACE_USE_ROCM_SMI)
endif()
add_subdirectory(components)
add_subdirectory(coverage)
add_subdirectory(rocm)
add_subdirectory(tracing)
@@ -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 <size_t>
struct category_type_id;
template <typename Tp>
struct category_enum_id;
template <size_t Idx>
using category_type_id_t = typename category_type_id<Idx>::type;
} // namespace omnitrace
#define OMNITRACE_DEFINE_CATEGORY_TRAIT(TYPE, ENUM) \
namespace omnitrace \
{ \
template <> \
struct category_type_id<ENUM> \
{ \
using type = TYPE; \
}; \
template <> \
struct category_enum_id<TYPE> \
{ \
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_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, "sampling", "Host-side call-stack sampling")
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<Tp...>;
#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), \
@@ -28,6 +28,7 @@
#include "library/runtime.hpp"
#include "library/timemory.hpp"
#include "library/tracing.hpp"
#include "library/tracing/annotation.hpp"
#include <timemory/components/gotcha/backends.hpp>
#include <timemory/mpl/concepts.hpp>
@@ -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
@@ -355,13 +355,4 @@ struct tmp_file
std::shared_ptr<tmp_file>
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
@@ -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 <timemory/backends/threading.hpp>
@@ -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})
@@ -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<OMNITRACE_MAX_THREADS>(
[]() { return utility::get_reserved_vector<ThreadState>(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()
{
@@ -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__) \
@@ -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 <timemory/backends/papi.hpp>
@@ -21,9 +21,96 @@
// SOFTWARE.
#include "library/state.hpp"
#include "library/config.hpp"
#include "library/debug.hpp"
#include "library/utility.hpp"
#include <string>
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<OMNITRACE_MAX_THREADS>(
[]() { return utility::get_reserved_vector<ThreadState>(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
@@ -24,6 +24,8 @@
#include "library/defines.hpp"
#include <string>
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 <string>
#define OMNITRACE_SCOPED_THREAD_STATE(STATE) \
::omnitrace::scoped_thread_state OMNITRACE_VARIABLE(_scoped_thread_state_, __LINE__) \
{ \
::omnitrace::STATE \
}
namespace std
{
@@ -200,76 +200,6 @@ pop_timemory(CategoryT, const char* name, Args&&... args)
}
}
template <typename Np, typename Tp>
auto
add_perfetto_annotation(perfetto::EventContext& ctx, Np&& _name, Tp&& _val,
int64_t _idx = -1)
{
using named_type = std::remove_reference_t<std::remove_cv_t<std::decay_t<Np>>>;
using value_type = std::remove_reference_t<std::remove_cv_t<std::decay_t<Tp>>>;
static_assert(concepts::is_string_type<named_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<Np>(_name));
_dbg->set_name(_arg_name);
}
else
{
_dbg->set_name(std::string_view{ std::forward<Np>(_name) }.data());
}
return _dbg;
};
if constexpr(std::is_same<value_type, std::string_view>::value)
{
_get_dbg()->set_string_value(_val.data());
}
else if constexpr(concepts::is_string_type<value_type>::value)
{
_get_dbg()->set_string_value(std::forward<Tp>(_val));
}
else if constexpr(std::is_same<value_type, bool>::value)
{
_get_dbg()->set_bool_value(std::forward<Tp>(_val));
}
else if constexpr(std::is_enum<value_type>::value)
{
_get_dbg()->set_int_value(static_cast<int64_t>(std::forward<Tp>(_val)));
}
else if constexpr(std::is_floating_point<value_type>::value)
{
_get_dbg()->set_double_value(std::forward<Tp>(_val));
}
else if constexpr(std::is_integral<value_type>::value)
{
if constexpr(std::is_unsigned<value_type>::value)
{
_get_dbg()->set_uint_value(std::forward<Tp>(_val));
}
else
{
_get_dbg()->set_int_value(std::forward<Tp>(_val));
}
}
else if constexpr(std::is_pointer<value_type>::value)
{
_get_dbg()->set_pointer_value(reinterpret_cast<uint64_t>(std::forward<Tp>(_val)));
}
else if constexpr(concepts::can_stringify<value_type>::value)
{
_get_dbg()->set_string_value(JOIN("", std::forward<Tp>(_val)));
}
else
{
static_assert(std::is_empty<value_type>::value, "Error! unsupported data type");
}
}
template <typename CategoryT, typename... Args>
inline void
push_perfetto(CategoryT, const char* name, Args&&... args)
@@ -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})
@@ -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
@@ -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 <timemory/mpl/concepts.hpp>
#include <type_traits>
namespace omnitrace
{
namespace tracing
{
using perfetto_event_context_t = ::perfetto::EventContext;
template <size_t Idx>
struct annotation_value_type;
template <size_t Idx>
using annotation_value_type_t = typename annotation_value_type<Idx>::type;
#define OMNITRACE_DEFINE_ANNOTATION_TYPE(ENUM, TYPE) \
template <> \
struct annotation_value_type<ENUM> \
{ \
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 <typename Np, typename Tp>
auto
add_perfetto_annotation(
perfetto_event_context_t& ctx, Np&& _name, Tp&& _val, int64_t _idx = -1,
std::enable_if_t<
!std::is_same<std::remove_pointer_t<concepts::unqualified_type_t<Np>>,
omnitrace_annotation_t>::value,
int> = 0)
{
using named_type = std::remove_reference_t<std::remove_cv_t<std::decay_t<Np>>>;
using value_type = std::remove_reference_t<std::remove_cv_t<std::decay_t<Tp>>>;
static_assert(concepts::is_string_type<named_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<Np>(_name));
_dbg->set_name(_arg_name);
}
else
{
_dbg->set_name(std::string_view{ std::forward<Np>(_name) }.data());
}
return _dbg;
};
if constexpr(std::is_same<value_type, std::string_view>::value)
{
_get_dbg()->set_string_value(_val.data());
}
else if constexpr(concepts::is_string_type<value_type>::value)
{
_get_dbg()->set_string_value(std::forward<Tp>(_val));
}
else if constexpr(std::is_same<value_type, bool>::value)
{
_get_dbg()->set_bool_value(std::forward<Tp>(_val));
}
else if constexpr(std::is_enum<value_type>::value)
{
_get_dbg()->set_int_value(static_cast<int64_t>(std::forward<Tp>(_val)));
}
else if constexpr(std::is_floating_point<value_type>::value)
{
_get_dbg()->set_double_value(std::forward<Tp>(_val));
}
else if constexpr(std::is_integral<value_type>::value)
{
if constexpr(std::is_unsigned<value_type>::value)
{
_get_dbg()->set_uint_value(std::forward<Tp>(_val));
}
else
{
_get_dbg()->set_int_value(std::forward<Tp>(_val));
}
}
else if constexpr(std::is_pointer<value_type>::value)
{
_get_dbg()->set_pointer_value(reinterpret_cast<uint64_t>(std::forward<Tp>(_val)));
}
else if constexpr(concepts::can_stringify<value_type>::value)
{
_get_dbg()->set_string_value(JOIN("", std::forward<Tp>(_val)));
}
else
{
static_assert(std::is_empty<value_type>::value, "Error! unsupported data type");
}
}
template <size_t Idx, size_t... Tail>
void
add_perfetto_annotation(perfetto_event_context_t& ctx,
const omnitrace_annotation_t& _annotation,
std::index_sequence<Idx, Tail...>)
{
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<Idx>;
// if the type is a pointer, pass the pointer. otherwise,
// cast to pointer of that type and dereference it
if constexpr(std::is_pointer<type>::value)
{
auto _value = reinterpret_cast<type>(_annotation.value);
add_perfetto_annotation(ctx, _annotation.name, _value);
}
else
{
auto* _value = reinterpret_cast<type*>(_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<Tail...>{});
}
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
@@ -63,5 +63,29 @@ get_reserved_vector(size_t _n)
_v.reserve(_n);
return _v;
}
template <typename Tp, size_t Offset>
struct offset_index_sequence;
template <size_t Idx, size_t Offset>
struct offset_index_value
{
static constexpr size_t value = Idx + Offset;
};
template <size_t Offset, size_t... Idx>
struct offset_index_sequence<std::index_sequence<Idx...>, Offset>
{
using type = std::integer_sequence<size_t, offset_index_value<Idx, Offset>::value...>;
};
template <size_t N, size_t OffsetN>
using make_offset_index_sequence =
offset_index_sequence<std::make_index_sequence<N>, OffsetN>;
template <size_t StartN, size_t EndN>
using make_index_sequence_range =
typename offset_index_sequence<std::make_index_sequence<(EndN - StartN)>,
StartN>::type;
} // namespace utility
} // namespace omnitrace
@@ -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 <timemory/backends/process.hpp>
@@ -179,6 +180,8 @@ using profiler_vec_t = std::vector<profiler_t>;
using profiler_label_map_t = std::unordered_map<std::string, profiler_vec_t>;
using profiler_index_map_t = std::unordered_map<uint32_t, profiler_label_map_t>;
using strset_t = std::unordered_set<std::string>;
using note_t = omnitrace_annotation_t;
using annotations_t = std::array<note_t, 6>;
//
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<profiler_t> 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<char*>(_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)
@@ -220,6 +220,16 @@ def parse_args(args=None):
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))
@@ -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)