HIP API Tracing (#357)
* Update include/rocprofiler-sdk/hip*
- updates for intercept table
* Update lib/common/units.hpp
- clang-tidy fixes
* Add lib/rocprofiler-sdk/hip
- tracing implementation for the HIP intercept table
* Update source/lib/rocprofiler-sdk/CMakeLists.txt
- add_subdirectory(hip)
* Update source/lib/rocprofiler-sdk/hsa
- offset function in hsa_api_info<Idx>
- remove report_activity, set_callback
- Tweak HSA_API_TABLE_LOOKUP_DEFINITION
* Update lib/rocprofiler-sdk/hip
- rocprofiler::hip::copy_table
- stringize_impl print dereferenced pointers when possible
* Update lib/rocprofiler-sdk/hsa/utils.hpp
- stringize_impl print dereferenced pointers when possible
* Update lib/rocprofiler-sdk/tests/intercept_table.cpp
- remove failures for intercepting HIP API tables
* Update include/rocprofiler-sdk/fwd.h
- add ROCPROFILER_HIP_RUNTIME_LIBRARY (== ROCPROFILER_HIP_LIBRARY)
- add ROCPROFILER_HIP_COMPILER_LIBRARY
* Update lib/rocprofiler-sdk/buffer_tracing.cpp
- Support ROCPROFILER_BUFFER_TRACING_HIP_API in rocprofiler_query_buffer_tracing_kind_operation_name
- Support ROCPROFILER_BUFFER_TRACING_HIP_API in rocprofiler_iterate_buffer_tracing_kind_operations
* Update lib/rocprofiler-sdk/callback_tracing.cpp
- Support ROCPROFILER_CALLBACK_TRACING_HIP_API in rocprofiler_query_callback_tracing_kind_operation_name
- Support ROCPROFILER_CALLBACK_TRACING_HIP_API in rocprofiler_iterate_callback_tracing_kind_operations
- Support ROCPROFILER_CALLBACK_TRACING_HIP_API in rocprofiler_iterate_callback_tracing_kind_operation_args
* Update lib/rocprofiler-sdk/intercept_table.cpp
- support HipDispatchTable and HipCompilerDispatchTable
* Update lib/rocprofiler-sdk/internal_threading.cpp
- Support ROCPROFILER_HIP_COMPILER_LIBRARY
* Update lib/rocprofiler-sdk/registration.cpp
- Support "hip" and "hip_compiler" in rocprofiler_set_api_table
- Added some extra logging
* Update samples/api_{buffered,callback}_tracing
- Modifications to demonstrate HIP API tracing
* Update tests/kernel-tracing
- Modifications to handle/test HIP API tracing
* Separate HIP tracing from HIP compiler tracing
* Fix installation of include/rocprofiler-sdk/hip/*
- add compiler and table headers to install
* Fixes to HIP interception
- hip_api_trace.hpp was updated a bit
- removed hipGetDeviceProperties (generic)
- added hipGetDevicePropertiesR0600
- added hipGetDevicePropertiesR0000
- removed hipRegisterTracerCallback
- reordered hipCreateChannelDesc, hipExtModuleLaunchKernel, hipHccModuleLaunchKernel
- added hipDrvGraphAddMemsetNode
- static asserts in hsa_api_info ensuring ordering of pointers
* Update lib/rocprofiler-sdk/hip/hip.*
- use size_t instead of rocprofiler_hip_table_api_id_t as non-type template parameter (smaller binary)
- separated out population of callback_context_data and buffered_context_data into non-template function (significantly smaller binary)
* Update lib/rocprofiler-sdk/hsa/hsa.*
- separated out population of callback_context_data and buffered_context_data into non-template function (significantly smaller binary)
* Update test/kernel-tracing/validate.py
- does not expect any hip_api_traces until libamdhip.so actually starts using rocprofiler-register
* Update tests/tools/json-tool.cpp
- fix context associated with "HIP_API_CALLBACK"
* Update external/CMakeLists.txt
- move misc variables to top of CMakeLists.txt so they apply to all external subprojects
- BUILD_TESTING (OFF)
- BUILD_SHARED_LIBS (OFF)
- BUILD_OBJECT_LIBS (OFF)
- BUILD_STATIC_LIBS (ON)
- CMAKE_POSITION_INDEPENDENT_CODE (ON)
- CMAKE_VISIBILITY_INLINES_HIDDEN (ON)
- CMAKE_CXX_VISIBILITY_PRESET (hidden)
- disable using libunwind in glog
* Update lib/rocprofiler-{sdk,sdk-tool}/CMakeLists.txt
- remove explicit setting of SKIP_BUILD_RPATH
* Update CMakeLists.txt
- set high-level CMAKE_BUILD_RPATH and CMAKE_INSTALL_RPATH_USE_LINK_PATH
* Update tests/CMakeLists.txt
- include(GNUInstallDirs)
* Update samples/CMakeLists.txt
- include(GNUInstallDirs)
* Update include/rocprofiler-sdk/hip/{compiler_api,api}_args.h
- remove extern "C" due to incompatibility b/t empty struct in C (size 0) vs. empty struct in C++ (size 1)
* Update lib/rocprofiler-sdk/hip/details/ostream.hpp
- clang-tidy fixes
* Update cmake/rocprofiler_linting.cmake
- add a feature for clang tidy exe
* Update lib/rocprofiler-sdk/hip/hip.cpp
- use recursion instead of fold expression due to clang-tidy errors (maximum nesting level exceeded)
* Update lib/rocprofiler-sdk/buffer_tracing.cpp
- fix merge
* Update lib/rocprofiler-sdk/callback_tracing.cpp
- fix merge
* Update bin/rocprofv3
- args for marker, HIP runtime, and HIP compiler tracing
* Update tests/apps/simple-transpose
- use roctx
* Update tests/rocprofv3/tracing
- validate marker API data
* Update lib/rocprofiler-sdk-tool
- support for HIP runtime, HIP compiler, marker API
* Update queue/queue_controller/registration/utility
- call hsa::queue_controller_fini() during finalization
- add a yield function to common/utility.hpp
- implements a thread yield + sleep
- add a sync function to Queue class
- add a iterate_queues member function to QueueController
- this is used to sync each queue during queue_controller_fini()
* Fix data races: queue/context/stable_vector
- stable_vector::emplace_back returns reference
- correlation id map uses stable_vector
- queue_info_session has explicit fields for queue id, hsa agent, rocp agent
- use hsa::get_table() in AsyncSignalHandler
- WriteInterceptor does not use TLS for context array
* Update lib/rocprofiler-sdk/hsa/hsa.*
- static object for API subtables
- accessors for API subtables
- google tests for HSA API subtables
* Update lib/rocprofiler-sdk/hsa/{queue,async_copy}.cpp
- use HSA subtable accessors
* Update rocprofiler_memcheck and CI workflow
- use GCC 13 instead of GCC 11 due to suspected false positives in thread sanitizer
- GCC 13 uses libtsan.so.2
* Update CI workflow
* Update lib/rocprofiler-sdk/counters/{metrics,counters}
- fix possibly dangling reference to a temporary from gcc-13
* Update thread-sanitizer-suppr.txt
- Ignore data races originating in hsa-runtime library
* Update cmake/rocprofiler_memcheck.cmake
- Deduce the sanitizer library to preload by compiling an application and extracting the linked sanitizer library
* Update tests/rocprofv3/tracing/CMakeLists.txt
- add csv files to REQUIRED_FILES and ATTACH_ON_FAIL in validate test
* Update lib/common/container/record_header_buffer.hpp
- fix data race identified by gcc v13 and libtsan.so.2
* Update hip API id, args, and def
- remove hipDrvGraphAddMemsetNode (not part of ROCm 6.0
* Update lib/common/container/record_header_buffer.hpp
- fix deadlock in save/read/reset
* Update source/docs/CMakeLists.txt
- remove COMMAND_ERROR_IS_FATAL ANY to allow for printing of stdout/stderr
* Update lib/rocprofiler-sdk/hip/details/ostream.hpp
- remove overloads for HIP_MEMSET_NODE_PARAMS
* Update docs/CMakeLists.txt
- use find_program for shell instead of hardcoded /bin/bash
This commit is contained in:
committed by
GitHub
parent
f84c2f4386
commit
c641749fe6
@@ -127,7 +127,14 @@ struct record_header_buffer
|
||||
auto is_full() const;
|
||||
|
||||
private:
|
||||
std::atomic<int32_t> m_locked = {0};
|
||||
/// this is an explicit write lock that does not guard against deadlocking like lock()
|
||||
void write_lock();
|
||||
|
||||
/// this is an explicit write unlock that does not guard against deadlocking like unlock()
|
||||
void write_unlock();
|
||||
|
||||
private:
|
||||
std::atomic<int64_t> m_locked = {0};
|
||||
std::atomic<size_t> m_index = {};
|
||||
std::shared_mutex m_shared = {};
|
||||
base_buffer_t m_buffer = {};
|
||||
@@ -144,14 +151,14 @@ inline void
|
||||
record_header_buffer::lock()
|
||||
{
|
||||
auto n = m_locked.fetch_add(1, std::memory_order_release);
|
||||
if(n == 0) m_shared.lock();
|
||||
if(n == 0) write_lock();
|
||||
}
|
||||
|
||||
inline void
|
||||
record_header_buffer::unlock()
|
||||
{
|
||||
auto n = m_locked.fetch_add(-1, std::memory_order_release);
|
||||
if(n <= 1) m_shared.unlock();
|
||||
auto n = m_locked.fetch_sub(1, std::memory_order_release);
|
||||
if(n <= 1) write_unlock();
|
||||
}
|
||||
|
||||
inline void
|
||||
@@ -166,6 +173,18 @@ record_header_buffer::read_unlock()
|
||||
m_shared.unlock_shared();
|
||||
}
|
||||
|
||||
inline void
|
||||
record_header_buffer::write_lock()
|
||||
{
|
||||
m_shared.lock();
|
||||
}
|
||||
|
||||
inline void
|
||||
record_header_buffer::write_unlock()
|
||||
{
|
||||
m_shared.unlock();
|
||||
}
|
||||
|
||||
inline bool
|
||||
record_header_buffer::is_allocated() const
|
||||
{
|
||||
@@ -212,21 +231,22 @@ template <typename Tp>
|
||||
bool
|
||||
record_header_buffer::emplace(uint64_t _hash, Tp& _v)
|
||||
{
|
||||
if(is_locked() || m_headers.empty()) return false;
|
||||
if(m_headers.empty()) return false;
|
||||
|
||||
// request N bytes in the buffer (where N=sizeof(Tp)) and if
|
||||
// available, copy _v into the buffer region
|
||||
auto _create_record = [](auto& _buf, auto& _data) {
|
||||
constexpr auto buffer_sz = sizeof(Tp);
|
||||
void* _ptr = _buf.request(buffer_sz, false);
|
||||
if(_ptr) new(_ptr) Tp{_data};
|
||||
return _ptr;
|
||||
};
|
||||
constexpr auto request_size = sizeof(Tp);
|
||||
|
||||
// in theory, we shouldn't need to lock here but the thread sanitizer says there is a race.
|
||||
// the lock will be short-lived so hopefully, it will scale fine
|
||||
write_lock();
|
||||
auto* _addr = m_buffer.request(request_size, false);
|
||||
write_unlock();
|
||||
|
||||
read_lock();
|
||||
auto _addr = _create_record(m_buffer, _v);
|
||||
if(_addr)
|
||||
{
|
||||
// placement new
|
||||
new(_addr) Tp{_v};
|
||||
|
||||
// if there is space in the buffer, atomically get an index
|
||||
// for where the header record should be placed.
|
||||
// NOTE: m_headers was resized to be large enough to accomodate
|
||||
@@ -245,21 +265,22 @@ template <typename Tp>
|
||||
bool
|
||||
record_header_buffer::emplace(uint32_t _category, uint32_t _kind, Tp& _v)
|
||||
{
|
||||
if(is_locked() || m_headers.empty()) return false;
|
||||
if(m_headers.empty()) return false;
|
||||
|
||||
// request N bytes in the buffer (where N=sizeof(Tp)) and if
|
||||
// available, copy _v into the buffer region
|
||||
auto _create_record = [](auto& _buf, auto& _data) {
|
||||
constexpr auto buffer_sz = sizeof(Tp);
|
||||
void* _ptr = _buf.request(buffer_sz, false);
|
||||
if(_ptr) new(_ptr) Tp{_data};
|
||||
return _ptr;
|
||||
};
|
||||
constexpr auto request_size = sizeof(Tp);
|
||||
|
||||
// in theory, we shouldn't need to lock here but the thread sanitizer says there is a race.
|
||||
// the lock will be short-lived so hopefully, it will scale fine
|
||||
write_lock();
|
||||
auto* _addr = m_buffer.request(request_size, false);
|
||||
write_unlock();
|
||||
|
||||
read_lock();
|
||||
auto _addr = _create_record(m_buffer, _v);
|
||||
if(_addr)
|
||||
{
|
||||
// placement new
|
||||
new(_addr) Tp{_v};
|
||||
|
||||
// if there is space in the buffer, atomically get an index
|
||||
// for where the header record should be placed.
|
||||
// NOTE: m_headers was resized to be large enough to accomodate
|
||||
|
||||
@@ -220,7 +220,7 @@ public:
|
||||
void push_back(Tp&& t);
|
||||
|
||||
template <typename... Args>
|
||||
void emplace_back(Args&&... args);
|
||||
reference emplace_back(Args&&... args);
|
||||
|
||||
reference operator[](size_type i);
|
||||
|
||||
@@ -351,10 +351,10 @@ stable_vector<Tp, ChunkSizeV>::push_back(Tp&& t)
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
template <typename... Args>
|
||||
void
|
||||
typename stable_vector<Tp, ChunkSizeV>::reference
|
||||
stable_vector<Tp, ChunkSizeV>::emplace_back(Args&&... args)
|
||||
{
|
||||
last_chunk().emplace_back(std::forward<Args>(args)...);
|
||||
return last_chunk().emplace_back(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Tp, size_t ChunkSizeV>
|
||||
|
||||
@@ -187,7 +187,7 @@ get_memory_unit(std::string _unit)
|
||||
using return_type = std::tuple<string_t, int64_t>;
|
||||
using inner_t = std::tuple<string_t, string_t, int64_t>;
|
||||
|
||||
if(_unit.length() == 0) return return_type{"MB", units::megabyte};
|
||||
if(_unit.empty()) return return_type{"MB", units::megabyte};
|
||||
|
||||
for(auto& itr : _unit)
|
||||
itr = tolower(itr);
|
||||
@@ -228,7 +228,7 @@ get_timing_unit(std::string _unit)
|
||||
using return_type = std::tuple<string_t, int64_t>;
|
||||
using inner_t = std::tuple<string_t, strset_t, int64_t>;
|
||||
|
||||
if(_unit.length() == 0) return return_type{"sec", units::sec};
|
||||
if(_unit.empty()) return return_type{"sec", units::sec};
|
||||
|
||||
for(auto& itr : _unit)
|
||||
itr = tolower(itr);
|
||||
@@ -264,7 +264,7 @@ get_frequncy_unit(std::string _unit)
|
||||
using return_type = std::tuple<string_t, int64_t>;
|
||||
using inner_t = std::tuple<string_t, string_t, int64_t>;
|
||||
|
||||
if(_unit.length() == 0) return return_type{"MHz", units::megahertz};
|
||||
if(_unit.empty()) return return_type{"MHz", units::megahertz};
|
||||
|
||||
for(auto& itr : _unit)
|
||||
itr = tolower(itr);
|
||||
@@ -295,7 +295,7 @@ get_power_unit(const std::string& _unit)
|
||||
using return_type = std::tuple<string_t, int64_t>;
|
||||
using inner_t = std::tuple<string_t, string_t, int64_t>;
|
||||
|
||||
if(_unit.length() == 0) return return_type{"watts", units::watt};
|
||||
if(_unit.empty()) return return_type{"watts", units::watt};
|
||||
|
||||
auto _lunit = _unit;
|
||||
for(auto& itr : _lunit)
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <ratio>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
@@ -210,5 +211,35 @@ private:
|
||||
data_type m_data = {};
|
||||
functor_type m_destroy_func = {};
|
||||
};
|
||||
|
||||
template <typename Tp = long, typename RatioT = std::ratio<1, 1000>>
|
||||
void
|
||||
yield(std::chrono::duration<Tp, RatioT> duration = std::chrono::milliseconds{10})
|
||||
{
|
||||
std::this_thread::yield();
|
||||
std::this_thread::sleep_for(duration);
|
||||
}
|
||||
|
||||
template <typename PredicateT, typename Tp = long, typename RatioT = std::ratio<1, 1000>>
|
||||
bool
|
||||
yield(PredicateT&& predicate,
|
||||
std::chrono::duration<Tp, RatioT> max_yield_time,
|
||||
std::chrono::duration<Tp, RatioT> query_interval = std::chrono::milliseconds{10})
|
||||
{
|
||||
auto now = []() { return std::chrono::steady_clock::now(); };
|
||||
auto start = now();
|
||||
auto result = false;
|
||||
while(!(result = predicate()))
|
||||
{
|
||||
yield(query_interval);
|
||||
if((now() - start) > max_yield_time)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// return the result of the last predicate query
|
||||
return result;
|
||||
}
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
|
||||
Reference in New Issue
Block a user