ROCTx Library Tracing (#390)

* Update include/rocprofiler-sdk/marker/*

- Update rocprofiler_marker_api_args_t for all API functions
- Add ROCPROFILER_MARKER_API_ID_roctxGetThreadId to rocprofiler_marker_api_id_t

* Update include/rocprofiler-sdk/marker/api_args.h

- fix include

* Update lib/common/mpl.hpp

- is_pair
- is_type_complete_v

* Update include/rocprofiler-sdk/marker/*

- fix rocprofiler_marker_api_retval_t
- add roctxGetThreadId to rocprofiler_marker_api_args_t
- fix type in enum: HsaDevice -> HsaAgent
- add table_api_id.h

* Update include/rocprofiler-sdk/marker.h

- include marker/table_api_id.h

* Update include/rocprofiler-sdk/buffer_tracing.h

- Buffer marker tracer records have begin and end timestamp

* Add lib/rocprofiler-sdk/marker

- tracing implementation for marker (roctx) library

* Update include/rocprofiler-sdk/{buffer_tracing,marker/table_api_id}.h

- rocprofiler_buffer_tracing_marker_record_t -> rocprofiler_buffer_tracing_marker_api_record_t

* Update lib/rocprofiler-sdk/buffer_tracing.cpp

- support for ROCPROFILER_BUFFER_TRACING_MARKER_API

* Update lib/rocprofiler-sdk/callback_tracing.cpp

- support for ROCPROFILER_CALLBACK_TRACING_MARKER_API

* Update lib/rocprofiler-sdk/intercept_table.cpp

- template instantiation for notify_runtime_api_registration

* Update lib/rocprofiler-sdk/registration.cpp

- enable roctx in rocprofiler_set_api_table

* Update lib/rocprofiler-sdk/marker/marker.cpp

- rocprofiler_buffer_tracing_marker_record_t -> rocprofiler_buffer_tracing_marker_api_record_t

* Update lib/rocprofiler/tests for roctx testing

- add roctx.cpp
  - unit tests for roctx callback and buffer tracing
- support marker API in get_{buffer,callback}_tracing_names()

* Update lib/common/logging.cpp

- logging initialized message mentions env variable

* Update lib/common/mpl.hpp

- NOLINT for misc-definitions-in-headers

* Update lib/rocprofiler-sdk/tests/CMakeLists.txt

- include LD_LIBRARY_PATH in rocprofiler-lib-tests-shared tests

* Update lib/rocprofiler-sdk/registration.cpp

- client_library_vec_t is now vector of option<client_library>
  - enables resetting the client_library after finalization
- removed acquiring registration lock when invoke_client_finalizers called via atexit
  - this was causing some lock-order-inversion warnings (potential deadlock)

* Update lib/rocprofiler-sdk/agent.cpp

- model name for agent supports spaces

* Update tests/common/serialization.hpp

- add serialization support for marker tracing data structures

* Update tests/apps

- Add ROCTx markers into reproducible-runtime and transpose

* Update tests/tools/json-tools.cpp

- add marker tracing support
- remove strdup (no longer necessary)

* Update tests/kernel-tracing/validate.py

- validate marker API tracing data

* Update tests/async-copy-tracing/validate.py

- validate marker API tracing data

* Update cmake for load path resolution during testing

* Update tests/async-copy-tracing/CMakeLists.txt

- fix test LD_LIBRARY_PATH

* Update cmake/Templates/rocprofiler-sdk-roctx/config.cmake.in

- fix constructing rocprofiler-sdk-roctx::rocprofiler-sdk-roctx
Tá an tiomantas seo le fáil i:
Jonathan R. Madsen
2024-01-18 09:48:06 -06:00
tiomanta ag GitHub
tuismitheoir b55cea0e98
tiomantas 21dd088c8e
D'athraigh 37 comhad le 2270 breiseanna agus 310 scriosta
+66 -63
Féach ar an gComhad
@@ -33,6 +33,7 @@
#include "lib/rocprofiler-sdk/hsa/queue_controller.hpp"
#include "lib/rocprofiler-sdk/intercept_table.hpp"
#include "lib/rocprofiler-sdk/internal_threading.hpp"
#include "lib/rocprofiler-sdk/marker/marker.hpp"
#include <rocprofiler-sdk/context.h>
#include <rocprofiler-sdk/fwd.h>
@@ -156,7 +157,7 @@ struct client_library
rocprofiler_client_id_t mutable_client_id = {};
};
using client_library_vec_t = std::vector<client_library>;
using client_library_vec_t = std::vector<std::optional<client_library>>;
client_library_vec_t
find_clients()
@@ -245,17 +246,17 @@ find_clients()
// skip the configure function that was forced
if(_sym == get_forced_configure())
{
data.front().name = itr;
data.front().dlhandle = handle;
data.front().internal_client_id.name = "(forced)";
data.front()->name = itr;
data.front()->dlhandle = handle;
data.front()->internal_client_id.name = "(forced)";
continue;
}
if(_sym == &rocprofiler_configure && data.size() == 1)
{
data.front().name = itr;
data.front().dlhandle = handle;
data.front().internal_client_id.name = "default";
data.front()->name = itr;
data.front()->dlhandle = handle;
data.front()->internal_client_id.name = "default";
}
else
{
@@ -267,7 +268,7 @@ find_clients()
nullptr,
rocprofiler_client_id_t{nullptr, _prio},
rocprofiler_client_id_t{nullptr, _prio}});
entry.internal_client_id.name = entry.name.c_str();
entry->internal_client_id.name = entry->name.c_str();
}
}
@@ -280,7 +281,7 @@ find_clients()
for(const auto& ditr : data)
{
if(ditr.dlhandle && ditr.dlhandle == handle)
if(ditr->dlhandle && ditr->dlhandle == handle)
{
handle = nullptr;
break;
@@ -315,7 +316,7 @@ get_clients()
return _v;
}
using mutex_t = std::recursive_mutex;
using mutex_t = std::mutex;
using scoped_lock_t = std::unique_lock<mutex_t>;
mutex_t&
@@ -330,9 +331,7 @@ invoke_client_configures()
{
if(get_init_status() > 0) return false;
auto _lk = scoped_lock_t{get_registration_mutex(), std::defer_lock};
if(_lk.owns_lock()) return false;
_lk.lock();
auto _lk = scoped_lock_t{get_registration_mutex()};
LOG(ERROR) << __FUNCTION__;
@@ -340,20 +339,22 @@ invoke_client_configures()
for(auto& itr : *get_clients())
{
if(!itr.configure_func)
if(!itr) continue;
if(!itr->configure_func)
{
LOG(ERROR) << "rocprofiler::registration::invoke_client_configures() attempted to "
"invoke configure function from "
<< itr.name << " that had no configuration function";
<< itr->name << " that had no configuration function";
continue;
}
if(get_invoked_configures().find(itr.configure_func) != get_invoked_configures().end())
if(get_invoked_configures().find(itr->configure_func) != get_invoked_configures().end())
{
LOG(ERROR) << "rocprofiler::registration::invoke_client_configures() attempted to "
"invoke configure function from "
<< itr.name << " (addr="
<< fmt::format("{:#018x}", reinterpret_cast<uint64_t>(itr.configure_func))
<< itr->name << " (addr="
<< fmt::format("{:#018x}", reinterpret_cast<uint64_t>(itr->configure_func))
<< ") more than once";
continue;
}
@@ -361,27 +362,27 @@ invoke_client_configures()
{
LOG(INFO) << "rocprofiler::registration::invoke_client_configures() invoking configure "
"function from "
<< itr.name << " (addr="
<< fmt::format("{:#018x}", reinterpret_cast<uint64_t>(itr.configure_func))
<< itr->name << " (addr="
<< fmt::format("{:#018x}", reinterpret_cast<uint64_t>(itr->configure_func))
<< ")";
}
auto* _result = itr.configure_func(ROCPROFILER_VERSION,
ROCPROFILER_VERSION_STRING,
itr.internal_client_id.handle - get_client_offset(),
&itr.mutable_client_id);
auto* _result = itr->configure_func(ROCPROFILER_VERSION,
ROCPROFILER_VERSION_STRING,
itr->internal_client_id.handle - get_client_offset(),
&itr->mutable_client_id);
if(_result)
{
itr.configure_result = new rocprofiler_tool_configure_result_t{*_result};
itr->configure_result = new rocprofiler_tool_configure_result_t{*_result};
}
else
{
context::deactivate_client_contexts(itr.internal_client_id);
context::deregister_client_contexts(itr.internal_client_id);
context::deactivate_client_contexts(itr->internal_client_id);
context::deregister_client_contexts(itr->internal_client_id);
}
get_invoked_configures().emplace(itr.configure_func);
get_invoked_configures().emplace(itr->configure_func);
}
return true;
@@ -392,9 +393,7 @@ invoke_client_initializers()
{
if(get_init_status() > 0) return false;
auto _lk = scoped_lock_t{get_registration_mutex(), std::defer_lock};
if(_lk.owns_lock()) return false;
_lk.lock();
auto _lk = scoped_lock_t{get_registration_mutex()};
LOG(ERROR) << __FUNCTION__;
@@ -402,14 +401,14 @@ invoke_client_initializers()
for(auto& itr : *get_clients())
{
if(itr.configure_result && itr.configure_result->initialize)
if(itr && itr->configure_result && itr->configure_result->initialize)
{
context::push_client(itr.internal_client_id.handle);
itr.configure_result->initialize(&invoke_client_finalizer,
itr.configure_result->tool_data);
context::pop_client(itr.internal_client_id.handle);
context::push_client(itr->internal_client_id.handle);
itr->configure_result->initialize(&invoke_client_finalizer,
itr->configure_result->tool_data);
context::pop_client(itr->internal_client_id.handle);
// set to nullptr so initialize only gets called once
itr.configure_result->initialize = nullptr;
itr->configure_result->initialize = nullptr;
}
}
@@ -424,23 +423,12 @@ invoke_client_finalizers()
if(get_init_status() < 1 || get_fini_status() > 0) return false;
auto _lk = scoped_lock_t{get_registration_mutex(), std::defer_lock};
if(_lk.owns_lock()) return false;
_lk.lock();
LOG(ERROR) << __FUNCTION__;
if(!get_clients()) return false;
for(auto& itr : *get_clients())
if(get_clients())
{
if(itr.configure_result && itr.configure_result->finalize)
for(auto& itr : *get_clients())
{
itr.configure_result->finalize(itr.configure_result->tool_data);
// set to nullptr so finalize only gets called once
itr.configure_result->finalize = nullptr;
if(itr) invoke_client_finalizer(itr->internal_client_id);
}
context::deactivate_client_contexts(itr.internal_client_id);
}
return true;
@@ -449,29 +437,30 @@ invoke_client_finalizers()
void
invoke_client_finalizer(rocprofiler_client_id_t client_id)
{
auto _lk = scoped_lock_t{get_registration_mutex(), std::defer_lock};
if(_lk.owns_lock()) return;
_lk.lock();
LOG(ERROR) << __FUNCTION__ << "(client_id=" << client_id.handle << ")";
LOG(ERROR) << __FUNCTION__;
auto _lk = scoped_lock_t{get_registration_mutex()};
if(!get_clients()) return;
for(auto& itr : *get_clients())
{
if(itr.internal_client_id.handle == client_id.handle &&
itr.mutable_client_id.handle == client_id.handle)
if(itr && itr->internal_client_id.handle == client_id.handle &&
itr->mutable_client_id.handle == client_id.handle)
{
if(itr.configure_result && itr.configure_result->finalize)
if(itr->configure_result && itr->configure_result->finalize)
{
// set to nullptr so finalize only gets called once
rocprofiler_tool_finalize_t _finalize_func = nullptr;
std::swap(_finalize_func, itr->configure_result->finalize);
auto _fini_status = get_fini_status();
if(_fini_status == 0) set_fini_status(-1);
itr.configure_result->finalize(itr.configure_result->tool_data);
_finalize_func(itr->configure_result->tool_data);
if(_fini_status == 0) set_fini_status(_fini_status);
// set to nullptr so finalize only gets called once
itr.configure_result->finalize = nullptr;
}
context::deactivate_client_contexts(itr.internal_client_id);
context::deactivate_client_contexts(itr->internal_client_id);
itr.reset();
}
}
}
@@ -684,7 +673,21 @@ rocprofiler_set_api_table(const char* name,
LOG_IF(ERROR, num_tables > 1)
<< " rocprofiler expected ROCTX library to pass 1 API table, not " << num_tables;
return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED;
auto* roctx_api_table = static_cast<roctxApiTable_t*>(*tables);
// any internal modifications to the roctxApiTable_t need to be done before we make
// the copy or else those modifications will be lost when ROCTx tracing is enabled because
// the ROCTx tracing invokes the function pointers from the copy below
rocprofiler::marker::copy_table(roctx_api_table);
// install rocprofiler API wrappers
rocprofiler::marker::update_table(roctx_api_table);
rocprofiler::intercept_table::notify_runtime_api_registration(
ROCPROFILER_MARKER_LIBRARY,
lib_version,
lib_instance,
std::make_tuple(roctx_api_table));
}
else
{