Stability improvements (#26)
* omnitrace verbprintf and errprintf * avail categories fix * omnitrace-dl namespace * OMNITRACE_CI macro / OMNITRACE_BUILD_CI option - always enables asserts * Roctracer improvements - Reworked roctracer significantly - Added categories to settings - create_cpu_cid_entry - handle clock_skew in roctracer - fixed roctracer activity names - hip_api_callback is "host" - perfetto::Flow for GPU * timemory submodule update * Tweak to redirect * Improved recursive guards - functors component - created "_hidden" variants of instrumentation funcs - omnitrace_* calls omnitrace_*_hidden - omnitrace-dl calls non-hidden - omnitrace-dl now strongly protects against recursion - omnitrace-dl now is standalone w.r.t. headers * Stability fixes - OMNITRACE_DEBUG_PUSH env variable - fix to HSA_TOOLS_LIB in dl.cpp - Fixed SFINAE warning in mpi_gotcha - Handle 64, _l, _r extensions in whole function names * cmake formatting * Fix for last commit + push/pop count info - don't instrument rocr::core::Signal::WaitAny - don't instrument rocr::core::Runtime::AsyncEventsLoop - fixed main not being popped in runtime instrument - updated interval data reserve - copy hash-ids and aliases onto main thread - warn about unclosed regions - removed guards in libomnitrace - added error checks for incorrect push_count vs. pop_count - fixed missing pop_timemory in last commit * Finalization methodology updates - added some more rocr:: functions to whole function names * Add event_base_loop to whole functions * Update VERSION to 0.1.0
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
145a6ae06f
Коммит
0d5c557552
+170
-54
@@ -22,40 +22,37 @@
|
||||
// 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 <cstdlib>
|
||||
#include <cstring>
|
||||
#include <dlfcn.h>
|
||||
#include <functional>
|
||||
#include <gnu/libc-version.h>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define OMNITRACE_VISIBLE __attribute__((visibility("default")))
|
||||
#define OMNITRACE_HIDDEN __attribute__((visibility("internal")))
|
||||
#define OMNITRACE_INLINE __attribute__((__always_inline__))
|
||||
#define OMNITRACE_FOLD_EXPRESSION(...) ((__VA_ARGS__), ...)
|
||||
#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()); \
|
||||
fprintf(stderr, "[omnitrace][dl][pid=%i]> %s :: %s\n", getpid(), FUNCNAME, \
|
||||
dlerror()); \
|
||||
} \
|
||||
}
|
||||
|
||||
namespace process = tim::process;
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
//
|
||||
// omnitrace symbols
|
||||
@@ -75,20 +72,51 @@ extern "C"
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
inline namespace omnitrace
|
||||
{
|
||||
inline namespace dl
|
||||
{
|
||||
namespace
|
||||
{
|
||||
inline int
|
||||
get_omnitrace_env();
|
||||
|
||||
bool
|
||||
get_env(const char* env_id, bool _default);
|
||||
|
||||
std::string
|
||||
get_env(const char* env_id, const char* _default);
|
||||
|
||||
int
|
||||
get_env(const char* env_id, int _default);
|
||||
|
||||
template <typename DelimT, typename... Args>
|
||||
auto
|
||||
join(DelimT&& _delim, Args&&... _args)
|
||||
{
|
||||
std::stringstream _ss{};
|
||||
OMNITRACE_FOLD_EXPRESSION(_ss << _delim << _args);
|
||||
if constexpr(std::is_same<DelimT, char>::value)
|
||||
{
|
||||
return _ss.str().substr(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _ss.str().substr(std::string{ _delim }.length());
|
||||
}
|
||||
}
|
||||
// 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);
|
||||
int _omnitrace_dl_verbose = get_env("OMNITRACE_DL_DEBUG", false)
|
||||
? 100
|
||||
: get_env("OMNITRACE_DL_VERBOSE", get_omnitrace_env());
|
||||
|
||||
template <typename ContainerT = std::vector<std::string>>
|
||||
inline ContainerT
|
||||
delimit(const std::string& line, const char* delimiters = "\"',;: ");
|
||||
|
||||
// The docs for dlopen suggest that the combination of RTLD_LOCAL + RTLD_DEEPBIND
|
||||
// (when available) helps ensure that the symbols in the instrumentation library
|
||||
@@ -142,9 +170,12 @@ struct OMNITRACE_HIDDEN indirect
|
||||
if(_omnitrace_dl_verbose > 0)
|
||||
{
|
||||
fprintf(stderr, "[omnitrace][dl][pid=%i] libomnitrace.so resolved to '%s'\n",
|
||||
process::get_id(), m_libpath.c_str());
|
||||
getpid(), m_libpath.c_str());
|
||||
}
|
||||
tim::set_env("HSA_TOOLS_LIB", m_libpath, 0);
|
||||
auto _omni_hsa_lib = m_libpath;
|
||||
const char* _hsa_lib = getenv("HSA_TOOLS_LIB");
|
||||
if(_hsa_lib) _omni_hsa_lib.append(":").append(_hsa_lib);
|
||||
setenv("HSA_TOOLS_LIB", _omni_hsa_lib.c_str(), 1);
|
||||
open();
|
||||
init();
|
||||
}
|
||||
@@ -163,7 +194,7 @@ struct OMNITRACE_HIDDEN indirect
|
||||
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);
|
||||
getpid(), m_libpath.c_str(), _omnitrace_dl_dlopen_descr);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -172,7 +203,7 @@ struct OMNITRACE_HIDDEN indirect
|
||||
{
|
||||
perror("dlopen");
|
||||
fprintf(stderr, "[omnitrace][dl][pid=%i] dlopen(%s, %s) :: %s\n",
|
||||
process::get_id(), m_libpath.c_str(), _omnitrace_dl_dlopen_descr,
|
||||
getpid(), m_libpath.c_str(), _omnitrace_dl_dlopen_descr,
|
||||
dlerror());
|
||||
}
|
||||
}
|
||||
@@ -196,11 +227,10 @@ struct OMNITRACE_HIDDEN indirect
|
||||
|
||||
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 _paths =
|
||||
delimit(join(":", get_env("OMNITRACE_PATH", ""),
|
||||
get_env("LD_LIBRARY_PATH", ""), get_env("LIBRARY_PATH", "")),
|
||||
":");
|
||||
|
||||
auto file_exists = [](const std::string& name) {
|
||||
struct stat buffer;
|
||||
@@ -209,7 +239,7 @@ struct OMNITRACE_HIDDEN indirect
|
||||
|
||||
for(auto&& itr : _paths)
|
||||
{
|
||||
auto _f = TIMEMORY_JOIN('/', itr, _path);
|
||||
auto _f = join('/', itr, _path);
|
||||
if(file_exists(_f)) return _f;
|
||||
}
|
||||
return _path;
|
||||
@@ -229,13 +259,15 @@ private:
|
||||
std::string m_libpath = {};
|
||||
};
|
||||
|
||||
inline std::unique_ptr<indirect>&
|
||||
inline indirect&
|
||||
get_indirect() OMNITRACE_HIDDEN;
|
||||
|
||||
template <typename FuncT, typename... Args>
|
||||
inline void
|
||||
invoke(const char* _name, FuncT&& _func, Args... _args) OMNITRACE_HIDDEN;
|
||||
} // namespace
|
||||
} // namespace dl
|
||||
} // namespace omnitrace
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
@@ -243,57 +275,132 @@ extern "C"
|
||||
{
|
||||
void omnitrace_init_library(void)
|
||||
{
|
||||
invoke(__FUNCTION__, get_indirect()->omnitrace_init_library_f);
|
||||
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);
|
||||
invoke(__FUNCTION__, get_indirect().omnitrace_init_f, a, b, c);
|
||||
}
|
||||
|
||||
void omnitrace_finalize(void)
|
||||
{
|
||||
invoke(__FUNCTION__, get_indirect()->omnitrace_finalize_f);
|
||||
invoke(__FUNCTION__, get_indirect().omnitrace_finalize_f);
|
||||
}
|
||||
|
||||
void omnitrace_push_trace(const char* name)
|
||||
{
|
||||
invoke(__FUNCTION__, get_indirect()->omnitrace_push_trace_f, 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);
|
||||
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);
|
||||
setenv(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);
|
||||
invoke(__FUNCTION__, get_indirect().omnitrace_set_mpi_f, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
inline namespace omnitrace
|
||||
{
|
||||
inline namespace dl
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template <typename ContainerT>
|
||||
inline ContainerT
|
||||
delimit(const std::string& line, const char* delimiters)
|
||||
{
|
||||
ContainerT _result{};
|
||||
size_t _beginp = 0; // position that is the beginning of the new string
|
||||
size_t _delimp = 0; // position of the delimiter in the string
|
||||
while(_beginp < line.length() && _delimp < line.length())
|
||||
{
|
||||
// find the first character (starting at _delimp) that is not a delimiter
|
||||
_beginp = line.find_first_not_of(delimiters, _delimp);
|
||||
// if no a character after or at _end that is not a delimiter is not found
|
||||
// then we are done
|
||||
if(_beginp == std::string::npos) break;
|
||||
// starting at the position of the new string, find the next delimiter
|
||||
_delimp = line.find_first_of(delimiters, _beginp);
|
||||
std::string _tmp{};
|
||||
// starting at the position of the new string, get the characters
|
||||
// between this position and the next delimiter
|
||||
_tmp = line.substr(_beginp, _delimp - _beginp);
|
||||
// don't add empty strings
|
||||
if(!_tmp.empty()) _result.emplace(_result.end(), _tmp);
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
std::string
|
||||
get_env(const char* env_id, const char* _default)
|
||||
{
|
||||
if(strlen(env_id) == 0) return _default;
|
||||
char* env_var = ::std::getenv(env_id);
|
||||
if(env_var) return std::string{ env_var };
|
||||
return _default;
|
||||
}
|
||||
|
||||
int
|
||||
get_env(const char* env_id, int _default)
|
||||
{
|
||||
if(strlen(env_id) == 0) return _default;
|
||||
char* env_var = ::std::getenv(env_id);
|
||||
if(env_var) return std::stoi(env_var);
|
||||
return _default;
|
||||
}
|
||||
|
||||
bool
|
||||
get_env(const char* env_id, bool _default)
|
||||
{
|
||||
if(strlen(env_id) == 0) return _default;
|
||||
char* env_var = ::std::getenv(env_id);
|
||||
if(env_var)
|
||||
{
|
||||
if(std::string{ env_var }.find_first_not_of("0123456789") == std::string::npos)
|
||||
return static_cast<bool>(std::stoi(env_var));
|
||||
else
|
||||
{
|
||||
for(size_t i = 0; i < strlen(env_var); ++i)
|
||||
env_var[i] = tolower(env_var[i]);
|
||||
for(const auto& itr : { "off", "false", "no", "n", "f", "0" })
|
||||
if(strcmp(env_var, itr) == 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return _default;
|
||||
}
|
||||
|
||||
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);
|
||||
auto&& _debug = get_env("OMNITRACE_DEBUG", false);
|
||||
return get_env("OMNITRACE_VERBOSE", (_debug) ? 100 : 0);
|
||||
}
|
||||
|
||||
std::unique_ptr<indirect>&
|
||||
indirect&
|
||||
get_indirect()
|
||||
{
|
||||
static std::unique_ptr<indirect> _v = std::make_unique<indirect>(
|
||||
tim::get_env<std::string>("OMNITRACE_LIBRARY", "libomnitrace.so"));
|
||||
static auto _v = indirect{ get_env("OMNITRACE_LIBRARY", "libomnitrace.so") };
|
||||
return _v;
|
||||
}
|
||||
|
||||
int32_t&
|
||||
get_guard()
|
||||
{
|
||||
static thread_local int32_t _v = 0;
|
||||
return _v;
|
||||
}
|
||||
|
||||
@@ -301,25 +408,34 @@ 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...);
|
||||
// if _lk is ever greater than zero on the same thread, this
|
||||
// means a function within the current function is calling
|
||||
// our instrumentation so we ignore the call
|
||||
int32_t _lk = get_guard()++;
|
||||
if(_lk == 0)
|
||||
{
|
||||
std::invoke(std::forward<FuncT>(_func), _args...);
|
||||
}
|
||||
else if(_omnitrace_dl_verbose > 2)
|
||||
{
|
||||
fflush(stderr);
|
||||
fprintf(stderr, "[omnitrace][dl] call to %s was guarded :: value = %i\n",
|
||||
_name, _lk);
|
||||
fflush(stderr);
|
||||
}
|
||||
// decrement the guard as it exits the scope
|
||||
--get_guard();
|
||||
}
|
||||
else if(_omnitrace_dl_verbose >= 0)
|
||||
{
|
||||
fprintf(stderr, "[omnitrace][dl] %s\n",
|
||||
TIMEMORY_JOIN("", "null function pointer to ", _name, ". Ignoring ",
|
||||
_name, "(", _args..., ")")
|
||||
join("", "null function pointer to ", _name, ". Ignoring ", _name, "(",
|
||||
_args..., ")")
|
||||
.c_str());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
} // namespace dl
|
||||
} // namespace omnitrace
|
||||
|
||||
Ссылка в новой задаче
Block a user