omnitrace-dl-library (#25)
* timemory submodule update
* Visibility, setting categories, and task-group protection
- OMNITRACE_VISIBILITY instead of TIMEMORY_VISIBILITY
- increased task group data-race protection
- add omnitrace categories to settings
* set component_apis type-trait
* omnitrace-dl-library implementation
- this library dlopen + dlsym's libomnitrace
- significantly reduces the instrumentation time
* omnitrace-avail categories
- suppress AVAILABLE column when --available
* omnitrace-exe update
- uses omnitrace-dl
- adds --print-excluded option
- removes --jump option
- comments out --stubs option
- removes --stdlib option
- support for C++ STL functions not in libstdc++
- tweak the --print-* outputs
- significantly refactors instrument_module and instrument_entity
- removes unused c_stdlib_module_constraint
- removes unused c_stdlib_function_constraint
- decreases get_whole_function_names() coverage
* library.cpp updates
- OMNITRACE_DEBUG -> OMNITRACE_DEBUG_F
- omnitrace_finalize sets state earlier
- omnitrace_finalize clears push/pop functors
- increased tasking shutdown safety
* - fix critical-trace thread hierarchy
- signal handler calls omnitrace_finalize
- get_cpu_cid_stack supports parent tid
- interval data reserves
- omnitrace-avail serialization support for module_functions
- omnitrace --simulate option
- omnitrace --print-format option
- omnitrace --load-instr option
- omnitrace runtime-inst doesn't oneTimeCode
- updated regex
- expand get_whole_function_names()
- Test Install CI update
* fixes to last commit
- expand get_whole_function_names()
- ignore sig c modules
- kill process in signal handler
* Remove RTLD_DEEPBIND + more
- removed use of RTLD_DEEPBIND
- causes dyninst segfaults
- fixed signal handling
- updated timemory submodule
* Build/link static timemory libraries
* omnitrace --{module,function}-restrict option
- Added restrict regex options
- Reworked handling of regex options
- Reworked reporting of module/function skipping
- Handle -o w/o file specified
* timemory-avail
- category views
- backtrace::sample checks state
* get_debug_sampling()
[ROCm/rocprofiler-systems commit: 145a6ae06f]
This commit is contained in:
committed by
GitHub
orang tua
b99b153030
melakukan
8b058902a2
@@ -30,7 +30,7 @@ target_link_libraries(
|
||||
$<BUILD_INTERFACE:omnitrace::omnitrace-ptl>
|
||||
$<BUILD_INTERFACE:timemory::timemory-headers>
|
||||
$<BUILD_INTERFACE:timemory::timemory-gotcha>
|
||||
$<BUILD_INTERFACE:timemory::timemory-cxx-shared>
|
||||
$<BUILD_INTERFACE:timemory::timemory-cxx-static>
|
||||
$<IF:$<BOOL:${OMNITRACE_USE_SANITIZER}>,omnitrace::omnitrace-sanitizer,>)
|
||||
|
||||
# ------------------------------------------------------------------------------#
|
||||
@@ -137,3 +137,31 @@ install(
|
||||
TARGETS omnitrace-library
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
OPTIONAL)
|
||||
|
||||
# ------------------------------------------------------------------------------#
|
||||
#
|
||||
# omnitrace dl library
|
||||
#
|
||||
# ------------------------------------------------------------------------------#
|
||||
|
||||
add_library(omnitrace-dl-library SHARED)
|
||||
add_library(omnitrace::omnitrace-dl-library ALIAS omnitrace-dl-library)
|
||||
|
||||
target_compile_definitions(omnitrace-dl-library PRIVATE TIMEMORY_USE_VISIBILITY=0)
|
||||
target_sources(omnitrace-dl-library PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/dl.cpp)
|
||||
target_link_libraries(omnitrace-dl-library
|
||||
PRIVATE $<BUILD_INTERFACE:timemory::timemory-headers>)
|
||||
|
||||
set_target_properties(
|
||||
omnitrace-dl-library
|
||||
PROPERTIES OUTPUT_NAME omnitrace-dl
|
||||
CXX_VISIBILITY_PRESET "hidden"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
INSTALL_RPATH "\$ORIGIN")
|
||||
|
||||
install(
|
||||
TARGETS omnitrace-dl-library
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
OPTIONAL)
|
||||
|
||||
@@ -30,27 +30,27 @@
|
||||
extern "C"
|
||||
{
|
||||
/// handles configuration logic
|
||||
void omnitrace_init_library(void) TIMEMORY_VISIBILITY("default");
|
||||
void omnitrace_init_library(void) OMNITRACE_VISIBILITY("default");
|
||||
|
||||
/// starts gotcha wrappers
|
||||
void omnitrace_init(const char*, bool, const char*) TIMEMORY_VISIBILITY("default");
|
||||
void omnitrace_init(const char*, bool, const char*) OMNITRACE_VISIBILITY("default");
|
||||
|
||||
/// shuts down all tooling and generates output
|
||||
void omnitrace_finalize(void) TIMEMORY_VISIBILITY("default");
|
||||
void omnitrace_finalize(void) OMNITRACE_VISIBILITY("default");
|
||||
|
||||
/// sets an environment variable
|
||||
void omnitrace_set_env(const char* env_name, const char* env_val)
|
||||
TIMEMORY_VISIBILITY("default");
|
||||
OMNITRACE_VISIBILITY("default");
|
||||
|
||||
/// sets whether MPI should be used
|
||||
void omnitrace_set_mpi(bool use, bool attached) TIMEMORY_VISIBILITY("default");
|
||||
void omnitrace_set_mpi(bool use, bool attached) OMNITRACE_VISIBILITY("default");
|
||||
|
||||
/// starts an instrumentation region
|
||||
void omnitrace_push_trace(const char* name) TIMEMORY_VISIBILITY("default");
|
||||
void omnitrace_push_trace(const char* name) OMNITRACE_VISIBILITY("default");
|
||||
|
||||
/// stops an instrumentation region
|
||||
void omnitrace_pop_trace(const char* name) TIMEMORY_VISIBILITY("default");
|
||||
void omnitrace_pop_trace(const char* name) OMNITRACE_VISIBILITY("default");
|
||||
|
||||
/// used by omnitrace-critical-trace
|
||||
bool omnitrace_init_tooling() TIMEMORY_VISIBILITY("hidden");
|
||||
bool omnitrace_init_tooling() OMNITRACE_VISIBILITY("hidden");
|
||||
}
|
||||
|
||||
@@ -24,12 +24,16 @@
|
||||
|
||||
#include "library/defines.hpp"
|
||||
|
||||
#include <timemory/api.hpp>
|
||||
#include <timemory/api/macros.hpp>
|
||||
#include <timemory/components/data_tracker/types.hpp>
|
||||
#include <timemory/components/macros.hpp>
|
||||
#include <timemory/components/user_bundle/types.hpp>
|
||||
#include <timemory/enum.h>
|
||||
#include <timemory/mpl/concepts.hpp>
|
||||
|
||||
TIMEMORY_DEFINE_NS_API(project, omnitrace)
|
||||
|
||||
TIMEMORY_DECLARE_COMPONENT(roctracer)
|
||||
|
||||
namespace omnitrace
|
||||
@@ -92,6 +96,34 @@ TIMEMORY_DEFINE_CONCRETE_TRAIT(is_available, omnitrace::component::sampling_gpu_
|
||||
false_type)
|
||||
#endif
|
||||
|
||||
TIMEMORY_SET_COMPONENT_API(omnitrace::component::omnitrace, project::omnitrace,
|
||||
category::dynamic_instrumentation, os::supports_linux)
|
||||
TIMEMORY_SET_COMPONENT_API(omnitrace::component::roctracer, project::omnitrace,
|
||||
tpls::rocm, device::gpu, os::supports_linux,
|
||||
category::external)
|
||||
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_wall_clock, project::omnitrace,
|
||||
category::timing, os::supports_unix, category::sampling,
|
||||
category::interrupt_sampling)
|
||||
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_cpu_clock, project::omnitrace,
|
||||
category::timing, os::supports_unix, category::sampling,
|
||||
category::interrupt_sampling)
|
||||
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_percent, project::omnitrace,
|
||||
category::timing, os::supports_unix, category::sampling,
|
||||
category::interrupt_sampling)
|
||||
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_gpu_busy, project::omnitrace,
|
||||
tpls::rocm, device::gpu, os::supports_linux,
|
||||
category::sampling, category::thread_sampling)
|
||||
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_gpu_memory, project::omnitrace,
|
||||
tpls::rocm, device::gpu, os::supports_linux, category::memory,
|
||||
category::sampling, category::thread_sampling)
|
||||
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_gpu_power, project::omnitrace,
|
||||
tpls::rocm, device::gpu, os::supports_linux, category::power,
|
||||
category::sampling, category::thread_sampling)
|
||||
TIMEMORY_SET_COMPONENT_API(omnitrace::component::sampling_gpu_temp, project::omnitrace,
|
||||
tpls::rocm, device::gpu, os::supports_linux,
|
||||
category::temperature, category::sampling,
|
||||
category::thread_sampling)
|
||||
|
||||
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::omnitrace, OMNITRACE_COMPONENT,
|
||||
"omnitrace", "omnitrace_component")
|
||||
TIMEMORY_PROPERTY_SPECIALIZATION(omnitrace::component::roctracer, OMNITRACE_ROCTRACER,
|
||||
|
||||
+2
-1
@@ -37,13 +37,14 @@ struct pthread_gotcha : tim::component::base<pthread_gotcha, void>
|
||||
using routine_t = void* (*) (void*);
|
||||
using promise_t = std::promise<void>;
|
||||
|
||||
wrapper(routine_t _routine, void* _arg, bool, promise_t*);
|
||||
wrapper(routine_t _routine, void* _arg, bool, int64_t, promise_t*);
|
||||
void* operator()() const;
|
||||
|
||||
static void* wrap(void* _arg);
|
||||
|
||||
private:
|
||||
bool m_enable_sampling = false;
|
||||
int64_t m_parent_tid = 0;
|
||||
routine_t m_routine = nullptr;
|
||||
void* m_arg = nullptr;
|
||||
promise_t* m_promise = nullptr;
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
#include "library/defines.hpp"
|
||||
#include "library/state.hpp"
|
||||
#include "library/timemory.hpp"
|
||||
#include "timemory/macros/language.hpp"
|
||||
|
||||
#include <timemory/backends/threading.hpp>
|
||||
#include <timemory/macros/language.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
@@ -129,6 +129,9 @@ get_debug_finalize();
|
||||
bool
|
||||
get_debug();
|
||||
|
||||
bool
|
||||
get_debug_sampling();
|
||||
|
||||
bool
|
||||
get_debug_tid();
|
||||
|
||||
@@ -252,5 +255,5 @@ std::atomic<uint64_t>&
|
||||
get_cpu_cid();
|
||||
|
||||
std::unique_ptr<std::vector<uint64_t>>&
|
||||
get_cpu_cid_stack(int64_t _tid = threading::get_id());
|
||||
get_cpu_cid_stack(int64_t _tid = threading::get_id(), int64_t _parent = 0);
|
||||
} // namespace omnitrace
|
||||
|
||||
@@ -50,3 +50,8 @@
|
||||
#define OMNITRACE_SAMPLING_GPU_TEMP OMNITRACE_SAMPLING_GPU_TEMP_idx
|
||||
#define OMNITRACE_SAMPLING_GPU_BUSY OMNITRACE_SAMPLING_GPU_BUSY_idx
|
||||
#define OMNITRACE_SAMPLING_GPU_MEMORY_USAGE OMNITRACE_SAMPLING_GPU_MEMORY_USAGE_idx
|
||||
|
||||
#define OMNITRACE_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
|
||||
#define OMNITRACE_VISIBILITY(MODE) OMNITRACE_ATTRIBUTE(visibility(MODE))
|
||||
#define OMNITRACE_PUBLIC_API OMNITRACE_VISIBILITY("default")
|
||||
#define OMNITRACE_HIDDEN_API OMNITRACE_VISIBILITY("hidden")
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020, The Regents of the University of California,
|
||||
// through Lawrence Berkeley National Laboratory (subject to receipt of any
|
||||
// required approvals from the U.S. Dept. of Energy). All rights reserved.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <timemory/backends/process.hpp>
|
||||
#include <timemory/environment.hpp>
|
||||
#include <timemory/environment/types.hpp>
|
||||
#include <timemory/macros/attributes.hpp>
|
||||
#include <timemory/utility/demangle.hpp>
|
||||
#include <timemory/variadic/macros.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <dlfcn.h>
|
||||
#include <gnu/libc-version.h>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define OMNITRACE_VISIBLE __attribute__((visibility("default")))
|
||||
#define OMNITRACE_HIDDEN __attribute__((visibility("internal")))
|
||||
#define OMNITRACE_INLINE __attribute__((__always_inline__))
|
||||
#define OMNITRACE_DLSYM(VARNAME, HANDLE, FUNCNAME) \
|
||||
if(HANDLE) \
|
||||
{ \
|
||||
*(void**) (&VARNAME) = dlsym(HANDLE, FUNCNAME); \
|
||||
if(VARNAME == nullptr && _omnitrace_dl_verbose >= 0) \
|
||||
{ \
|
||||
fprintf(stderr, "[omnitrace][dl][pid=%i]> %s :: %s\n", process::get_id(), \
|
||||
FUNCNAME, dlerror()); \
|
||||
} \
|
||||
}
|
||||
|
||||
namespace process = tim::process;
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
//
|
||||
// omnitrace symbols
|
||||
//
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void omnitrace_init_library(void) OMNITRACE_VISIBLE;
|
||||
void omnitrace_init(const char*, bool, const char*) OMNITRACE_VISIBLE;
|
||||
void omnitrace_finalize(void) OMNITRACE_VISIBLE;
|
||||
void omnitrace_set_env(const char* env_name, const char* env_val) OMNITRACE_VISIBLE;
|
||||
void omnitrace_set_mpi(bool use, bool attached) OMNITRACE_VISIBLE;
|
||||
void omnitrace_push_trace(const char* name) OMNITRACE_VISIBLE;
|
||||
void omnitrace_pop_trace(const char* name) OMNITRACE_VISIBLE;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
namespace
|
||||
{
|
||||
inline int
|
||||
get_omnitrace_env();
|
||||
|
||||
// environment priority:
|
||||
// - OMNITRACE_DL_DEBUG
|
||||
// - OMNITRACE_DL_VERBOSE
|
||||
// - OMNITRACE_DEBUG
|
||||
// - OMNITRACE_VERBOSE
|
||||
int _omnitrace_dl_verbose =
|
||||
tim::get_env<bool>("OMNITRACE_DL_DEBUG", false, false)
|
||||
? 100
|
||||
: tim::get_env<int>("OMNITRACE_DL_VERBOSE", get_omnitrace_env(), false);
|
||||
|
||||
// The docs for dlopen suggest that the combination of RTLD_LOCAL + RTLD_DEEPBIND
|
||||
// (when available) helps ensure that the symbols in the instrumentation library
|
||||
// libomnitrace.so will use it's own symbols... not symbols that are potentially
|
||||
// instrumented. However, this only applies to the symbols in libomnitrace.so,
|
||||
// which is NOT self-contained, i.e. symbols in timemory and the libs it links to
|
||||
// (such as libpapi.so) are not protected by the deep-bind option. Additionally,
|
||||
// it should be noted that DynInst does *NOT* add instrumentation by manipulating the
|
||||
// dynamic linker (otherwise it would only be limited to shared libs) -- it manipulates
|
||||
// the instructions in the binary so that a call to a function such as "main" actually
|
||||
// calls "main_dyninst", which executes the instrumentation snippets around the actual
|
||||
// "main" (this is the reason you need the dyninstAPI_RT library).
|
||||
//
|
||||
// UPDATE:
|
||||
// Use of RTLD_DEEPBIND has been removed because it causes the dyninst
|
||||
// ProcControlAPI to segfault within pthread_cond_wait on certain executables.
|
||||
//
|
||||
// Here are the docs on the dlopen options used:
|
||||
//
|
||||
// RTLD_LAZY
|
||||
// Perform lazy binding. Only resolve symbols as the code that references them is
|
||||
// executed. If the symbol is never referenced, then it is never resolved. (Lazy
|
||||
// binding is only performed for function references; references to variables are
|
||||
// always immediately bound when the library is loaded.)
|
||||
//
|
||||
// RTLD_LOCAL
|
||||
// This is the converse of RTLD_GLOBAL, and the default if neither flag is specified.
|
||||
// Symbols defined in this library are not made available to resolve references in
|
||||
// subsequently loaded libraries.
|
||||
//
|
||||
// RTLD_DEEPBIND (since glibc 2.3.4)
|
||||
// Place the lookup scope of the symbols in this library ahead of the global scope.
|
||||
// This means that a self-contained library will use its own symbols in preference to
|
||||
// global symbols with the same name contained in libraries that have already been
|
||||
// loaded. This flag is not specified in POSIX.1-2001.
|
||||
//
|
||||
#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 4
|
||||
auto _omnitrace_dl_dlopen_flags = RTLD_LAZY | RTLD_LOCAL;
|
||||
const char* _omnitrace_dl_dlopen_descr = "RTLD_LAZY | RTLD_LOCAL";
|
||||
#else
|
||||
auto _omnitrace_dl_dlopen_flags = RTLD_LAZY | RTLD_LOCAL;
|
||||
const char* _omnitrace_dl_dlopen_descr = "RTLD_LAZY | RTLD_LOCAL";
|
||||
#endif
|
||||
|
||||
/// This class contains function pointers for omnitrace's instrumentation functions
|
||||
struct OMNITRACE_HIDDEN indirect
|
||||
{
|
||||
explicit OMNITRACE_INLINE indirect(std::string libpath)
|
||||
: m_libpath{ find_path(std::move(libpath)) }
|
||||
{
|
||||
if(_omnitrace_dl_verbose > 0)
|
||||
{
|
||||
fprintf(stderr, "[omnitrace][dl][pid=%i] libomnitrace.so resolved to '%s'\n",
|
||||
process::get_id(), m_libpath.c_str());
|
||||
}
|
||||
tim::set_env("HSA_TOOLS_LIB", m_libpath, 0);
|
||||
open();
|
||||
init();
|
||||
}
|
||||
|
||||
OMNITRACE_INLINE ~indirect() { dlclose(m_libhandle); }
|
||||
|
||||
OMNITRACE_INLINE void open()
|
||||
{
|
||||
if(m_libhandle) return;
|
||||
|
||||
auto* libhandle = dlopen(m_libpath.c_str(), _omnitrace_dl_dlopen_flags);
|
||||
|
||||
if(libhandle)
|
||||
{
|
||||
m_libhandle = libhandle;
|
||||
if(_omnitrace_dl_verbose > 0)
|
||||
{
|
||||
fprintf(stderr, "[omnitrace][dl][pid=%i] dlopen(%s, %s) :: success\n",
|
||||
process::get_id(), m_libpath.c_str(), _omnitrace_dl_dlopen_descr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(_omnitrace_dl_verbose >= 0)
|
||||
{
|
||||
perror("dlopen");
|
||||
fprintf(stderr, "[omnitrace][dl][pid=%i] dlopen(%s, %s) :: %s\n",
|
||||
process::get_id(), m_libpath.c_str(), _omnitrace_dl_dlopen_descr,
|
||||
dlerror());
|
||||
}
|
||||
}
|
||||
|
||||
dlerror(); // Clear any existing error
|
||||
}
|
||||
|
||||
OMNITRACE_INLINE void init()
|
||||
{
|
||||
if(!m_libhandle) open();
|
||||
|
||||
// Initialize all pointers
|
||||
OMNITRACE_DLSYM(omnitrace_init_library_f, m_libhandle, "omnitrace_init_library");
|
||||
OMNITRACE_DLSYM(omnitrace_init_f, m_libhandle, "omnitrace_init");
|
||||
OMNITRACE_DLSYM(omnitrace_finalize_f, m_libhandle, "omnitrace_finalize");
|
||||
OMNITRACE_DLSYM(omnitrace_set_env_f, m_libhandle, "omnitrace_set_env");
|
||||
OMNITRACE_DLSYM(omnitrace_set_mpi_f, m_libhandle, "omnitrace_set_mpi");
|
||||
OMNITRACE_DLSYM(omnitrace_push_trace_f, m_libhandle, "omnitrace_push_trace");
|
||||
OMNITRACE_DLSYM(omnitrace_pop_trace_f, m_libhandle, "omnitrace_pop_trace");
|
||||
}
|
||||
|
||||
static OMNITRACE_INLINE std::string find_path(std::string&& _path)
|
||||
{
|
||||
auto _paths = tim::delimit(
|
||||
TIMEMORY_JOIN(":", tim::get_env<std::string>("OMNITRACE_PATH", ""),
|
||||
tim::get_env<std::string>("LD_LIBRARY_PATH", ""),
|
||||
tim::get_env<std::string>("LIBRARY_PATH", "")),
|
||||
":");
|
||||
|
||||
auto file_exists = [](const std::string& name) {
|
||||
struct stat buffer;
|
||||
return (stat(name.c_str(), &buffer) == 0);
|
||||
};
|
||||
|
||||
for(auto&& itr : _paths)
|
||||
{
|
||||
auto _f = TIMEMORY_JOIN('/', itr, _path);
|
||||
if(file_exists(_f)) return _f;
|
||||
}
|
||||
return _path;
|
||||
}
|
||||
|
||||
public:
|
||||
void (*omnitrace_init_library_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_push_trace_f)(const char*) = nullptr;
|
||||
void (*omnitrace_pop_trace_f)(const char*) = nullptr;
|
||||
|
||||
private:
|
||||
void* m_libhandle = nullptr;
|
||||
std::string m_libpath = {};
|
||||
};
|
||||
|
||||
inline std::unique_ptr<indirect>&
|
||||
get_indirect() OMNITRACE_HIDDEN;
|
||||
|
||||
template <typename FuncT, typename... Args>
|
||||
inline void
|
||||
invoke(const char* _name, FuncT&& _func, Args... _args) OMNITRACE_HIDDEN;
|
||||
} // namespace
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void omnitrace_init_library(void)
|
||||
{
|
||||
invoke(__FUNCTION__, get_indirect()->omnitrace_init_library_f);
|
||||
}
|
||||
|
||||
void omnitrace_init(const char* a, bool b, const char* c)
|
||||
{
|
||||
invoke(__FUNCTION__, get_indirect()->omnitrace_init_f, a, b, c);
|
||||
}
|
||||
|
||||
void omnitrace_finalize(void)
|
||||
{
|
||||
invoke(__FUNCTION__, get_indirect()->omnitrace_finalize_f);
|
||||
}
|
||||
|
||||
void omnitrace_push_trace(const char* name)
|
||||
{
|
||||
invoke(__FUNCTION__, get_indirect()->omnitrace_push_trace_f, name);
|
||||
}
|
||||
|
||||
void omnitrace_pop_trace(const char* name)
|
||||
{
|
||||
invoke(__FUNCTION__, get_indirect()->omnitrace_pop_trace_f, name);
|
||||
}
|
||||
|
||||
void omnitrace_set_env(const char* a, const char* b)
|
||||
{
|
||||
tim::set_env(a, b, 0);
|
||||
invoke(__FUNCTION__, get_indirect()->omnitrace_set_env_f, a, b);
|
||||
}
|
||||
|
||||
void omnitrace_set_mpi(bool a, bool b)
|
||||
{
|
||||
invoke(__FUNCTION__, get_indirect()->omnitrace_set_mpi_f, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
namespace
|
||||
{
|
||||
int
|
||||
get_omnitrace_env()
|
||||
{
|
||||
auto&& _debug = tim::get_env<bool>("OMNITRACE_DEBUG", false, false);
|
||||
return tim::get_env<int>("OMNITRACE_VERBOSE", (_debug) ? 100 : 0, false);
|
||||
}
|
||||
|
||||
std::unique_ptr<indirect>&
|
||||
get_indirect()
|
||||
{
|
||||
static std::unique_ptr<indirect> _v = std::make_unique<indirect>(
|
||||
tim::get_env<std::string>("OMNITRACE_LIBRARY", "libomnitrace.so"));
|
||||
return _v;
|
||||
}
|
||||
|
||||
template <typename FuncT, typename... Args>
|
||||
void
|
||||
invoke(const char* _name, FuncT&& _func, Args... _args)
|
||||
{
|
||||
if(!get_indirect())
|
||||
{
|
||||
// allow -2 verbosity to avoid throwing exception
|
||||
if(_omnitrace_dl_verbose >= -1)
|
||||
throw std::runtime_error(
|
||||
"[omnitrace][dl] nullptr to struct holding dlsym function");
|
||||
return;
|
||||
}
|
||||
|
||||
if(_func)
|
||||
{
|
||||
std::invoke(std::forward<FuncT>(_func), _args...);
|
||||
}
|
||||
else if(_omnitrace_dl_verbose >= 0)
|
||||
{
|
||||
fprintf(stderr, "[omnitrace][dl] %s\n",
|
||||
TIMEMORY_JOIN("", "null function pointer to ", _name, ". Ignoring ",
|
||||
_name, "(", _args..., ")")
|
||||
.c_str());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
@@ -28,11 +28,11 @@
|
||||
#include "library/debug.hpp"
|
||||
#include "library/defines.hpp"
|
||||
#include "library/gpu.hpp"
|
||||
#include "library/ptl.hpp"
|
||||
#include "library/sampling.hpp"
|
||||
#include "library/thread_data.hpp"
|
||||
#include "library/thread_sampler.hpp"
|
||||
#include "library/timemory.hpp"
|
||||
#include "timemory/mpl/type_traits.hpp"
|
||||
|
||||
#include <mutex>
|
||||
#include <string_view>
|
||||
@@ -44,7 +44,11 @@ namespace
|
||||
std::vector<bool>&
|
||||
get_interval_data()
|
||||
{
|
||||
static thread_local auto _v = std::vector<bool>{};
|
||||
static thread_local auto _v = []() {
|
||||
auto _tmp = std::vector<bool>{};
|
||||
_tmp.reserve(max_supported_threads);
|
||||
return _tmp;
|
||||
}();
|
||||
return _v;
|
||||
}
|
||||
|
||||
@@ -86,10 +90,9 @@ is_system_backend()
|
||||
}
|
||||
|
||||
auto&
|
||||
get_instrumentation_bundles()
|
||||
get_instrumentation_bundles(int64_t _tid = threading::get_id())
|
||||
{
|
||||
static thread_local auto& _v =
|
||||
instrumentation_bundles::instances().at(threading::get_id());
|
||||
static thread_local auto& _v = instrumentation_bundles::instances().at(_tid);
|
||||
return _v;
|
||||
}
|
||||
|
||||
@@ -120,10 +123,41 @@ using Phase = critical_trace::Phase;
|
||||
/// \brief the "start" function for an instrumentation region
|
||||
///
|
||||
//======================================================================================//
|
||||
namespace
|
||||
{
|
||||
auto&
|
||||
push_count()
|
||||
{
|
||||
static thread_local uint16_t _v = 0;
|
||||
return _v;
|
||||
}
|
||||
auto&
|
||||
pop_count()
|
||||
{
|
||||
static thread_local uint16_t _v = 0;
|
||||
return _v;
|
||||
}
|
||||
|
||||
struct reentry_guard
|
||||
{
|
||||
reentry_guard(uint16_t& _v)
|
||||
: m_v{ _v }
|
||||
{
|
||||
++m_v;
|
||||
}
|
||||
~reentry_guard() { --m_v; }
|
||||
uint16_t& m_v;
|
||||
|
||||
operator bool() const { return (m_v <= 1); }
|
||||
};
|
||||
} // namespace
|
||||
|
||||
extern "C" void
|
||||
omnitrace_push_trace(const char* name)
|
||||
{
|
||||
reentry_guard _lk{ push_count() };
|
||||
if(!_lk) return;
|
||||
|
||||
// return if not active
|
||||
if(get_state() == State::Finalized) return;
|
||||
|
||||
@@ -135,12 +169,14 @@ omnitrace_push_trace(const char* name)
|
||||
return;
|
||||
}
|
||||
|
||||
OMNITRACE_DEBUG("[%s] %s\n", __FUNCTION__, name);
|
||||
OMNITRACE_DEBUG_F("%s\n", name);
|
||||
|
||||
static auto _sample_rate = std::max<size_t>(get_instrumentation_interval(), 1);
|
||||
static thread_local size_t _sample_idx = 0;
|
||||
auto& _interval = get_interval_data();
|
||||
auto _enabled = (_sample_idx++ % _sample_rate == 0);
|
||||
get_interval_data().emplace_back(_enabled);
|
||||
|
||||
_interval.emplace_back(_enabled);
|
||||
if(_enabled) get_functors().first(name);
|
||||
if(get_use_critical_trace())
|
||||
{
|
||||
@@ -168,9 +204,17 @@ omnitrace_push_trace(const char* name)
|
||||
extern "C" void
|
||||
omnitrace_pop_trace(const char* name)
|
||||
{
|
||||
// the same thread should not be pushing AND popping
|
||||
if(push_count() > 0) return;
|
||||
|
||||
reentry_guard _lk{ pop_count() };
|
||||
// return if reentry
|
||||
if(!_lk) return;
|
||||
|
||||
// only execute when active
|
||||
if(get_state() == State::Active)
|
||||
{
|
||||
OMNITRACE_DEBUG("[%s] %s\n", __FUNCTION__, name);
|
||||
OMNITRACE_DEBUG_F("%s\n", name);
|
||||
auto& _interval_data = get_interval_data();
|
||||
if(!_interval_data.empty())
|
||||
{
|
||||
@@ -382,9 +426,8 @@ omnitrace_init_tooling()
|
||||
!get_use_rocm_smi())
|
||||
{
|
||||
get_state() = State::Finalized;
|
||||
OMNITRACE_DEBUG("[%s] Both perfetto and timemory are disabled. Setting the state "
|
||||
"to finalized\n",
|
||||
__FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("Both perfetto and timemory are disabled. Setting the state "
|
||||
"to finalized\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -487,6 +530,7 @@ omnitrace_init_tooling()
|
||||
};
|
||||
|
||||
static auto _pop_timemory = [](const char* name) {
|
||||
auto _hash = tim::hash::get_hash_id(tim::string_view_t{ name });
|
||||
auto& _data = get_instrumentation_bundles();
|
||||
if(_data.bundles.empty())
|
||||
{
|
||||
@@ -494,10 +538,17 @@ omnitrace_init_tooling()
|
||||
"omnitrace_pop_trace", name);
|
||||
return;
|
||||
}
|
||||
_data.bundles.back()->stop();
|
||||
_data.allocator.destroy(_data.bundles.back());
|
||||
_data.allocator.deallocate(_data.bundles.back(), 1);
|
||||
_data.bundles.pop_back();
|
||||
for(size_t i = _data.bundles.size(); i > 0; --i)
|
||||
{
|
||||
auto*& _v = _data.bundles.at(i - 1);
|
||||
if(_v->get_hash() == _hash)
|
||||
{
|
||||
_v->stop();
|
||||
_data.allocator.destroy(_v);
|
||||
_data.allocator.deallocate(_v, 1);
|
||||
_data.bundles.erase(_data.bundles.begin() + (i - 1));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static auto _pop_perfetto = [](const char*) {
|
||||
@@ -597,11 +648,32 @@ omnitrace_finalize(void)
|
||||
// return if not active
|
||||
if(get_state() != State::Active)
|
||||
{
|
||||
OMNITRACE_DEBUG_F("State = %s. Finalization skipped\n",
|
||||
std::to_string(get_state()).c_str());
|
||||
OMNITRACE_BASIC_DEBUG_F("State = %s. Finalization skipped\n",
|
||||
std::to_string(get_state()).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
get_state() = State::Finalized;
|
||||
|
||||
get_functors().first = [](const char*) {};
|
||||
get_functors().second = [](const char*) {};
|
||||
|
||||
if(get_use_timemory())
|
||||
{
|
||||
auto& _data = get_instrumentation_bundles();
|
||||
if(!_data.bundles.empty())
|
||||
{
|
||||
for(size_t i = _data.bundles.size(); i > 0; --i)
|
||||
{
|
||||
auto*& _v = _data.bundles.at(i - 1);
|
||||
_v->stop();
|
||||
_data.allocator.destroy(_v);
|
||||
_data.allocator.deallocate(_v, 1);
|
||||
}
|
||||
_data.bundles.clear();
|
||||
}
|
||||
}
|
||||
|
||||
pthread_gotcha::enable_sampling_on_child_threads() = false;
|
||||
|
||||
auto _debug_init = get_debug_finalize();
|
||||
@@ -611,24 +683,22 @@ omnitrace_finalize(void)
|
||||
if(_debug_init) config::set_setting_value("OMNITRACE_DEBUG", _debug_value);
|
||||
} };
|
||||
|
||||
OMNITRACE_DEBUG("[%s]\n", __FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("\n");
|
||||
|
||||
auto& _thread_bundle = thread_data<omnitrace_thread_bundle_t>::instance();
|
||||
if(_thread_bundle) _thread_bundle->stop();
|
||||
|
||||
if(dmp::rank() == 0 && get_verbose() >= 0) fprintf(stderr, "\n");
|
||||
if(get_verbose_env() > 0) config::print_settings();
|
||||
|
||||
get_state() = State::Finalized;
|
||||
if(get_verbose() > 0 || get_debug()) config::print_settings();
|
||||
|
||||
if(get_use_sampling())
|
||||
{
|
||||
OMNITRACE_DEBUG("[%s] Shutting down sampling...\n", __FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("Shutting down sampling...\n");
|
||||
sampling::shutdown();
|
||||
sampling::block_signals();
|
||||
}
|
||||
|
||||
OMNITRACE_DEBUG("[%s] Stopping gotcha bundle...\n", __FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("Stopping gotcha bundle...\n");
|
||||
// stop the gotcha bundle
|
||||
if(get_gotcha_bundle())
|
||||
{
|
||||
@@ -639,13 +709,13 @@ omnitrace_finalize(void)
|
||||
pthread_gotcha::shutdown();
|
||||
thread_sampler::shutdown();
|
||||
|
||||
OMNITRACE_DEBUG("[%s] Shutting down roctracer...\n", __FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("Shutting down roctracer...\n");
|
||||
// ensure that threads running roctracer callbacks shutdown
|
||||
comp::roctracer::shutdown();
|
||||
|
||||
if(dmp::rank() == 0) fprintf(stderr, "\n");
|
||||
|
||||
OMNITRACE_DEBUG("[%s] Stopping main bundle...\n", __FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("Stopping main bundle...\n");
|
||||
// stop the main bundle and report the high-level metrics
|
||||
if(get_main_bundle())
|
||||
{
|
||||
@@ -659,18 +729,18 @@ omnitrace_finalize(void)
|
||||
|
||||
int _threadpool_verbose = (get_debug()) ? 4 : -1;
|
||||
tasking::get_roctracer_thread_pool().set_verbose(_threadpool_verbose);
|
||||
tasking::get_critical_trace_thread_pool().set_verbose(_threadpool_verbose);
|
||||
if(get_use_critical_trace())
|
||||
tasking::get_critical_trace_thread_pool().set_verbose(_threadpool_verbose);
|
||||
|
||||
// join extra thread(s) used by roctracer
|
||||
OMNITRACE_DEBUG("[%s] waiting for all roctracer tasks to complete...\n",
|
||||
__FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("waiting for all roctracer tasks to complete...\n");
|
||||
tasking::get_roctracer_task_group().join();
|
||||
|
||||
// print out thread-data if they are not still running
|
||||
// if they are still running (e.g. thread-pool still alive), the
|
||||
// thread-specific data will be wrong if try to stop them from
|
||||
// the main thread.
|
||||
OMNITRACE_DEBUG("[%s] Destroying thread bundle data...\n", __FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("Destroying thread bundle data...\n");
|
||||
for(auto& itr : thread_data<omnitrace_thread_bundle_t>::instances())
|
||||
{
|
||||
if(itr && itr->get<comp::wall_clock>() &&
|
||||
@@ -684,8 +754,7 @@ omnitrace_finalize(void)
|
||||
}
|
||||
|
||||
// ensure that all the MT instances are flushed
|
||||
OMNITRACE_DEBUG("[%s] Stopping and destroying instrumentation bundles...\n",
|
||||
__FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("Stopping and destroying instrumentation bundles...\n");
|
||||
for(auto& itr : instrumentation_bundles::instances())
|
||||
{
|
||||
while(!itr.bundles.empty())
|
||||
@@ -701,8 +770,7 @@ omnitrace_finalize(void)
|
||||
// ensure that all the MT instances are flushed
|
||||
if(get_use_sampling())
|
||||
{
|
||||
OMNITRACE_DEBUG("[%s] Post-processing the sampling backtraces...\n",
|
||||
__FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("Post-processing the sampling backtraces...\n");
|
||||
for(size_t i = 0; i < max_supported_threads; ++i)
|
||||
{
|
||||
sampling::backtrace::post_process(i);
|
||||
@@ -712,7 +780,7 @@ omnitrace_finalize(void)
|
||||
|
||||
if(get_use_critical_trace() || (get_use_rocm_smi() && get_use_roctracer()))
|
||||
{
|
||||
OMNITRACE_DEBUG("[%s] Generating the critical trace...\n", __FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("Generating the critical trace...\n");
|
||||
// increase the thread-pool size
|
||||
tasking::get_critical_trace_thread_pool().initialize_threadpool(
|
||||
get_critical_trace_num_threads());
|
||||
@@ -739,18 +807,12 @@ omnitrace_finalize(void)
|
||||
|
||||
if(get_use_critical_trace())
|
||||
{
|
||||
OMNITRACE_DEBUG("[%s] Generating the critical trace...\n", __FUNCTION__);
|
||||
// increase the thread-pool size
|
||||
tasking::get_critical_trace_thread_pool().initialize_threadpool(
|
||||
get_critical_trace_num_threads());
|
||||
|
||||
// make sure outstanding hash tasks completed before compute
|
||||
OMNITRACE_PRINT("[%s] waiting for all critical trace tasks to complete...\n",
|
||||
__FUNCTION__);
|
||||
OMNITRACE_PRINT_F("waiting for all critical trace tasks to complete...\n");
|
||||
tasking::get_critical_trace_task_group().join();
|
||||
|
||||
// launch compute task
|
||||
OMNITRACE_PRINT("[%s] launching critical trace compute task...\n", __FUNCTION__);
|
||||
OMNITRACE_PRINT_F("launching critical trace compute task...\n");
|
||||
critical_trace::compute();
|
||||
}
|
||||
|
||||
@@ -767,11 +829,10 @@ omnitrace_finalize(void)
|
||||
perfetto::TrackEvent::Flush();
|
||||
|
||||
auto& tracing_session = get_trace_session();
|
||||
OMNITRACE_DEBUG("[%s] Stopping the blocking perfetto trace sessions...\n",
|
||||
__FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("Stopping the blocking perfetto trace sessions...\n");
|
||||
tracing_session->StopBlocking();
|
||||
|
||||
OMNITRACE_DEBUG("[%s] Getting the trace data...\n", __FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("Getting the trace data...\n");
|
||||
std::vector<char> trace_data{ tracing_session->ReadTraceBlocking() };
|
||||
|
||||
if(trace_data.empty())
|
||||
@@ -808,18 +869,31 @@ omnitrace_finalize(void)
|
||||
|
||||
// these should be destroyed before timemory is finalized, especially the
|
||||
// roctracer thread-pool
|
||||
OMNITRACE_DEBUG("[%s] Destroying the thread pools...\n", __FUNCTION__);
|
||||
tasking::get_roctracer_thread_pool().destroy_threadpool();
|
||||
tasking::get_critical_trace_thread_pool().destroy_threadpool();
|
||||
OMNITRACE_DEBUG_F("Destroying the roctracer thread pool...\n");
|
||||
{
|
||||
std::unique_lock<std::mutex> _lk{ tasking::get_roctracer_mutex() };
|
||||
tasking::get_roctracer_task_group().join();
|
||||
tasking::get_roctracer_task_group().clear();
|
||||
tasking::get_roctracer_task_group().set_pool(nullptr);
|
||||
tasking::get_roctracer_thread_pool().destroy_threadpool();
|
||||
}
|
||||
|
||||
if(get_use_sampling())
|
||||
static_cast<tim::tsettings<bool>*>(
|
||||
tim::settings::instance()->find("OMNITRACE_DEBUG")->second.get())
|
||||
->set(false);
|
||||
OMNITRACE_DEBUG_F("Destroying the critical trace thread pool...\n");
|
||||
{
|
||||
std::unique_lock<std::mutex> _lk{ tasking::get_critical_trace_mutex() };
|
||||
tasking::get_critical_trace_task_group().join();
|
||||
tasking::get_critical_trace_task_group().clear();
|
||||
tasking::get_critical_trace_task_group().set_pool(nullptr);
|
||||
tasking::get_critical_trace_thread_pool().destroy_threadpool();
|
||||
}
|
||||
|
||||
OMNITRACE_DEBUG("[%s] Finalizing timemory...\n", __FUNCTION__);
|
||||
OMNITRACE_DEBUG_F("Finalizing timemory...\n");
|
||||
tim::timemory_finalize();
|
||||
OMNITRACE_DEBUG("[%s] Finalizing timemory... Done\n", __FUNCTION__);
|
||||
|
||||
OMNITRACE_DEBUG_F("Disabling signal handling...\n");
|
||||
tim::disable_signal_detection();
|
||||
|
||||
OMNITRACE_DEBUG_F("Finalized\n");
|
||||
|
||||
if(_perfetto_output_error)
|
||||
{
|
||||
|
||||
@@ -231,8 +231,16 @@ backtrace::get_thread_cpu_timestamp() const
|
||||
void
|
||||
backtrace::sample(int signum)
|
||||
{
|
||||
static bool _debug = tim::get_env<bool>("OMNITRACE_DEBUG_SAMPLING", get_debug());
|
||||
if(_debug)
|
||||
if(get_state() != State::Active)
|
||||
{
|
||||
OMNITRACE_CONDITIONAL_PRINT(
|
||||
get_debug_sampling(),
|
||||
"request to sample (signal %i) ignored because omnitrace is not active\n",
|
||||
signum);
|
||||
return;
|
||||
}
|
||||
|
||||
if(get_debug_sampling())
|
||||
{
|
||||
static auto _timestamp_str = [](const auto& _tp) {
|
||||
char _repr[64];
|
||||
@@ -269,7 +277,7 @@ backtrace::sample(int signum)
|
||||
if(strlen(*itr) == 0) break;
|
||||
}
|
||||
std::reverse(m_data.begin(), itr);
|
||||
if(!get_debug())
|
||||
if(!get_debug_sampling())
|
||||
{
|
||||
bool _ignore = false;
|
||||
for(auto& itr : m_data)
|
||||
@@ -317,6 +325,7 @@ backtrace::configure(bool _setup, int64_t _tid)
|
||||
|
||||
if(_setup && !_sampler && !_is_running)
|
||||
{
|
||||
(void) get_debug_sampling(); // make sure query in sampler does not allocate
|
||||
assert(_tid == threading::get_id());
|
||||
sampling::block_signals(*_signal_types);
|
||||
if constexpr(tim::trait::is_available<hw_counters>::value)
|
||||
@@ -424,7 +433,7 @@ backtrace::post_process(int64_t _tid)
|
||||
auto _use_label = [](const std::string& _lbl, bool _check_internal) -> short {
|
||||
// debugging feature
|
||||
static bool _keep_internal =
|
||||
tim::get_env<bool>("OMNITRACE_SAMPLING_KEEP_INTERNAL", get_debug());
|
||||
tim::get_env<bool>("OMNITRACE_SAMPLING_KEEP_INTERNAL", get_debug_sampling());
|
||||
const auto _npos = std::string::npos;
|
||||
if(_keep_internal) return 1;
|
||||
if(_lbl.find("omnitrace_init_tooling") != _npos) return -1;
|
||||
@@ -450,8 +459,8 @@ backtrace::post_process(int64_t _tid)
|
||||
// "_dyninst", i.e. "main" will show up as "main_dyninst" in the backtrace.
|
||||
auto _patch_label = [](std::string _lbl) -> std::string {
|
||||
// debugging feature
|
||||
static bool _keep_suffix =
|
||||
tim::get_env<bool>("OMNITRACE_SAMPLING_KEEP_DYNINST_SUFFIX", get_debug());
|
||||
static bool _keep_suffix = tim::get_env<bool>(
|
||||
"OMNITRACE_SAMPLING_KEEP_DYNINST_SUFFIX", get_debug_sampling());
|
||||
if(_keep_suffix) return _lbl;
|
||||
const std::string _dyninst{ "_dyninst" };
|
||||
auto _pos = _lbl.find(_dyninst);
|
||||
@@ -570,7 +579,7 @@ backtrace::post_process(int64_t _tid)
|
||||
if(_data.empty()) return;
|
||||
|
||||
OMNITRACE_CONDITIONAL_PRINT(
|
||||
get_verbose() >= 0 || get_debug(),
|
||||
get_verbose() >= 0 || get_debug_sampling(),
|
||||
"Post-processing %zu sampling entries for thread %lu...\n", _data.size(), _tid);
|
||||
|
||||
std::sort(_data.begin(), _data.end(),
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
#include "library/components/omnitrace.hpp"
|
||||
#include "library/config.hpp"
|
||||
#include "library/debug.hpp"
|
||||
#include "timemory/backends/process.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <timemory/backends/mpi.hpp>
|
||||
#include <timemory/backends/process.hpp>
|
||||
|
||||
namespace omnitrace
|
||||
{
|
||||
|
||||
+13
-4
@@ -27,10 +27,11 @@
|
||||
#include "library/debug.hpp"
|
||||
#include "library/sampling.hpp"
|
||||
|
||||
#include <ostream>
|
||||
#include <timemory/backends/threading.hpp>
|
||||
#include <timemory/sampling/allocator.hpp>
|
||||
#include <timemory/utility/types.hpp>
|
||||
|
||||
#include <ostream>
|
||||
#include <pthread.h>
|
||||
|
||||
namespace omnitrace
|
||||
@@ -85,8 +86,9 @@ stop_bundle(bundle_t& _bundle, int64_t _tid)
|
||||
} // namespace
|
||||
|
||||
pthread_gotcha::wrapper::wrapper(routine_t _routine, void* _arg, bool _enable_sampling,
|
||||
promise_t* _p)
|
||||
int64_t _parent, promise_t* _p)
|
||||
: m_enable_sampling{ _enable_sampling }
|
||||
, m_parent_tid{ _parent }
|
||||
, m_routine{ _routine }
|
||||
, m_arg{ _arg }
|
||||
, m_promise{ _p }
|
||||
@@ -117,6 +119,8 @@ pthread_gotcha::wrapper::operator()() const
|
||||
}
|
||||
} };
|
||||
|
||||
if(_active) get_cpu_cid_stack(threading::get_id(), m_parent_tid);
|
||||
|
||||
if(m_enable_sampling && _enable_sampling && _active)
|
||||
{
|
||||
_tid = threading::get_id();
|
||||
@@ -197,11 +201,16 @@ pthread_gotcha::operator()(pthread_t* thread, const pthread_attr_t* attr,
|
||||
{
|
||||
bundle_t _bundle{ "pthread_create" };
|
||||
auto _enable_sampling = enable_sampling_on_child_threads();
|
||||
auto _active = (get_state() == omnitrace::State::Active);
|
||||
int64_t _tid = (_active) ? threading::get_id() : 0;
|
||||
|
||||
// ensure that cpu cid stack exists on the parent thread if active
|
||||
if(_active) get_cpu_cid_stack();
|
||||
|
||||
if(!get_use_sampling() || !_enable_sampling)
|
||||
{
|
||||
// if(!get_use_sampling()) start_bundle(_bundle);
|
||||
auto* _obj = new wrapper(start_routine, arg, _enable_sampling, nullptr);
|
||||
auto* _obj = new wrapper(start_routine, arg, _enable_sampling, _tid, nullptr);
|
||||
// create the thread
|
||||
auto _ret =
|
||||
pthread_create(thread, attr, &wrapper::wrap, static_cast<void*>(_obj));
|
||||
@@ -219,7 +228,7 @@ pthread_gotcha::operator()(pthread_t* thread, const pthread_attr_t* attr,
|
||||
// promise set by thread when signal handler is configured
|
||||
auto _promise = std::promise<void>{};
|
||||
auto _fut = _promise.get_future();
|
||||
auto* _wrap = new wrapper(start_routine, arg, _enable_sampling, &_promise);
|
||||
auto* _wrap = new wrapper(start_routine, arg, _enable_sampling, _tid, &_promise);
|
||||
|
||||
// create the thread
|
||||
auto _ret = pthread_create(thread, attr, &wrapper::wrap, static_cast<void*>(_wrap));
|
||||
|
||||
@@ -215,8 +215,8 @@ TIMEMORY_INSTANTIATE_EXTERN_COMPONENT(roctracer_data, true, double)
|
||||
extern "C"
|
||||
{
|
||||
bool OnLoad(HsaApiTable* table, uint64_t runtime_version, uint64_t failed_tool_count,
|
||||
const char* const* failed_tool_names) TIMEMORY_VISIBILITY("default");
|
||||
void OnUnload() TIMEMORY_VISIBILITY("default");
|
||||
const char* const* failed_tool_names) OMNITRACE_VISIBILITY("default");
|
||||
void OnUnload() OMNITRACE_VISIBILITY("default");
|
||||
|
||||
bool OnLoad(HsaApiTable* table, uint64_t runtime_version, uint64_t failed_tool_count,
|
||||
const char* const* failed_tool_names)
|
||||
|
||||
+11
-9
@@ -185,14 +185,15 @@ hsa_api_callback(uint32_t domain, uint32_t cid, const void* callback_data, void*
|
||||
std::unique_lock<std::mutex> _lk{ tasking::get_roctracer_mutex() };
|
||||
auto _begin_ns = begin_timestamp;
|
||||
auto _end_ns = end_timestamp;
|
||||
tasking::get_roctracer_task_group().exec(
|
||||
[_name, _begin_ns, _end_ns]() {
|
||||
roctracer_hsa_bundle_t _bundle{ _name, _scope };
|
||||
_bundle.start()
|
||||
.store(std::plus<double>{},
|
||||
static_cast<double>(_end_ns - _begin_ns))
|
||||
.stop();
|
||||
});
|
||||
if(tasking::get_roctracer_task_group().pool())
|
||||
tasking::get_roctracer_task_group().exec(
|
||||
[_name, _begin_ns, _end_ns]() {
|
||||
roctracer_hsa_bundle_t _bundle{ _name, _scope };
|
||||
_bundle.start()
|
||||
.store(std::plus<double>{},
|
||||
static_cast<double>(_end_ns - _begin_ns))
|
||||
.stop();
|
||||
});
|
||||
}
|
||||
// timemory is disabled in this callback because collecting data in this
|
||||
// thread causes strange segmentation faults
|
||||
@@ -251,7 +252,8 @@ hsa_activity_callback(uint32_t op, activity_record_t* record, void* arg)
|
||||
};
|
||||
|
||||
std::unique_lock<std::mutex> _lk{ tasking::get_roctracer_mutex() };
|
||||
tasking::get_roctracer_task_group().exec(_func);
|
||||
if(tasking::get_roctracer_task_group().pool())
|
||||
tasking::get_roctracer_task_group().exec(_func);
|
||||
|
||||
// timemory is disabled in this callback because collecting data in this thread
|
||||
// causes strange segmentation faults
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
// SOFTWARE.
|
||||
|
||||
#include "library/config.hpp"
|
||||
#include "library/api.hpp"
|
||||
#include "library/debug.hpp"
|
||||
#include "library/defines.hpp"
|
||||
#include "library/thread_data.hpp"
|
||||
@@ -29,16 +30,21 @@
|
||||
#include <timemory/backends/mpi.hpp>
|
||||
#include <timemory/backends/process.hpp>
|
||||
#include <timemory/environment.hpp>
|
||||
#include <timemory/sampling/allocator.hpp>
|
||||
#include <timemory/settings.hpp>
|
||||
#include <timemory/settings/types.hpp>
|
||||
#include <timemory/utility/argparse.hpp>
|
||||
#include <timemory/utility/declaration.hpp>
|
||||
#include <timemory/utility/signals.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <csignal>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <numeric>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace omnitrace
|
||||
{
|
||||
@@ -69,7 +75,8 @@ get_setting_name(std::string _v)
|
||||
{ \
|
||||
auto _ret = _config->insert<TYPE, TYPE>( \
|
||||
ENV_NAME, get_setting_name(ENV_NAME), DESCRIPTION, INITIAL_VALUE, \
|
||||
std::set<std::string>{ "custom", "omnitrace", __VA_ARGS__ }); \
|
||||
std::set<std::string>{ "custom", "omnitrace", "omnitrace-library", \
|
||||
__VA_ARGS__ }); \
|
||||
if(!_ret.second) \
|
||||
OMNITRACE_PRINT("Warning! Duplicate setting: %s / %s\n", \
|
||||
get_setting_name(ENV_NAME).c_str(), ENV_NAME); \
|
||||
@@ -261,6 +268,24 @@ configure_settings()
|
||||
_config->get_memory_units() = "MB";
|
||||
_config->get_papi_events() = "PAPI_TOT_CYC, PAPI_TOT_INS";
|
||||
|
||||
// settings native to timemory but critically and/or extensively used by omnitrace
|
||||
auto _add_omnitrace_category = [](auto itr) {
|
||||
if(itr != _config->end())
|
||||
{
|
||||
auto _categories = itr->second->get_categories();
|
||||
_categories.emplace("omnitrace");
|
||||
_categories.emplace("omnitrace-library");
|
||||
itr->second->set_categories(_categories);
|
||||
}
|
||||
};
|
||||
|
||||
_add_omnitrace_category(_config->find("OMNITRACE_CONFIG_FILE"));
|
||||
_add_omnitrace_category(_config->find("OMNITRACE_DEBUG"));
|
||||
_add_omnitrace_category(_config->find("OMNITRACE_VERBOSE"));
|
||||
_add_omnitrace_category(_config->find("OMNITRACE_TIME_OUTPUT"));
|
||||
_add_omnitrace_category(_config->find("OMNITRACE_OUTPUT_PREFIX"));
|
||||
_add_omnitrace_category(_config->find("OMNITRACE_OUTPUT_PATH"));
|
||||
|
||||
#if defined(TIMEMORY_USE_PAPI)
|
||||
int _paranoid = 2;
|
||||
{
|
||||
@@ -287,6 +312,10 @@ configure_settings()
|
||||
tim::trait::runtime_enabled<comp::cpu_roofline_sp_flops>::set(false);
|
||||
_config->get_papi_events() = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
_add_omnitrace_category(_config->find("OMNITRACE_PAPI_EVENTS"));
|
||||
}
|
||||
#else
|
||||
_config->get_papi_quiet() = true;
|
||||
#endif
|
||||
@@ -330,6 +359,30 @@ configure_settings()
|
||||
if(tim::mpi::is_initialized()) settings::default_process_suffix() = tim::mpi::rank();
|
||||
#endif
|
||||
OMNITRACE_CONDITIONAL_BASIC_PRINT(get_verbose_env() > 0, "configuration complete\n");
|
||||
|
||||
if(_config->get_enable_signal_handler())
|
||||
{
|
||||
using signal_settings = tim::signal_settings;
|
||||
using sys_signal = tim::sys_signal;
|
||||
tim::disable_signal_detection();
|
||||
auto _exit_action = [](int nsig) {
|
||||
tim::sampling::block_signals({ SIGPROF, SIGALRM },
|
||||
tim::sampling::sigmask_scope::process);
|
||||
OMNITRACE_BASIC_PRINT(
|
||||
"Finalizing afer signal %i :: %s\n", nsig,
|
||||
signal_settings::str(static_cast<sys_signal>(nsig)).c_str());
|
||||
if(get_state() == State::Active) omnitrace_finalize();
|
||||
kill(process::get_id(), nsig);
|
||||
};
|
||||
signal_settings::set_exit_action(_exit_action);
|
||||
tim::set_env("SIGNAL_ENABLE_INTERRUPT", "1", 0);
|
||||
signal_settings::check_environment();
|
||||
auto default_signals = signal_settings::get_default();
|
||||
for(const auto& itr : default_signals)
|
||||
signal_settings::enable(itr);
|
||||
auto enabled_signals = signal_settings::get_enabled();
|
||||
tim::enable_signal_detection(enabled_signals);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -575,6 +628,13 @@ get_debug()
|
||||
return static_cast<tim::tsettings<bool>&>(*_v->second).get();
|
||||
}
|
||||
|
||||
bool
|
||||
get_debug_sampling()
|
||||
{
|
||||
static bool _v = tim::get_env<bool>("OMNITRACE_DEBUG_SAMPLING", get_debug_env());
|
||||
return (_v || get_debug());
|
||||
}
|
||||
|
||||
int
|
||||
get_verbose_env()
|
||||
{
|
||||
@@ -896,19 +956,24 @@ get_cpu_cid()
|
||||
}
|
||||
|
||||
std::unique_ptr<std::vector<uint64_t>>&
|
||||
get_cpu_cid_stack(int64_t _tid)
|
||||
get_cpu_cid_stack(int64_t _tid, int64_t _parent)
|
||||
{
|
||||
struct omnitrace_cpu_cid_stack
|
||||
{};
|
||||
using thread_data_t = thread_data<std::vector<uint64_t>, omnitrace_cpu_cid_stack>;
|
||||
static auto& _v = thread_data_t::instances();
|
||||
static thread_local auto _v_check = [_tid]() {
|
||||
thread_data_t::construct((_tid > 0) ? *thread_data_t::instances().at(0)
|
||||
: std::vector<uint64_t>{});
|
||||
static auto& _v = thread_data_t::instances();
|
||||
static thread_local auto _v_copy = [_tid, _parent]() {
|
||||
auto _parent_tid = _parent;
|
||||
// if tid != parent and there is not a valid pointer for the provided parent
|
||||
// thread id set it to zero since that will always be valid
|
||||
if(_tid != _parent_tid && !_v.at(_parent_tid)) _parent_tid = 0;
|
||||
// copy over the thread ids from the parent if tid != parent
|
||||
thread_data_t::construct((_tid != _parent_tid) ? *(_v.at(_parent_tid))
|
||||
: std::vector<uint64_t>{});
|
||||
return true;
|
||||
}();
|
||||
return _v.at(_tid);
|
||||
(void) _v_check;
|
||||
(void) _v_copy;
|
||||
}
|
||||
|
||||
namespace
|
||||
|
||||
@@ -508,10 +508,9 @@ get(int64_t _tid)
|
||||
void
|
||||
add_hash_id(const hash_ids& _labels)
|
||||
{
|
||||
std::unique_lock<std::mutex> _lk{ tasking::get_critical_trace_mutex(),
|
||||
std::defer_lock };
|
||||
if(!_lk.owns_lock()) _lk.lock();
|
||||
tasking::get_critical_trace_task_group().run([_labels]() {
|
||||
std::unique_lock<std::mutex> _lk{ tasking::get_critical_trace_mutex() };
|
||||
if(!tasking::get_critical_trace_task_group().pool()) return;
|
||||
tasking::get_critical_trace_task_group().exec([_labels]() {
|
||||
static std::mutex _mtx{};
|
||||
_mtx.lock();
|
||||
for(auto itr : _labels)
|
||||
@@ -539,9 +538,8 @@ void
|
||||
update(int64_t _tid)
|
||||
{
|
||||
if(!get_use_critical_trace() && !get_use_rocm_smi()) return;
|
||||
std::unique_lock<std::mutex> _lk{ tasking::get_critical_trace_mutex(),
|
||||
std::defer_lock };
|
||||
if(!_lk.owns_lock()) _lk.lock();
|
||||
std::unique_lock<std::mutex> _lk{ tasking::get_critical_trace_mutex() };
|
||||
if(!tasking::get_critical_trace_task_group().pool()) return;
|
||||
call_chain _data{};
|
||||
std::swap(_data, *critical_trace::get(_tid));
|
||||
tasking::get_critical_trace_task_group().exec(update_critical_path, _data, _tid);
|
||||
@@ -551,6 +549,8 @@ void
|
||||
compute(int64_t _tid)
|
||||
{
|
||||
update(_tid);
|
||||
std::unique_lock<std::mutex> _lk{ tasking::get_critical_trace_mutex() };
|
||||
if(!tasking::get_critical_trace_task_group().pool()) return;
|
||||
tasking::get_critical_trace_task_group().exec(compute_critical_trace);
|
||||
}
|
||||
|
||||
@@ -824,8 +824,10 @@ get_entries(int64_t _ts, const std::function<bool(const entry&)>& _eval)
|
||||
}
|
||||
*_targ = _v;
|
||||
};
|
||||
std::unique_lock<std::mutex> _lk{ tasking::get_critical_trace_mutex() };
|
||||
size_t _n = 0;
|
||||
std::vector<std::pair<std::string, entry>> _v{};
|
||||
if(!tasking::get_critical_trace_task_group().pool()) return _v;
|
||||
tasking::get_critical_trace_task_group().exec(_func, &_v, &_n);
|
||||
tasking::get_critical_trace_task_group().join();
|
||||
OMNITRACE_DEBUG("critical_trace::%s :: found %zu out of %zu entries at %li...\n",
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
# if !defined(TIMEMORY_USE_HIP)
|
||||
# define TIMEMORY_USE_HIP 1
|
||||
# endif
|
||||
# include "timemory/components/hip/backends.hpp"
|
||||
# include <timemory/components/hip/backends.hpp>
|
||||
#endif
|
||||
|
||||
namespace omnitrace
|
||||
|
||||
Reference in New Issue
Block a user