* 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
Этот коммит содержится в:
Jonathan R. Madsen
2022-02-25 03:56:41 -06:00
коммит произвёл GitHub
родитель 145a6ae06f
Коммит 0d5c557552
27 изменённых файлов: 1214 добавлений и 597 удалений
+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