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
This commit is contained in:
committed by
GitHub
parent
b55cea0e98
commit
21dd088c8e
@@ -44,7 +44,7 @@ else()
|
||||
|
||||
# Library dependencies
|
||||
foreach(TARG @PROJECT_BUILD_TARGETS@)
|
||||
set(TARG @PACKAGE_NAME@::@PACKAGE_NAME@-${TARG})
|
||||
set(TARG @PACKAGE_NAME@::${TARG})
|
||||
if(NOT @PACKAGE_NAME@_FIND_COMPONENTS)
|
||||
list(APPEND @PACKAGE_NAME@_LIBRARIES ${TARG})
|
||||
target_link_libraries(@PACKAGE_NAME@::@PACKAGE_NAME@ INTERFACE ${TARG})
|
||||
@@ -53,7 +53,7 @@ else()
|
||||
|
||||
if(@PACKAGE_NAME@_FIND_COMPONENTS)
|
||||
foreach(COMP ${@PACKAGE_NAME@_FIND_COMPONENTS})
|
||||
set(TARG @PACKAGE_NAME@::${COMP})
|
||||
set(TARG @PACKAGE_NAME@::@PACKAGE_NAME@-${COMP})
|
||||
if(TARGET ${TARG})
|
||||
set(@PACKAGE_NAME@_${COMP}_FOUND 1)
|
||||
list(APPEND @PACKAGE_NAME@_LIBRARIES ${TARG})
|
||||
|
||||
@@ -70,11 +70,12 @@ typedef struct
|
||||
{
|
||||
uint64_t size; ///< size of this struct
|
||||
rocprofiler_buffer_tracing_kind_t kind; ///< ::ROCPROFILER_CALLBACK_TRACING_MARKER_API
|
||||
rocprofiler_correlation_id_t correlation_id; ///< correlation ids for record
|
||||
rocprofiler_tracing_operation_t operation; ///< ::rocprofiler_marker_api_id_t
|
||||
rocprofiler_timestamp_t timestamp; ///< time in nanoseconds
|
||||
rocprofiler_thread_id_t thread_id; ///< id for thread generating this record
|
||||
uint64_t marker_id; ///< rocprofiler_marker_id_t
|
||||
rocprofiler_correlation_id_t correlation_id; ///< correlation ids for record
|
||||
rocprofiler_tracing_operation_t operation; ///< ::rocprofiler_marker_api_id_t
|
||||
rocprofiler_timestamp_t start_timestamp; ///< start time in nanoseconds
|
||||
rocprofiler_timestamp_t end_timestamp; ///< end time in nanoseconds
|
||||
rocprofiler_thread_id_t thread_id; ///< id for thread generating this record
|
||||
uint64_t marker_id; ///< rocprofiler_marker_id_t
|
||||
// const char* message; // (Need Review?)
|
||||
} rocprofiler_buffer_tracing_marker_api_record_t;
|
||||
|
||||
|
||||
@@ -24,3 +24,4 @@
|
||||
|
||||
#include <rocprofiler-sdk/marker/api_args.h>
|
||||
#include <rocprofiler-sdk/marker/api_id.h>
|
||||
#include <rocprofiler-sdk/marker/table_api_id.h>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# Installation of public HSA headers
|
||||
#
|
||||
#
|
||||
set(ROCPROFILER_MARKER_HEADER_FILES api_args.h api_id.h)
|
||||
set(ROCPROFILER_MARKER_HEADER_FILES api_args.h api_id.h table_api_id.h)
|
||||
|
||||
install(
|
||||
FILES ${ROCPROFILER_MARKER_HEADER_FILES}
|
||||
|
||||
@@ -22,13 +22,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rocprofiler-sdk-roctx/api_trace.h>
|
||||
#include <rocprofiler-sdk-roctx/types.h>
|
||||
|
||||
typedef uint64_t roctx_range_id_t;
|
||||
#include <stdint.h>
|
||||
|
||||
typedef union rocprofiler_marker_api_retval_u
|
||||
{
|
||||
uint32_t uint32_t_retval;
|
||||
int32_t int32_t_retval;
|
||||
int64_t int64_t_retval;
|
||||
uint64_t uint64_t_retval;
|
||||
} rocprofiler_marker_api_retval_t;
|
||||
|
||||
@@ -53,4 +55,35 @@ typedef union rocprofiler_marker_api_args_u
|
||||
{
|
||||
roctx_range_id_t id;
|
||||
} roctxRangeStop;
|
||||
struct
|
||||
{
|
||||
roctx_thread_id_t tid;
|
||||
} roctxProfilerPause;
|
||||
struct
|
||||
{
|
||||
roctx_thread_id_t tid;
|
||||
} roctxProfilerResume;
|
||||
struct
|
||||
{
|
||||
const char* name;
|
||||
} roctxNameOsThread;
|
||||
struct
|
||||
{
|
||||
const char* name;
|
||||
const struct hsa_agent_s* agent;
|
||||
} roctxNameHsaAgent;
|
||||
struct
|
||||
{
|
||||
const char* name;
|
||||
int device_id;
|
||||
} roctxNameHipDevice;
|
||||
struct
|
||||
{
|
||||
const char* name;
|
||||
const struct ihipStream_t* stream;
|
||||
} roctxNameHipStream;
|
||||
struct
|
||||
{
|
||||
roctx_thread_id_t* tid;
|
||||
} roctxGetThreadId;
|
||||
} rocprofiler_marker_api_args_t;
|
||||
|
||||
@@ -36,8 +36,9 @@ typedef enum // NOLINT(performance-enum-size)
|
||||
ROCPROFILER_MARKER_API_ID_roctxProfilerPause,
|
||||
ROCPROFILER_MARKER_API_ID_roctxProfilerResume,
|
||||
ROCPROFILER_MARKER_API_ID_roctxNameOsThread,
|
||||
ROCPROFILER_MARKER_API_ID_roctxNameHsaDevice,
|
||||
ROCPROFILER_MARKER_API_ID_roctxNameHsaAgent,
|
||||
ROCPROFILER_MARKER_API_ID_roctxNameHipDevice,
|
||||
ROCPROFILER_MARKER_API_ID_roctxNameHipStream,
|
||||
ROCPROFILER_MARKER_API_ID_roctxGetThreadId,
|
||||
ROCPROFILER_MARKER_API_ID_LAST,
|
||||
} rocprofiler_marker_api_id_t;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
// NOLINTNEXTLINE(performance-enum-size)
|
||||
typedef enum
|
||||
{
|
||||
ROCPROFILER_MARKER_API_TABLE_ID_NONE = -1,
|
||||
ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi = 0,
|
||||
} rocprofiler_marker_table_api_id_t;
|
||||
@@ -79,7 +79,7 @@ init_logging(std::string_view env_var)
|
||||
|
||||
FLAGS_minloglevel = loglvl_v;
|
||||
FLAGS_stderrthreshold = loglvl_v;
|
||||
LOG(INFO) << "logging initialized";
|
||||
LOG(INFO) << "logging initialized via " << env_var;
|
||||
});
|
||||
}
|
||||
} // namespace common
|
||||
|
||||
@@ -90,6 +90,28 @@ struct is_one_of<F, Tuple<S, T...>>
|
||||
{
|
||||
static constexpr bool value = is_one_of<F, S, Tuple<T...>>::value;
|
||||
};
|
||||
|
||||
template <typename Tp>
|
||||
struct is_pair_impl
|
||||
{
|
||||
static constexpr auto value = false;
|
||||
};
|
||||
|
||||
template <typename LhsT, typename RhsT>
|
||||
struct is_pair_impl<std::pair<LhsT, RhsT>>
|
||||
{
|
||||
static constexpr auto value = true;
|
||||
};
|
||||
|
||||
template <typename Tp>
|
||||
struct is_pair : is_pair_impl<std::remove_cv_t<std::remove_reference_t<std::decay_t<Tp>>>>
|
||||
{};
|
||||
|
||||
template <typename, typename = void>
|
||||
constexpr bool is_type_complete_v = false; // NOLINT(misc-definitions-in-headers)
|
||||
|
||||
template <typename T> // NOLINTNEXTLINE(misc-definitions-in-headers)
|
||||
constexpr bool is_type_complete_v<T, std::void_t<decltype(sizeof(T))>> = true;
|
||||
} // namespace mpl
|
||||
} // namespace common
|
||||
} // namespace rocprofiler
|
||||
|
||||
@@ -7,6 +7,8 @@ find_package(rocprofiler-register REQUIRED)
|
||||
add_library(rocprofiler-sdk-roctx-shared-library SHARED)
|
||||
add_library(rocprofiler::rocprofiler-sdk-roctx-shared-library ALIAS
|
||||
rocprofiler-sdk-roctx-shared-library)
|
||||
add_library(rocprofiler-sdk-roctx::rocprofiler-sdk-roctx-shared-library ALIAS
|
||||
rocprofiler-sdk-roctx-shared-library)
|
||||
|
||||
target_sources(rocprofiler-sdk-roctx-shared-library PRIVATE roctx.cpp)
|
||||
target_include_directories(
|
||||
|
||||
@@ -40,6 +40,7 @@ add_subdirectory(context)
|
||||
add_subdirectory(counters)
|
||||
add_subdirectory(aql)
|
||||
add_subdirectory(pc_sampling)
|
||||
add_subdirectory(marker)
|
||||
|
||||
target_link_libraries(
|
||||
rocprofiler-object-library
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "lib/rocprofiler-sdk/agent.hpp"
|
||||
#include "lib/rocprofiler-sdk/hsa/agent_cache.hpp"
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/format.h>
|
||||
#include <glog/logging.h>
|
||||
#include <hsa/hsa_api_trace.h>
|
||||
#include <libdrm/amdgpu.h>
|
||||
@@ -404,7 +404,8 @@ read_topology()
|
||||
agent_info.node_id = nodecount++;
|
||||
|
||||
if(!name_prop.empty())
|
||||
agent_info.model_name = get_string_entry(name_prop.front())->c_str();
|
||||
agent_info.model_name =
|
||||
get_string_entry(fmt::format("{}", fmt::join(name_prop, " ")))->c_str();
|
||||
else
|
||||
agent_info.model_name = "";
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "lib/rocprofiler-sdk/context/context.hpp"
|
||||
#include "lib/rocprofiler-sdk/context/domain.hpp"
|
||||
#include "lib/rocprofiler-sdk/hsa/hsa.hpp"
|
||||
#include "lib/rocprofiler-sdk/marker/marker.hpp"
|
||||
#include "lib/rocprofiler-sdk/registration.hpp"
|
||||
|
||||
#include <glog/logging.h>
|
||||
@@ -143,25 +144,26 @@ rocprofiler_query_buffer_tracing_kind_operation_name(rocprofiler_buffer_tracing_
|
||||
if(kind < ROCPROFILER_BUFFER_TRACING_NONE || kind >= ROCPROFILER_BUFFER_TRACING_LAST)
|
||||
return ROCPROFILER_STATUS_ERROR_KIND_NOT_FOUND;
|
||||
|
||||
const char* val = nullptr;
|
||||
if(kind == ROCPROFILER_BUFFER_TRACING_HSA_API)
|
||||
val = rocprofiler::hsa::name_by_id(operation);
|
||||
else if(kind == ROCPROFILER_BUFFER_TRACING_MARKER_API)
|
||||
val = rocprofiler::marker::name_by_id<ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi>(operation);
|
||||
else
|
||||
return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
if(!val)
|
||||
{
|
||||
const auto* val = rocprofiler::hsa::name_by_id(operation);
|
||||
if(name) *name = nullptr;
|
||||
if(name_len) *name_len = 0;
|
||||
|
||||
if(!val)
|
||||
{
|
||||
if(name) *name = nullptr;
|
||||
if(name_len) *name_len = 0;
|
||||
|
||||
return ROCPROFILER_STATUS_ERROR_OPERATION_NOT_FOUND;
|
||||
}
|
||||
|
||||
if(name) *name = val;
|
||||
if(name_len) *name_len = strnlen(val, 4096);
|
||||
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
return ROCPROFILER_STATUS_ERROR_OPERATION_NOT_FOUND;
|
||||
}
|
||||
|
||||
return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED;
|
||||
if(name) *name = val;
|
||||
if(name_len) *name_len = strnlen(val, 4096);
|
||||
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
rocprofiler_status_t
|
||||
@@ -182,18 +184,20 @@ rocprofiler_iterate_buffer_tracing_kind_operations(
|
||||
rocprofiler_buffer_tracing_kind_operation_cb_t callback,
|
||||
void* data)
|
||||
{
|
||||
auto ops = std::vector<uint32_t>{};
|
||||
if(kind == ROCPROFILER_BUFFER_TRACING_HSA_API)
|
||||
{
|
||||
auto ops = rocprofiler::hsa::get_ids();
|
||||
for(const auto& itr : ops)
|
||||
{
|
||||
auto _success = callback(kind, itr, data);
|
||||
if(_success != 0) break;
|
||||
}
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
}
|
||||
ops = rocprofiler::hsa::get_ids();
|
||||
else if(kind == ROCPROFILER_BUFFER_TRACING_MARKER_API)
|
||||
ops = rocprofiler::marker::get_ids<ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi>();
|
||||
else
|
||||
return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED;
|
||||
for(const auto& itr : ops)
|
||||
{
|
||||
auto _success = callback(kind, itr, data);
|
||||
if(_success != 0) break;
|
||||
}
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "lib/rocprofiler-sdk/context/context.hpp"
|
||||
#include "lib/rocprofiler-sdk/context/domain.hpp"
|
||||
#include "lib/rocprofiler-sdk/hsa/hsa.hpp"
|
||||
#include "lib/rocprofiler-sdk/marker/marker.hpp"
|
||||
#include "lib/rocprofiler-sdk/registration.hpp"
|
||||
|
||||
#include <glog/logging.h>
|
||||
@@ -134,25 +135,26 @@ rocprofiler_query_callback_tracing_kind_operation_name(rocprofiler_callback_trac
|
||||
if(kind < ROCPROFILER_CALLBACK_TRACING_NONE || kind >= ROCPROFILER_CALLBACK_TRACING_LAST)
|
||||
return ROCPROFILER_STATUS_ERROR_KIND_NOT_FOUND;
|
||||
|
||||
const char* val = nullptr;
|
||||
if(kind == ROCPROFILER_CALLBACK_TRACING_HSA_API)
|
||||
val = rocprofiler::hsa::name_by_id(operation);
|
||||
else if(kind == ROCPROFILER_CALLBACK_TRACING_MARKER_API)
|
||||
val = rocprofiler::marker::name_by_id<ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi>(operation);
|
||||
else
|
||||
return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
if(!val)
|
||||
{
|
||||
const auto* val = rocprofiler::hsa::name_by_id(operation);
|
||||
if(name) *name = nullptr;
|
||||
if(name_len) *name_len = 0;
|
||||
|
||||
if(!val)
|
||||
{
|
||||
if(name) *name = nullptr;
|
||||
if(name_len) *name_len = 0;
|
||||
|
||||
return ROCPROFILER_STATUS_ERROR_OPERATION_NOT_FOUND;
|
||||
}
|
||||
|
||||
if(name) *name = val;
|
||||
if(name_len) *name_len = strnlen(val, 4096);
|
||||
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
return ROCPROFILER_STATUS_ERROR_OPERATION_NOT_FOUND;
|
||||
}
|
||||
|
||||
return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED;
|
||||
if(name) *name = val;
|
||||
if(name_len) *name_len = strnlen(val, 4096);
|
||||
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
rocprofiler_status_t
|
||||
@@ -174,18 +176,20 @@ rocprofiler_iterate_callback_tracing_kind_operations(
|
||||
rocprofiler_callback_tracing_kind_operation_cb_t callback,
|
||||
void* data)
|
||||
{
|
||||
auto ops = std::vector<uint32_t>{};
|
||||
if(kind == ROCPROFILER_CALLBACK_TRACING_HSA_API)
|
||||
{
|
||||
auto ops = rocprofiler::hsa::get_ids();
|
||||
for(const auto& itr : ops)
|
||||
{
|
||||
auto _success = callback(kind, itr, data);
|
||||
if(_success != 0) break;
|
||||
}
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
}
|
||||
ops = rocprofiler::hsa::get_ids();
|
||||
else if(kind == ROCPROFILER_CALLBACK_TRACING_MARKER_API)
|
||||
ops = rocprofiler::marker::get_ids<ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi>();
|
||||
else
|
||||
return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED;
|
||||
for(const auto& itr : ops)
|
||||
{
|
||||
auto _success = callback(kind, itr, data);
|
||||
if(_success != 0) break;
|
||||
}
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
rocprofiler_status_t
|
||||
@@ -203,6 +207,15 @@ rocprofiler_iterate_callback_tracing_kind_operation_args(
|
||||
user_data);
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
}
|
||||
else if(record.kind == ROCPROFILER_CALLBACK_TRACING_MARKER_API)
|
||||
{
|
||||
rocprofiler::marker::iterate_args(
|
||||
record.operation,
|
||||
*static_cast<rocprofiler_callback_tracing_marker_api_data_t*>(record.payload),
|
||||
callback,
|
||||
user_data);
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@@ -156,6 +156,11 @@ template void notify_runtime_api_registration(rocprofiler_runtime_library_t,
|
||||
uint64_t,
|
||||
uint64_t,
|
||||
std::tuple<HsaApiTable*>);
|
||||
|
||||
template void notify_runtime_api_registration(rocprofiler_runtime_library_t,
|
||||
uint64_t,
|
||||
uint64_t,
|
||||
std::tuple<roctxApiTable_t*>);
|
||||
} // namespace intercept_table
|
||||
} // namespace rocprofiler
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#
|
||||
#
|
||||
set(ROCPROFILER_LIB_MARKER_SOURCES marker.cpp)
|
||||
set(ROCPROFILER_LIB_MARKER_HEADERS defines.hpp marker.hpp utils.hpp)
|
||||
|
||||
target_sources(rocprofiler-object-library PRIVATE ${ROCPROFILER_LIB_MARKER_SOURCES}
|
||||
${ROCPROFILER_LIB_MARKER_HEADERS})
|
||||
@@ -0,0 +1,286 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define IMPL_DETAIL_EXPAND(X) X
|
||||
#define IMPL_DETAIL_FOR_EACH_NARG(...) \
|
||||
IMPL_DETAIL_FOR_EACH_NARG_(__VA_ARGS__, IMPL_DETAIL_FOR_EACH_RSEQ_N())
|
||||
#define IMPL_DETAIL_FOR_EACH_NARG_(...) IMPL_DETAIL_EXPAND(IMPL_DETAIL_FOR_EACH_ARG_N(__VA_ARGS__))
|
||||
#define IMPL_DETAIL_FOR_EACH_ARG_N( \
|
||||
_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, N, ...) \
|
||||
N
|
||||
#define IMPL_DETAIL_FOR_EACH_RSEQ_N() 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
|
||||
#define IMPL_DETAIL_CONCATENATE(X, Y) X##Y
|
||||
#define IMPL_DETAIL_FOR_EACH_(N, MACRO, PREFIX, ...) \
|
||||
IMPL_DETAIL_EXPAND(IMPL_DETAIL_CONCATENATE(MACRO, N)(PREFIX, __VA_ARGS__))
|
||||
#define IMPL_DETAIL_FOR_EACH(MACRO, PREFIX, ...) \
|
||||
IMPL_DETAIL_FOR_EACH_(IMPL_DETAIL_FOR_EACH_NARG(__VA_ARGS__), MACRO, PREFIX, __VA_ARGS__)
|
||||
|
||||
#define ADDR_MEMBER_0(...)
|
||||
#define ADDR_MEMBER_1(PREFIX, FIELD) static_cast<void*>(&PREFIX.FIELD)
|
||||
#define ADDR_MEMBER_2(PREFIX, A, B) ADDR_MEMBER_1(PREFIX, A), ADDR_MEMBER_1(PREFIX, B)
|
||||
#define ADDR_MEMBER_3(PREFIX, A, B, C) ADDR_MEMBER_2(PREFIX, A, B), ADDR_MEMBER_1(PREFIX, C)
|
||||
#define ADDR_MEMBER_4(PREFIX, A, B, C, D) ADDR_MEMBER_3(PREFIX, A, B, C), ADDR_MEMBER_1(PREFIX, D)
|
||||
#define ADDR_MEMBER_5(PREFIX, A, B, C, D, E) \
|
||||
ADDR_MEMBER_4(PREFIX, A, B, C, D), ADDR_MEMBER_1(PREFIX, E)
|
||||
#define ADDR_MEMBER_6(PREFIX, A, B, C, D, E, F) \
|
||||
ADDR_MEMBER_5(PREFIX, A, B, C, D, E), ADDR_MEMBER_1(PREFIX, F)
|
||||
#define ADDR_MEMBER_7(PREFIX, A, B, C, D, E, F, G) \
|
||||
ADDR_MEMBER_6(PREFIX, A, B, C, D, E, F), ADDR_MEMBER_1(PREFIX, G)
|
||||
#define ADDR_MEMBER_8(PREFIX, A, B, C, D, E, F, G, H) \
|
||||
ADDR_MEMBER_7(PREFIX, A, B, C, D, E, F, G), ADDR_MEMBER_1(PREFIX, H)
|
||||
#define ADDR_MEMBER_9(PREFIX, A, B, C, D, E, F, G, H, I) \
|
||||
ADDR_MEMBER_8(PREFIX, A, B, C, D, E, F, G, H), ADDR_MEMBER_1(PREFIX, I)
|
||||
#define ADDR_MEMBER_10(PREFIX, A, B, C, D, E, F, G, H, I, J) \
|
||||
ADDR_MEMBER_9(PREFIX, A, B, C, D, E, F, G, H, I), ADDR_MEMBER_1(PREFIX, J)
|
||||
#define ADDR_MEMBER_11(PREFIX, A, B, C, D, E, F, G, H, I, J, K) \
|
||||
ADDR_MEMBER_10(PREFIX, A, B, C, D, E, F, G, H, I, J), ADDR_MEMBER_1(PREFIX, K)
|
||||
#define ADDR_MEMBER_12(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L) \
|
||||
ADDR_MEMBER_11(PREFIX, A, B, C, D, E, F, G, H, I, J, K), ADDR_MEMBER_1(PREFIX, L)
|
||||
#define ADDR_MEMBER_13(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L, M) \
|
||||
ADDR_MEMBER_12(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L), ADDR_MEMBER_1(PREFIX, M)
|
||||
#define ADDR_MEMBER_14(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L, M, N) \
|
||||
ADDR_MEMBER_13(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L, M), ADDR_MEMBER_1(PREFIX, N)
|
||||
#define ADDR_MEMBER_15(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) \
|
||||
ADDR_MEMBER_14(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L, M, N), ADDR_MEMBER_1(PREFIX, O)
|
||||
|
||||
#define NAMED_MEMBER_0(...)
|
||||
#define NAMED_MEMBER_1(PREFIX, FIELD) std::make_pair(#FIELD, PREFIX.FIELD)
|
||||
#define NAMED_MEMBER_2(PREFIX, A, B) NAMED_MEMBER_1(PREFIX, A), NAMED_MEMBER_1(PREFIX, B)
|
||||
#define NAMED_MEMBER_3(PREFIX, A, B, C) NAMED_MEMBER_2(PREFIX, A, B), NAMED_MEMBER_1(PREFIX, C)
|
||||
#define NAMED_MEMBER_4(PREFIX, A, B, C, D) \
|
||||
NAMED_MEMBER_3(PREFIX, A, B, C), NAMED_MEMBER_1(PREFIX, D)
|
||||
#define NAMED_MEMBER_5(PREFIX, A, B, C, D, E) \
|
||||
NAMED_MEMBER_4(PREFIX, A, B, C, D), NAMED_MEMBER_1(PREFIX, E)
|
||||
#define NAMED_MEMBER_6(PREFIX, A, B, C, D, E, F) \
|
||||
NAMED_MEMBER_5(PREFIX, A, B, C, D, E), NAMED_MEMBER_1(PREFIX, F)
|
||||
#define NAMED_MEMBER_7(PREFIX, A, B, C, D, E, F, G) \
|
||||
NAMED_MEMBER_6(PREFIX, A, B, C, D, E, F), NAMED_MEMBER_1(PREFIX, G)
|
||||
#define NAMED_MEMBER_8(PREFIX, A, B, C, D, E, F, G, H) \
|
||||
NAMED_MEMBER_7(PREFIX, A, B, C, D, E, F, G), NAMED_MEMBER_1(PREFIX, H)
|
||||
#define NAMED_MEMBER_9(PREFIX, A, B, C, D, E, F, G, H, I) \
|
||||
NAMED_MEMBER_8(PREFIX, A, B, C, D, E, F, G, H), NAMED_MEMBER_1(PREFIX, I)
|
||||
#define NAMED_MEMBER_10(PREFIX, A, B, C, D, E, F, G, H, I, J) \
|
||||
NAMED_MEMBER_9(PREFIX, A, B, C, D, E, F, G, H, I), NAMED_MEMBER_1(PREFIX, J)
|
||||
#define NAMED_MEMBER_11(PREFIX, A, B, C, D, E, F, G, H, I, J, K) \
|
||||
NAMED_MEMBER_10(PREFIX, A, B, C, D, E, F, G, H, I, J), NAMED_MEMBER_1(PREFIX, K)
|
||||
#define NAMED_MEMBER_12(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L) \
|
||||
NAMED_MEMBER_11(PREFIX, A, B, C, D, E, F, G, H, I, J, K), NAMED_MEMBER_1(PREFIX, L)
|
||||
#define NAMED_MEMBER_13(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L, M) \
|
||||
NAMED_MEMBER_12(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L), NAMED_MEMBER_1(PREFIX, M)
|
||||
#define NAMED_MEMBER_14(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L, M, N) \
|
||||
NAMED_MEMBER_13(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L, M), NAMED_MEMBER_1(PREFIX, N)
|
||||
#define NAMED_MEMBER_15(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O) \
|
||||
NAMED_MEMBER_14(PREFIX, A, B, C, D, E, F, G, H, I, J, K, L, M, N), NAMED_MEMBER_1(PREFIX, O)
|
||||
|
||||
#define GET_ADDR_MEMBER_FIELDS(VAR, ...) IMPL_DETAIL_FOR_EACH(ADDR_MEMBER_, VAR, __VA_ARGS__)
|
||||
#define GET_NAMED_MEMBER_FIELDS(VAR, ...) IMPL_DETAIL_FOR_EACH(NAMED_MEMBER_, VAR, __VA_ARGS__)
|
||||
|
||||
#define MARKER_API_INFO_DEFINITION_0(MARKER_TABLE, MARKER_API_ID, MARKER_FUNC, MARKER_FUNC_PTR) \
|
||||
namespace rocprofiler \
|
||||
{ \
|
||||
namespace marker \
|
||||
{ \
|
||||
template <> \
|
||||
struct roctx_api_info<MARKER_TABLE, MARKER_API_ID> : roctx_domain_info<MARKER_TABLE> \
|
||||
{ \
|
||||
static constexpr auto table_idx = MARKER_TABLE; \
|
||||
static constexpr auto operation_idx = MARKER_API_ID; \
|
||||
static constexpr auto name = #MARKER_FUNC; \
|
||||
\
|
||||
using domain_type = roctx_domain_info<table_idx>; \
|
||||
using this_type = roctx_api_info<table_idx, operation_idx>; \
|
||||
using base_type = roctx_api_impl<table_idx, operation_idx>; \
|
||||
\
|
||||
using domain_type::callback_domain_idx; \
|
||||
using domain_type::buffered_domain_idx; \
|
||||
using domain_type::args_type; \
|
||||
using domain_type::retval_type; \
|
||||
using domain_type::callback_data_type; \
|
||||
\
|
||||
static constexpr auto offset() \
|
||||
{ \
|
||||
return offsetof(roctx_table_lookup<table_idx>::type, MARKER_FUNC_PTR); \
|
||||
} \
|
||||
\
|
||||
static_assert(offsetof(roctx_table_lookup<table_idx>::type, MARKER_FUNC_PTR) == \
|
||||
(sizeof(size_t) + (operation_idx * sizeof(void*))), \
|
||||
"ABI error for " #MARKER_FUNC); \
|
||||
\
|
||||
static auto& get_table() { return roctx_table_lookup<table_idx>{}(); } \
|
||||
\
|
||||
template <typename TableT> \
|
||||
static auto& get_table(TableT& _v) \
|
||||
{ \
|
||||
return roctx_table_lookup<table_idx>{}(_v); \
|
||||
} \
|
||||
\
|
||||
template <typename TableT> \
|
||||
static auto& get_table_func(TableT& _table) \
|
||||
{ \
|
||||
if constexpr(std::is_pointer<TableT>::value) \
|
||||
{ \
|
||||
assert(_table != nullptr && "nullptr to MARKER table for " #MARKER_FUNC \
|
||||
" function"); \
|
||||
return _table->MARKER_FUNC_PTR; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
return _table.MARKER_FUNC_PTR; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static auto& get_table_func() { return get_table_func(get_table()); } \
|
||||
\
|
||||
template <typename DataT> \
|
||||
static auto& get_api_data_args(DataT& _data) \
|
||||
{ \
|
||||
return _data.MARKER_FUNC; \
|
||||
} \
|
||||
\
|
||||
template <typename RetT, typename... Args> \
|
||||
static auto get_functor(RetT (*)(Args...)) \
|
||||
{ \
|
||||
if constexpr(std::is_void<RetT>::value) \
|
||||
return [](Args... args) -> RetT { base_type::functor(args...); }; \
|
||||
else \
|
||||
return [](Args... args) -> RetT { return base_type::functor(args...); }; \
|
||||
} \
|
||||
\
|
||||
static auto get_functor() { return get_functor(get_table_func()); } \
|
||||
\
|
||||
static std::vector<void*> as_arg_addr(callback_data_type) { return std::vector<void*>{}; } \
|
||||
\
|
||||
static std::vector<std::pair<std::string, std::string>> as_arg_list(callback_data_type) \
|
||||
{ \
|
||||
return {}; \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MARKER_API_INFO_DEFINITION_V( \
|
||||
MARKER_TABLE, MARKER_API_ID, MARKER_FUNC, MARKER_FUNC_PTR, ...) \
|
||||
namespace rocprofiler \
|
||||
{ \
|
||||
namespace marker \
|
||||
{ \
|
||||
template <> \
|
||||
struct roctx_api_info<MARKER_TABLE, MARKER_API_ID> : roctx_domain_info<MARKER_TABLE> \
|
||||
{ \
|
||||
static constexpr auto table_idx = MARKER_TABLE; \
|
||||
static constexpr auto operation_idx = MARKER_API_ID; \
|
||||
static constexpr auto name = #MARKER_FUNC; \
|
||||
\
|
||||
using domain_type = roctx_domain_info<table_idx>; \
|
||||
using this_type = roctx_api_info<table_idx, operation_idx>; \
|
||||
using base_type = roctx_api_impl<table_idx, operation_idx>; \
|
||||
\
|
||||
static constexpr auto callback_domain_idx = domain_type::callback_domain_idx; \
|
||||
static constexpr auto buffered_domain_idx = domain_type::buffered_domain_idx; \
|
||||
\
|
||||
using domain_type::args_type; \
|
||||
using domain_type::retval_type; \
|
||||
using domain_type::callback_data_type; \
|
||||
\
|
||||
static constexpr auto offset() \
|
||||
{ \
|
||||
return offsetof(roctx_table_lookup<table_idx>::type, MARKER_FUNC_PTR); \
|
||||
} \
|
||||
\
|
||||
static_assert(offsetof(roctx_table_lookup<table_idx>::type, MARKER_FUNC_PTR) == \
|
||||
(sizeof(size_t) + (operation_idx * sizeof(void*))), \
|
||||
"ABI error for " #MARKER_FUNC); \
|
||||
\
|
||||
static auto& get_table() { return roctx_table_lookup<table_idx>{}(); } \
|
||||
\
|
||||
template <typename TableT> \
|
||||
static auto& get_table(TableT& _v) \
|
||||
{ \
|
||||
return roctx_table_lookup<table_idx>{}(_v); \
|
||||
} \
|
||||
\
|
||||
template <typename TableT> \
|
||||
static auto& get_table_func(TableT& _table) \
|
||||
{ \
|
||||
if constexpr(std::is_pointer<TableT>::value) \
|
||||
{ \
|
||||
assert(_table != nullptr && "nullptr to MARKER table for " #MARKER_FUNC \
|
||||
" function"); \
|
||||
return _table->MARKER_FUNC_PTR; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
return _table.MARKER_FUNC_PTR; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
static auto& get_table_func() { return get_table_func(get_table()); } \
|
||||
\
|
||||
template <typename DataT> \
|
||||
static auto& get_api_data_args(DataT& _data) \
|
||||
{ \
|
||||
return _data.MARKER_FUNC; \
|
||||
} \
|
||||
\
|
||||
template <typename RetT, typename... Args> \
|
||||
static auto get_functor(RetT (*)(Args...)) \
|
||||
{ \
|
||||
if constexpr(std::is_same<RetT, void>::value) \
|
||||
return [](Args... args) -> RetT { base_type::functor(args...); }; \
|
||||
else \
|
||||
return [](Args... args) -> RetT { return base_type::functor(args...); }; \
|
||||
} \
|
||||
\
|
||||
static auto get_functor() { return get_functor(get_table_func()); } \
|
||||
\
|
||||
static std::vector<void*> as_arg_addr(callback_data_type trace_data) \
|
||||
{ \
|
||||
return std::vector<void*>{ \
|
||||
GET_ADDR_MEMBER_FIELDS(get_api_data_args(trace_data.args), __VA_ARGS__)}; \
|
||||
} \
|
||||
\
|
||||
static auto as_arg_list(callback_data_type trace_data) \
|
||||
{ \
|
||||
return utils::stringize( \
|
||||
GET_NAMED_MEMBER_FIELDS(get_api_data_args(trace_data.args), __VA_ARGS__)); \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define MARKER_API_TABLE_LOOKUP_DEFINITION(TABLE_ID, TYPE) \
|
||||
namespace rocprofiler \
|
||||
{ \
|
||||
namespace marker \
|
||||
{ \
|
||||
template <> \
|
||||
struct roctx_table_lookup<TABLE_ID> \
|
||||
{ \
|
||||
using type = TYPE; \
|
||||
auto& operator()(roctx_api_table_t& _v) const { return _v; } \
|
||||
auto& operator()(roctx_api_table_t* _v) const { return *_v; } \
|
||||
auto& operator()() const { return (*this)(get_table()); } \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
@@ -0,0 +1,612 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. 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 "lib/rocprofiler-sdk/marker/marker.hpp"
|
||||
#include "lib/common/defines.hpp"
|
||||
#include "lib/common/utility.hpp"
|
||||
#include "lib/rocprofiler-sdk/buffer.hpp"
|
||||
#include "lib/rocprofiler-sdk/context/context.hpp"
|
||||
#include "lib/rocprofiler-sdk/marker/utils.hpp"
|
||||
|
||||
#include <rocprofiler-sdk/buffer.h>
|
||||
#include <rocprofiler-sdk/callback_tracing.h>
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/marker.h>
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include <rocprofiler-sdk-roctx/roctx.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace marker
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct null_type
|
||||
{};
|
||||
|
||||
template <typename Tp>
|
||||
auto
|
||||
get_default_retval()
|
||||
{
|
||||
if constexpr(std::is_integral<Tp>::value)
|
||||
return Tp{0};
|
||||
else
|
||||
static_assert(std::is_empty<Tp>::value, "Error! unsupported return type");
|
||||
}
|
||||
|
||||
template <typename DataT, typename Tp>
|
||||
void
|
||||
set_data_retval(DataT& _data, Tp _val)
|
||||
{
|
||||
if constexpr(std::is_same<int32_t, Tp>::value)
|
||||
_data.int32_t_retval = _val;
|
||||
else if constexpr(std::is_same<int64_t, Tp>::value)
|
||||
_data.int64_t_retval = _val;
|
||||
else if constexpr(std::is_same<uint64_t, Tp>::value)
|
||||
_data.uint64_t_retval = _val;
|
||||
else
|
||||
static_assert(std::is_empty<Tp>::value, "Error! unsupported return type");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
roctx_api_table_t&
|
||||
get_table()
|
||||
{
|
||||
static auto _v = common::init_public_api_struct(roctx_api_table_t{});
|
||||
return _v;
|
||||
}
|
||||
|
||||
template <size_t TableIdx, size_t OpIdx>
|
||||
template <typename DataArgsT, typename... Args>
|
||||
auto
|
||||
roctx_api_impl<TableIdx, OpIdx>::set_data_args(DataArgsT& _data_args, Args... args)
|
||||
{
|
||||
_data_args = DataArgsT{args...};
|
||||
}
|
||||
|
||||
template <size_t TableIdx, size_t OpIdx>
|
||||
template <typename FuncT, typename... Args>
|
||||
auto
|
||||
roctx_api_impl<TableIdx, OpIdx>::exec(FuncT&& _func, Args&&... args)
|
||||
{
|
||||
using return_type = std::decay_t<std::invoke_result_t<FuncT, Args...>>;
|
||||
|
||||
if(_func)
|
||||
{
|
||||
if constexpr(std::is_void<return_type>::value)
|
||||
{
|
||||
_func(std::forward<Args>(args)...);
|
||||
return null_type{};
|
||||
}
|
||||
else
|
||||
{
|
||||
return _func(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
using info_type = roctx_api_info<TableIdx, OpIdx>;
|
||||
LOG(ERROR) << "nullptr to next roctx function for " << info_type::name << " ("
|
||||
<< info_type::operation_idx << ")";
|
||||
|
||||
if constexpr(std::is_void<return_type>::value)
|
||||
return null_type{};
|
||||
else
|
||||
return get_default_retval<return_type>();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
using correlation_service = context::correlation_tracing_service;
|
||||
using buffer_marker_api_record_t = rocprofiler_buffer_tracing_marker_api_record_t;
|
||||
|
||||
struct callback_context_data
|
||||
{
|
||||
const context::context* ctx = nullptr;
|
||||
rocprofiler_callback_tracing_record_t record = {};
|
||||
rocprofiler_user_data_t user_data = {.value = 0};
|
||||
};
|
||||
|
||||
struct buffered_context_data
|
||||
{
|
||||
const context::context* ctx = nullptr;
|
||||
rocprofiler_user_data_t external_correlation = {};
|
||||
};
|
||||
|
||||
constexpr auto empty_user_data = rocprofiler_user_data_t{.value = 0};
|
||||
|
||||
void
|
||||
populate_contexts(rocprofiler_callback_tracing_kind_t callback_domain_idx,
|
||||
rocprofiler_buffer_tracing_kind_t buffered_domain_idx,
|
||||
int operation_idx,
|
||||
std::vector<callback_context_data>& callback_contexts,
|
||||
std::vector<buffered_context_data>& buffered_contexts)
|
||||
{
|
||||
auto active_contexts = context::context_array_t{};
|
||||
auto thr_id = common::get_tid();
|
||||
for(const auto* itr : context::get_active_contexts(active_contexts))
|
||||
{
|
||||
if(!itr) continue;
|
||||
|
||||
// if(itr->pc_sampler) has_pc_sampling = true;
|
||||
|
||||
if(itr->callback_tracer)
|
||||
{
|
||||
// if the given domain + op is not enabled, skip this context
|
||||
if(itr->callback_tracer->domains(callback_domain_idx, operation_idx))
|
||||
callback_contexts.emplace_back(
|
||||
callback_context_data{itr, rocprofiler_callback_tracing_record_t{}});
|
||||
}
|
||||
|
||||
if(itr->buffered_tracer)
|
||||
{
|
||||
// if the given domain + op is not enabled, skip this context
|
||||
if(itr->buffered_tracer->domains(buffered_domain_idx, operation_idx))
|
||||
buffered_contexts.emplace_back(buffered_context_data{
|
||||
itr, itr->correlation_tracer.external_correlator.get(thr_id)});
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <size_t TableIdx, size_t OpIdx>
|
||||
template <typename... Args>
|
||||
auto
|
||||
roctx_api_impl<TableIdx, OpIdx>::functor(Args&&... args)
|
||||
{
|
||||
using info_type = roctx_api_info<TableIdx, OpIdx>;
|
||||
using callback_api_data_t = typename roctx_domain_info<TableIdx>::callback_data_type;
|
||||
|
||||
auto thr_id = common::get_tid();
|
||||
auto callback_contexts = std::vector<callback_context_data>{};
|
||||
auto buffered_contexts = std::vector<buffered_context_data>{};
|
||||
auto has_pc_sampling = false;
|
||||
|
||||
populate_contexts(info_type::callback_domain_idx,
|
||||
info_type::buffered_domain_idx,
|
||||
info_type::operation_idx,
|
||||
callback_contexts,
|
||||
buffered_contexts);
|
||||
|
||||
if(callback_contexts.empty() && buffered_contexts.empty())
|
||||
{
|
||||
auto _ret = exec(info_type::get_table_func(), std::forward<Args>(args)...);
|
||||
if constexpr(!std::is_same<decltype(_ret), null_type>::value)
|
||||
return _ret;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto ref_count = (has_pc_sampling) ? 4 : 2;
|
||||
auto buffer_record = common::init_public_api_struct(buffer_marker_api_record_t{});
|
||||
auto tracer_data = callback_api_data_t{.size = sizeof(callback_api_data_t)};
|
||||
auto* corr_id = correlation_service::construct(ref_count);
|
||||
auto internal_corr_id = corr_id->internal;
|
||||
|
||||
// construct the buffered info before the callback so the callbacks are as closely wrapped
|
||||
// around the function call as possible
|
||||
if(!buffered_contexts.empty())
|
||||
{
|
||||
buffer_record.kind = info_type::buffered_domain_idx;
|
||||
// external correlation will be updated right before record is placed in buffer
|
||||
buffer_record.correlation_id =
|
||||
rocprofiler_correlation_id_t{internal_corr_id, empty_user_data};
|
||||
buffer_record.operation = info_type::operation_idx;
|
||||
buffer_record.thread_id = thr_id;
|
||||
}
|
||||
|
||||
tracer_data.size = sizeof(callback_api_data_t);
|
||||
set_data_args(info_type::get_api_data_args(tracer_data.args), std::forward<Args>(args)...);
|
||||
|
||||
// invoke the callbacks
|
||||
if(!callback_contexts.empty())
|
||||
{
|
||||
set_data_args(info_type::get_api_data_args(tracer_data.args), std::forward<Args>(args)...);
|
||||
|
||||
for(auto& itr : callback_contexts)
|
||||
{
|
||||
auto& ctx = itr.ctx;
|
||||
auto& record = itr.record;
|
||||
auto& user_data = itr.user_data;
|
||||
|
||||
auto extern_corr_id_v = ctx->correlation_tracer.external_correlator.get(thr_id);
|
||||
|
||||
auto corr_id_v = rocprofiler_correlation_id_t{internal_corr_id, extern_corr_id_v};
|
||||
record =
|
||||
rocprofiler_callback_tracing_record_t{rocprofiler_context_id_t{ctx->context_idx},
|
||||
thr_id,
|
||||
corr_id_v,
|
||||
info_type::callback_domain_idx,
|
||||
info_type::operation_idx,
|
||||
ROCPROFILER_CALLBACK_PHASE_ENTER,
|
||||
static_cast<void*>(&tracer_data)};
|
||||
|
||||
auto& callback_info =
|
||||
ctx->callback_tracer->callback_data.at(info_type::callback_domain_idx);
|
||||
callback_info.callback(record, &user_data, callback_info.data);
|
||||
|
||||
// enter callback may update the external correlation id field
|
||||
record.correlation_id.external =
|
||||
ctx->correlation_tracer.external_correlator.get(thr_id);
|
||||
}
|
||||
}
|
||||
|
||||
// record the start timestamp as close to the function call as possible
|
||||
if(!buffered_contexts.empty())
|
||||
{
|
||||
for(auto& itr : buffered_contexts)
|
||||
{
|
||||
itr.external_correlation = itr.ctx->correlation_tracer.external_correlator.get(thr_id);
|
||||
}
|
||||
|
||||
buffer_record.start_timestamp = common::timestamp_ns();
|
||||
}
|
||||
|
||||
// decrement the reference count before invoking
|
||||
corr_id->ref_count.fetch_sub(1);
|
||||
|
||||
auto _ret = exec(info_type::get_table_func(), std::forward<Args>(args)...);
|
||||
|
||||
// record the end timestamp as close to the function call as possible
|
||||
if(!buffered_contexts.empty())
|
||||
{
|
||||
buffer_record.end_timestamp = common::timestamp_ns();
|
||||
}
|
||||
|
||||
if(!callback_contexts.empty())
|
||||
{
|
||||
set_data_retval(tracer_data.retval, _ret);
|
||||
|
||||
for(auto& itr : callback_contexts)
|
||||
{
|
||||
auto& ctx = itr.ctx;
|
||||
auto& record = itr.record;
|
||||
auto& user_data = itr.user_data;
|
||||
|
||||
record.phase = ROCPROFILER_CALLBACK_PHASE_EXIT;
|
||||
record.payload = static_cast<void*>(&tracer_data);
|
||||
|
||||
auto& callback_info =
|
||||
ctx->callback_tracer->callback_data.at(info_type::callback_domain_idx);
|
||||
callback_info.callback(record, &user_data, callback_info.data);
|
||||
}
|
||||
}
|
||||
|
||||
if(!buffered_contexts.empty())
|
||||
{
|
||||
for(auto& itr : buffered_contexts)
|
||||
{
|
||||
assert(itr.ctx->buffered_tracer);
|
||||
auto buffer_id =
|
||||
itr.ctx->buffered_tracer->buffer_data.at(info_type::buffered_domain_idx);
|
||||
auto buffer_v = buffer::get_buffer(buffer_id);
|
||||
if(buffer_v && buffer_v->context_id == itr.ctx->context_idx &&
|
||||
buffer_v->buffer_id == buffer_id.handle)
|
||||
{
|
||||
// make copy of record
|
||||
auto record_v = buffer_record;
|
||||
// update the record with the correlation
|
||||
record_v.correlation_id.external = itr.external_correlation;
|
||||
|
||||
buffer_v->emplace(
|
||||
ROCPROFILER_BUFFER_CATEGORY_TRACING, info_type::buffered_domain_idx, record_v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decrement the reference count after usage in the callback/buffers
|
||||
corr_id->ref_count.fetch_sub(1);
|
||||
|
||||
context::pop_latest_correlation_id(corr_id);
|
||||
|
||||
if constexpr(!std::is_same<decltype(_ret), null_type>::value)
|
||||
return _ret;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
} // namespace marker
|
||||
} // namespace rocprofiler
|
||||
|
||||
#define ROCPROFILER_LIB_ROCPROFILER_MARKER_MARKER_CPP_IMPL 1
|
||||
|
||||
// template specializations
|
||||
#include "marker.def.cpp"
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace marker
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template <size_t TableIdx>
|
||||
struct api_id_bounds;
|
||||
|
||||
template <>
|
||||
struct api_id_bounds<ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi>
|
||||
{
|
||||
static constexpr auto none = ROCPROFILER_MARKER_API_ID_NONE;
|
||||
static constexpr auto last = ROCPROFILER_MARKER_API_ID_LAST;
|
||||
};
|
||||
|
||||
template <size_t TableIdx, size_t OpIdx, size_t... OpIdxTail>
|
||||
const char*
|
||||
name_by_id(const uint32_t id, std::index_sequence<OpIdx, OpIdxTail...>)
|
||||
{
|
||||
if(OpIdx == id) return roctx_api_info<TableIdx, OpIdx>::name;
|
||||
|
||||
if constexpr(sizeof...(OpIdxTail) > 0)
|
||||
return name_by_id<TableIdx>(id, std::index_sequence<OpIdxTail...>{});
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <size_t TableIdx, size_t OpIdx, size_t... OpIdxTail>
|
||||
uint32_t
|
||||
id_by_name(const char* name, std::index_sequence<OpIdx, OpIdxTail...>)
|
||||
{
|
||||
if(std::string_view{roctx_api_info<TableIdx, OpIdx>::name} == std::string_view{name})
|
||||
return roctx_api_info<TableIdx, OpIdx>::operation_idx;
|
||||
|
||||
if constexpr(sizeof...(OpIdxTail) > 0)
|
||||
return id_by_name<TableIdx>(name, std::index_sequence<OpIdxTail...>{});
|
||||
else
|
||||
return api_id_bounds<TableIdx>::none;
|
||||
}
|
||||
|
||||
template <size_t TableIdx, size_t OpIdx, size_t... OpIdxTail>
|
||||
void
|
||||
get_ids(std::vector<uint32_t>& _id_list, std::index_sequence<OpIdx, OpIdxTail...>)
|
||||
{
|
||||
auto _idx = roctx_api_info<TableIdx, OpIdx>::operation_idx;
|
||||
if(_idx < api_id_bounds<TableIdx>::last) _id_list.emplace_back(_idx);
|
||||
|
||||
if constexpr(sizeof...(OpIdxTail) > 0)
|
||||
get_ids<TableIdx>(_id_list, std::index_sequence<OpIdxTail...>{});
|
||||
}
|
||||
|
||||
template <size_t TableIdx, size_t OpIdx, size_t... OpIdxTail>
|
||||
void
|
||||
get_names(std::vector<const char*>& _name_list, std::index_sequence<OpIdx, OpIdxTail...>)
|
||||
{
|
||||
auto&& _name = roctx_api_info<TableIdx, OpIdx>::name;
|
||||
if(_name != nullptr && strnlen(_name, 1) > 0) _name_list.emplace_back(_name);
|
||||
|
||||
if constexpr(sizeof...(OpIdxTail) > 0)
|
||||
get_names<TableIdx>(_name_list, std::index_sequence<OpIdxTail...>{});
|
||||
}
|
||||
|
||||
template <size_t OpIdx, size_t... OpIdxTail>
|
||||
void
|
||||
iterate_args(const uint32_t id,
|
||||
const rocprofiler_callback_tracing_marker_api_data_t& data,
|
||||
rocprofiler_callback_tracing_operation_args_cb_t func,
|
||||
void* user_data,
|
||||
std::index_sequence<OpIdx, OpIdxTail...>)
|
||||
{
|
||||
if(OpIdx == id)
|
||||
{
|
||||
using info_type = roctx_api_info<ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, OpIdx>;
|
||||
auto&& arg_list = info_type::as_arg_list(data);
|
||||
auto&& arg_addr = info_type::as_arg_addr(data);
|
||||
for(size_t i = 0; i < std::min(arg_list.size(), arg_addr.size()); ++i)
|
||||
{
|
||||
auto ret = func(info_type::callback_domain_idx, // kind
|
||||
id, // operation
|
||||
i, // arg_number
|
||||
arg_list.at(i).first.c_str(), // arg_name
|
||||
arg_list.at(i).second.c_str(), // arg_value_str
|
||||
arg_addr.at(i), // arg_value_addr
|
||||
user_data);
|
||||
if(ret != 0) break;
|
||||
}
|
||||
}
|
||||
if constexpr(sizeof...(OpIdxTail) > 0)
|
||||
iterate_args(id, data, func, user_data, std::index_sequence<OpIdxTail...>{});
|
||||
}
|
||||
|
||||
bool
|
||||
should_wrap_functor(rocprofiler_callback_tracing_kind_t _callback_domain,
|
||||
rocprofiler_buffer_tracing_kind_t _buffered_domain,
|
||||
int _operation)
|
||||
{
|
||||
// we loop over all the *registered* contexts and see if any of them, at any point in time,
|
||||
// might require callback or buffered API tracing
|
||||
for(const auto& itr : context::get_registered_contexts())
|
||||
{
|
||||
if(!itr) continue;
|
||||
|
||||
// if there is a callback tracer enabled for the given domain and op, we need to wrap
|
||||
if(itr->callback_tracer && itr->callback_tracer->domains(_callback_domain) &&
|
||||
itr->callback_tracer->domains(_callback_domain, _operation))
|
||||
return true;
|
||||
|
||||
// if there is a buffered tracer enabled for the given domain and op, we need to wrap
|
||||
if(itr->buffered_tracer && itr->buffered_tracer->domains(_buffered_domain) &&
|
||||
itr->buffered_tracer->domains(_buffered_domain, _operation))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <size_t TableIdx, typename Tp, size_t OpIdx>
|
||||
void
|
||||
copy_table(Tp* _orig, std::integral_constant<size_t, OpIdx>)
|
||||
{
|
||||
using table_type = typename roctx_table_lookup<TableIdx>::type;
|
||||
|
||||
if constexpr(std::is_same<table_type, Tp>::value)
|
||||
{
|
||||
auto _info = roctx_api_info<TableIdx, OpIdx>{};
|
||||
|
||||
LOG(INFO) << "copying table entry for " << _info.name;
|
||||
|
||||
// make sure we don't access a field that doesn't exist in input table
|
||||
if(_info.offset() >= _orig->size) return;
|
||||
|
||||
// 1. get the sub-table containing the function pointer in original table
|
||||
// 2. get reference to function pointer in sub-table in original table
|
||||
auto& _table = _info.get_table(_orig);
|
||||
auto& _func = _info.get_table_func(_table);
|
||||
// 3. get the sub-table containing the function pointer in saved table
|
||||
// 4. get reference to function pointer in sub-table in saved table
|
||||
// 5. save the original function in the saved table
|
||||
auto& _saved = _info.get_table(get_table());
|
||||
auto& _ofunc = _info.get_table_func(_saved);
|
||||
_ofunc = _func;
|
||||
}
|
||||
|
||||
(void) _orig;
|
||||
}
|
||||
|
||||
template <size_t TableIdx, typename Tp, size_t OpIdx>
|
||||
void
|
||||
update_table(Tp* _orig, std::integral_constant<size_t, OpIdx>)
|
||||
{
|
||||
using table_type = typename roctx_table_lookup<TableIdx>::type;
|
||||
|
||||
if constexpr(std::is_same<table_type, Tp>::value)
|
||||
{
|
||||
auto _info = roctx_api_info<TableIdx, OpIdx>{};
|
||||
|
||||
LOG(INFO) << "updating table entry for " << _info.name;
|
||||
|
||||
// make sure we don't access a field that doesn't exist in input table
|
||||
if(_info.offset() >= _orig->size) return;
|
||||
|
||||
// check to see if there are any contexts which enable this operation in the ROCTX API
|
||||
// domain
|
||||
if(!should_wrap_functor(
|
||||
_info.callback_domain_idx, _info.buffered_domain_idx, _info.operation_idx))
|
||||
return;
|
||||
|
||||
// 1. get the sub-table containing the function pointer in original table
|
||||
// 2. get reference to function pointer in sub-table in original table
|
||||
// 3. update function pointer with wrapper
|
||||
auto& _table = _info.get_table(_orig);
|
||||
auto& _func = _info.get_table_func(_table);
|
||||
_func = _info.get_functor(_func);
|
||||
}
|
||||
|
||||
(void) _orig;
|
||||
}
|
||||
|
||||
template <size_t TableIdx, typename Tp, size_t OpIdx, size_t... OpIdxTail>
|
||||
void
|
||||
copy_table(Tp* _orig, std::index_sequence<OpIdx, OpIdxTail...>)
|
||||
{
|
||||
copy_table<TableIdx>(_orig, std::integral_constant<size_t, OpIdx>{});
|
||||
if constexpr(sizeof...(OpIdxTail) > 0)
|
||||
copy_table<TableIdx>(_orig, std::index_sequence<OpIdxTail...>{});
|
||||
}
|
||||
|
||||
template <size_t TableIdx, typename Tp, size_t OpIdx, size_t... OpIdxTail>
|
||||
void
|
||||
update_table(Tp* _orig, std::index_sequence<OpIdx, OpIdxTail...>)
|
||||
{
|
||||
update_table<TableIdx>(_orig, std::integral_constant<size_t, OpIdx>{});
|
||||
if constexpr(sizeof...(OpIdxTail) > 0)
|
||||
update_table<TableIdx>(_orig, std::index_sequence<OpIdxTail...>{});
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// check out the assembly here... this compiles to a switch statement
|
||||
template <size_t TableIdx>
|
||||
const char*
|
||||
name_by_id(uint32_t id)
|
||||
{
|
||||
return name_by_id<TableIdx>(id, std::make_index_sequence<api_id_bounds<TableIdx>::last>{});
|
||||
}
|
||||
|
||||
template <size_t TableIdx>
|
||||
uint32_t
|
||||
id_by_name(const char* name)
|
||||
{
|
||||
return id_by_name<TableIdx>(name, std::make_index_sequence<api_id_bounds<TableIdx>::last>{});
|
||||
}
|
||||
|
||||
template <size_t TableIdx>
|
||||
std::vector<uint32_t>
|
||||
get_ids()
|
||||
{
|
||||
constexpr auto last_api_id = api_id_bounds<TableIdx>::last;
|
||||
auto _data = std::vector<uint32_t>{};
|
||||
_data.reserve(last_api_id);
|
||||
get_ids<TableIdx>(_data, std::make_index_sequence<last_api_id>{});
|
||||
return _data;
|
||||
}
|
||||
|
||||
template <size_t TableIdx>
|
||||
std::vector<const char*>
|
||||
get_names()
|
||||
{
|
||||
constexpr auto last_api_id = api_id_bounds<TableIdx>::last;
|
||||
auto _data = std::vector<const char*>{};
|
||||
_data.reserve(last_api_id);
|
||||
get_names<TableIdx>(_data, std::make_index_sequence<last_api_id>{});
|
||||
return _data;
|
||||
}
|
||||
|
||||
void
|
||||
iterate_args(uint32_t id,
|
||||
const rocprofiler_callback_tracing_marker_api_data_t& data,
|
||||
rocprofiler_callback_tracing_operation_args_cb_t callback,
|
||||
void* user_data)
|
||||
{
|
||||
if(callback)
|
||||
iterate_args(id,
|
||||
data,
|
||||
callback,
|
||||
user_data,
|
||||
std::make_index_sequence<ROCPROFILER_MARKER_API_ID_LAST>{});
|
||||
}
|
||||
|
||||
#define INSTANTIATE_MARKER_TABLE_FUNC(TABLE) \
|
||||
template const char* name_by_id<TABLE>(uint32_t); \
|
||||
template uint32_t id_by_name<TABLE>(const char*); \
|
||||
template std::vector<uint32_t> get_ids<TABLE>(); \
|
||||
template std::vector<const char*> get_names<TABLE>();
|
||||
|
||||
INSTANTIATE_MARKER_TABLE_FUNC(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi)
|
||||
|
||||
void
|
||||
copy_table(roctx_api_table_t* _orig)
|
||||
{
|
||||
if(_orig)
|
||||
copy_table<ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi>(
|
||||
_orig, std::make_index_sequence<ROCPROFILER_MARKER_API_ID_LAST>{});
|
||||
}
|
||||
|
||||
void
|
||||
update_table(roctx_api_table_t* _orig)
|
||||
{
|
||||
if(_orig)
|
||||
update_table<ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi>(
|
||||
_orig, std::make_index_sequence<ROCPROFILER_MARKER_API_ID_LAST>{});
|
||||
}
|
||||
} // namespace marker
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,65 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. 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 "lib/rocprofiler-sdk/marker/defines.hpp"
|
||||
#include "lib/rocprofiler-sdk/marker/marker.hpp"
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace marker
|
||||
{
|
||||
template <>
|
||||
struct roctx_domain_info<ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi>
|
||||
{
|
||||
static constexpr auto callback_domain_idx = ROCPROFILER_CALLBACK_TRACING_MARKER_API;
|
||||
static constexpr auto buffered_domain_idx = ROCPROFILER_BUFFER_TRACING_MARKER_API;
|
||||
using args_type = rocprofiler_marker_api_args_t;
|
||||
using retval_type = rocprofiler_marker_api_retval_t;
|
||||
using callback_data_type = rocprofiler_callback_tracing_marker_api_data_t;
|
||||
};
|
||||
} // namespace marker
|
||||
} // namespace rocprofiler
|
||||
|
||||
#if defined(ROCPROFILER_LIB_ROCPROFILER_MARKER_MARKER_CPP_IMPL) && \
|
||||
ROCPROFILER_LIB_ROCPROFILER_MARKER_MARKER_CPP_IMPL == 1
|
||||
|
||||
// clang-format off
|
||||
MARKER_API_TABLE_LOOKUP_DEFINITION(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, roctx_api_table_t)
|
||||
|
||||
MARKER_API_INFO_DEFINITION_V(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, ROCPROFILER_MARKER_API_ID_roctxMarkA, roctxMarkA, roctxMarkA_fn, message)
|
||||
MARKER_API_INFO_DEFINITION_V(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, ROCPROFILER_MARKER_API_ID_roctxRangePushA, roctxRangePushA, roctxRangePushA_fn, message)
|
||||
MARKER_API_INFO_DEFINITION_0(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, ROCPROFILER_MARKER_API_ID_roctxRangePop, roctxRangePop, roctxRangePop_fn)
|
||||
MARKER_API_INFO_DEFINITION_V(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, ROCPROFILER_MARKER_API_ID_roctxRangeStartA, roctxRangeStartA, roctxRangeStartA_fn, message)
|
||||
MARKER_API_INFO_DEFINITION_V(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, ROCPROFILER_MARKER_API_ID_roctxRangeStop, roctxRangeStop, roctxRangeStop_fn, id)
|
||||
MARKER_API_INFO_DEFINITION_V(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, ROCPROFILER_MARKER_API_ID_roctxProfilerPause, roctxProfilerPause, roctxProfilerPause_fn, tid)
|
||||
MARKER_API_INFO_DEFINITION_V(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, ROCPROFILER_MARKER_API_ID_roctxProfilerResume, roctxProfilerResume, roctxProfilerResume_fn, tid)
|
||||
MARKER_API_INFO_DEFINITION_V(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, ROCPROFILER_MARKER_API_ID_roctxNameOsThread, roctxNameOsThread, roctxNameOsThread_fn, name)
|
||||
MARKER_API_INFO_DEFINITION_V(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, ROCPROFILER_MARKER_API_ID_roctxNameHsaAgent, roctxNameHsaAgent, roctxNameHsaAgent_fn, name, agent)
|
||||
MARKER_API_INFO_DEFINITION_V(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, ROCPROFILER_MARKER_API_ID_roctxNameHipDevice, roctxNameHipDevice, roctxNameHipDevice_fn, name, device_id)
|
||||
MARKER_API_INFO_DEFINITION_V(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, ROCPROFILER_MARKER_API_ID_roctxNameHipStream, roctxNameHipStream, roctxNameHipStream_fn, name, stream)
|
||||
MARKER_API_INFO_DEFINITION_V(ROCPROFILER_MARKER_API_TABLE_ID_RoctxApi, ROCPROFILER_MARKER_API_ID_roctxGetThreadId, roctxGetThreadId, roctxGetThreadId_fn, tid)
|
||||
// clang-format on
|
||||
|
||||
#else
|
||||
# error \
|
||||
"Do not compile this file directly. It is included by lib/rocprofiler-sdk/marker/marker.cpp"
|
||||
#endif
|
||||
@@ -0,0 +1,91 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <rocprofiler-sdk/rocprofiler.h>
|
||||
|
||||
#include <rocprofiler-sdk-roctx/api_trace.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace marker
|
||||
{
|
||||
using roctx_api_table_t = ::roctxApiTable_t;
|
||||
|
||||
roctx_api_table_t&
|
||||
get_table();
|
||||
|
||||
template <size_t OpIdx>
|
||||
struct roctx_table_lookup;
|
||||
|
||||
template <size_t TableIdx>
|
||||
struct roctx_domain_info;
|
||||
|
||||
template <size_t TableIdx, size_t OpIdx>
|
||||
struct roctx_api_info;
|
||||
|
||||
template <size_t TableIdx, size_t OpIdx>
|
||||
struct roctx_api_impl : roctx_domain_info<TableIdx>
|
||||
{
|
||||
template <typename DataArgsT, typename... Args>
|
||||
static auto set_data_args(DataArgsT&, Args... args);
|
||||
|
||||
template <typename FuncT, typename... Args>
|
||||
static auto exec(FuncT&&, Args&&... args);
|
||||
|
||||
template <typename... Args>
|
||||
static auto functor(Args&&... args);
|
||||
};
|
||||
|
||||
template <size_t TableIdx>
|
||||
const char*
|
||||
name_by_id(uint32_t id);
|
||||
|
||||
template <size_t TableIdx>
|
||||
uint32_t
|
||||
id_by_name(const char* name);
|
||||
|
||||
void
|
||||
iterate_args(uint32_t id,
|
||||
const rocprofiler_callback_tracing_marker_api_data_t& data,
|
||||
rocprofiler_callback_tracing_operation_args_cb_t callback,
|
||||
void* user_data);
|
||||
|
||||
template <size_t TableIdx>
|
||||
std::vector<const char*>
|
||||
get_names();
|
||||
|
||||
template <size_t TableIdx>
|
||||
std::vector<uint32_t>
|
||||
get_ids();
|
||||
|
||||
void
|
||||
copy_table(roctx_api_table_t* _orig);
|
||||
|
||||
void
|
||||
update_table(roctx_api_table_t* _orig);
|
||||
} // namespace marker
|
||||
} // namespace rocprofiler
|
||||
@@ -0,0 +1,124 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <hsa/hsa.h>
|
||||
#include <rocprofiler-sdk/version.h>
|
||||
|
||||
#include "lib/common/mpl.hpp"
|
||||
|
||||
#include "fmt/core.h"
|
||||
#include "fmt/ranges.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace rocprofiler
|
||||
{
|
||||
namespace marker
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
template <typename Tp>
|
||||
auto
|
||||
stringize_impl(const Tp& _v)
|
||||
{
|
||||
using nonpointer_type = typename std::remove_pointer_t<Tp>;
|
||||
|
||||
if constexpr(common::mpl::is_pair<Tp>::value)
|
||||
{
|
||||
return std::make_pair(stringize_impl(_v.first), stringize_impl(_v.second));
|
||||
}
|
||||
else if constexpr(std::is_constructible<std::string_view, Tp>::value)
|
||||
{
|
||||
auto _ss = std::stringstream{};
|
||||
_ss << _v;
|
||||
return _ss.str();
|
||||
}
|
||||
else if constexpr(fmt::is_formattable<Tp>::value && !std::is_pointer<Tp>::value)
|
||||
{
|
||||
return fmt::format("{}", _v);
|
||||
}
|
||||
else if constexpr(std::is_pointer<Tp>::value && !std::is_pointer<nonpointer_type>::value &&
|
||||
common::mpl::is_type_complete_v<nonpointer_type> &&
|
||||
!std::is_void<nonpointer_type>::value)
|
||||
{
|
||||
if(_v)
|
||||
{
|
||||
return stringize_impl(*_v);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto _ss = std::stringstream{};
|
||||
_ss << _v;
|
||||
return _ss.str();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto _ss = std::stringstream{};
|
||||
_ss << _v;
|
||||
return _ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
auto
|
||||
stringize(Args... args)
|
||||
{
|
||||
return std::vector<std::pair<std::string, std::string>>{stringize_impl(args)...};
|
||||
}
|
||||
|
||||
template <typename Tp>
|
||||
struct handle_formatter
|
||||
{
|
||||
template <typename ParseContext>
|
||||
constexpr auto parse(ParseContext& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename Ctx>
|
||||
auto format(const Tp& v, Ctx& ctx) const
|
||||
{
|
||||
return fmt::format_to(ctx.out(), "handle={}", v.handle);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Tp>
|
||||
struct handle_formatter<const Tp> : handle_formatter<Tp>
|
||||
{};
|
||||
} // namespace utils
|
||||
} // namespace marker
|
||||
} // namespace rocprofiler
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
template <>
|
||||
struct formatter<hsa_agent_t> : rocprofiler::marker::utils::handle_formatter<hsa_agent_t>
|
||||
{};
|
||||
} // namespace fmt
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -36,15 +36,20 @@ set_tests_properties(${lib_TESTS} PROPERTIES TIMEOUT 45 LABELS "unittests")
|
||||
# -------------------------------------------------------------------------------------- #
|
||||
|
||||
set(rocprofiler_shared_lib_sources external_correlation.cpp intercept_table.cpp
|
||||
registration.cpp status.cpp)
|
||||
registration.cpp roctx.cpp status.cpp)
|
||||
|
||||
add_executable(rocprofiler-lib-tests-shared)
|
||||
target_sources(rocprofiler-lib-tests-shared PRIVATE ${rocprofiler_shared_lib_sources})
|
||||
target_link_libraries(
|
||||
rocprofiler-lib-tests-shared
|
||||
PRIVATE rocprofiler::rocprofiler-shared-library
|
||||
rocprofiler::rocprofiler-common-library rocprofiler::rocprofiler-hsa-runtime
|
||||
GTest::gtest GTest::gtest_main)
|
||||
rocprofiler::rocprofiler-common-library
|
||||
rocprofiler::rocprofiler-hsa-runtime
|
||||
rocprofiler::rocprofiler-sdk-roctx-shared-library
|
||||
GTest::gtest
|
||||
GTest::gtest_main)
|
||||
set_target_properties(rocprofiler-lib-tests-shared PROPERTIES BUILD_RPATH
|
||||
"\$ORIGIN/../lib")
|
||||
|
||||
gtest_add_tests(
|
||||
TARGET rocprofiler-lib-tests-shared
|
||||
@@ -52,7 +57,10 @@ gtest_add_tests(
|
||||
TEST_LIST shared_lib_TESTS
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(rocprofiler-lib-tests-env
|
||||
"HSA_TOOLS_LIB=$<TARGET_FILE:rocprofiler-shared-library>"
|
||||
"LD_LIBRARY_PATH=${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}:$ENV{LD_LIBRARY_PATH}")
|
||||
|
||||
set_tests_properties(
|
||||
${shared_lib_TESTS}
|
||||
PROPERTIES TIMEOUT 360 LABELS "unittests" ENVIRONMENT
|
||||
"HSA_TOOLS_LIB=$<TARGET_FILE:rocprofiler-shared-library>")
|
||||
${shared_lib_TESTS} PROPERTIES TIMEOUT 360 LABELS "unittests" ENVIRONMENT
|
||||
"${rocprofiler-lib-tests-env}")
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <rocprofiler-sdk/rocprofiler.h>
|
||||
|
||||
#include "lib/common/defines.hpp"
|
||||
#include "rocprofiler-sdk/fwd.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@@ -76,7 +77,7 @@ inline auto
|
||||
get_callback_tracing_names()
|
||||
{
|
||||
static const auto supported_kinds = std::unordered_set<rocprofiler_callback_tracing_kind_t>{
|
||||
ROCPROFILER_CALLBACK_TRACING_HSA_API};
|
||||
ROCPROFILER_CALLBACK_TRACING_HSA_API, ROCPROFILER_CALLBACK_TRACING_MARKER_API};
|
||||
|
||||
auto cb_name_info = callback_name_info{};
|
||||
//
|
||||
@@ -139,8 +140,8 @@ struct buffer_name_info
|
||||
inline buffer_name_info
|
||||
get_buffer_tracing_names()
|
||||
{
|
||||
static const auto supported_kinds =
|
||||
std::unordered_set<rocprofiler_buffer_tracing_kind_t>{ROCPROFILER_BUFFER_TRACING_HSA_API};
|
||||
static const auto supported_kinds = std::unordered_set<rocprofiler_buffer_tracing_kind_t>{
|
||||
ROCPROFILER_BUFFER_TRACING_HSA_API, ROCPROFILER_BUFFER_TRACING_MARKER_API};
|
||||
|
||||
auto cb_name_info = buffer_name_info{};
|
||||
//
|
||||
|
||||
@@ -0,0 +1,542 @@
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2023 Advanced Micro Devices, Inc. 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 <hsa/hsa.h>
|
||||
#include <rocprofiler-sdk-roctx/roctx.h>
|
||||
#include <rocprofiler-sdk/buffer.h>
|
||||
#include <rocprofiler-sdk/fwd.h>
|
||||
#include <rocprofiler-sdk/registration.h>
|
||||
#include <rocprofiler-sdk/rocprofiler.h>
|
||||
|
||||
#include "lib/common/defines.hpp"
|
||||
#include "lib/common/environment.hpp"
|
||||
#include "lib/common/filesystem.hpp"
|
||||
#include "lib/common/units.hpp"
|
||||
#include "lib/common/utility.hpp"
|
||||
#include "lib/rocprofiler-sdk/tests/common.hpp"
|
||||
#include "rocprofiler-sdk-roctx/api_trace.h"
|
||||
#include "rocprofiler-sdk-roctx/types.h"
|
||||
#include "rocprofiler-sdk/callback_tracing.h"
|
||||
#include "rocprofiler-sdk/context.h"
|
||||
#include "rocprofiler-sdk/marker/api_id.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
#define ROCTX_CALL(ARG, MSG) \
|
||||
{ \
|
||||
auto _status = (ARG); \
|
||||
EXPECT_EQ(_status, 0) << MSG << " :: " << #ARG; \
|
||||
}
|
||||
|
||||
void
|
||||
run_roctx_functions()
|
||||
{
|
||||
auto roctx_tid = roctx_thread_id_t{};
|
||||
auto rocp_tid = rocprofiler_thread_id_t{};
|
||||
auto hsa_agent = hsa_agent_t{.handle = roctx_tid};
|
||||
auto* hip_stream = hipStream_t{};
|
||||
|
||||
roctxGetThreadId(&roctx_tid);
|
||||
rocprofiler_get_thread_id(&rocp_tid);
|
||||
|
||||
EXPECT_EQ(roctx_tid, rocp_tid);
|
||||
roctxNameOsThread(std::to_string(roctx_tid).c_str());
|
||||
roctxNameHsaAgent("hsa_agent", &hsa_agent);
|
||||
roctxNameHipDevice("hip_device", 0);
|
||||
roctxNameHipStream("hip_device", hip_stream);
|
||||
|
||||
roctxProfilerPause(roctx_tid);
|
||||
roctxMark(__FUNCTION__);
|
||||
roctxProfilerResume(roctx_tid);
|
||||
|
||||
ROCTX_CALL(roctxRangePush(__FUNCTION__), "push failed");
|
||||
ROCTX_CALL(roctxRangePop(), "pop failed");
|
||||
|
||||
auto range_id = roctxRangeStart(__FUNCTION__);
|
||||
EXPECT_GE(range_id, 0);
|
||||
roctxRangeStop(range_id);
|
||||
}
|
||||
|
||||
void
|
||||
tool_tracing_ctrl_callback(rocprofiler_callback_tracing_record_t record,
|
||||
rocprofiler_user_data_t*,
|
||||
void* client_data)
|
||||
{
|
||||
auto* cb_data = static_cast<callback_data*>(client_data);
|
||||
|
||||
if(record.phase == ROCPROFILER_CALLBACK_PHASE_ENTER &&
|
||||
record.kind == ROCPROFILER_CALLBACK_TRACING_MARKER_API &&
|
||||
record.operation == ROCPROFILER_MARKER_API_ID_roctxProfilerPause)
|
||||
{
|
||||
ROCPROFILER_CALL(rocprofiler_stop_context(cb_data->client_ctx), "pausing client context");
|
||||
}
|
||||
else if(record.phase == ROCPROFILER_CALLBACK_PHASE_EXIT &&
|
||||
record.kind == ROCPROFILER_CALLBACK_TRACING_MARKER_API &&
|
||||
record.operation == ROCPROFILER_MARKER_API_ID_roctxProfilerResume)
|
||||
{
|
||||
ROCPROFILER_CALL(rocprofiler_start_context(cb_data->client_ctx), "resuming client context");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tool_tracing_callback(rocprofiler_callback_tracing_record_t record,
|
||||
rocprofiler_user_data_t* user_data,
|
||||
void* client_data)
|
||||
{
|
||||
auto* cb_data = static_cast<callback_data*>(client_data);
|
||||
auto get_timestamp = []() {
|
||||
return std::chrono::steady_clock::now().time_since_epoch().count();
|
||||
};
|
||||
|
||||
if(record.phase == ROCPROFILER_CALLBACK_PHASE_ENTER && cb_data->current_depth == 0)
|
||||
{
|
||||
user_data->value = get_timestamp();
|
||||
}
|
||||
|
||||
static auto name_map = get_callback_tracing_names();
|
||||
|
||||
EXPECT_EQ(name_map.kind_names.size(), ROCPROFILER_CALLBACK_TRACING_LAST);
|
||||
EXPECT_EQ(name_map.operation_names.at(ROCPROFILER_CALLBACK_TRACING_MARKER_API).size(),
|
||||
ROCPROFILER_MARKER_API_ID_LAST);
|
||||
|
||||
std::cout << "[" << __FILE__ << ":" << __LINE__ << "] "
|
||||
<< name_map.operation_names[record.kind][record.operation] << "\n"
|
||||
<< std::flush;
|
||||
|
||||
cb_data->client_callback_count++;
|
||||
if(record.phase == ROCPROFILER_CALLBACK_PHASE_ENTER)
|
||||
{
|
||||
cb_data->current_depth++;
|
||||
}
|
||||
else if(record.phase == ROCPROFILER_CALLBACK_PHASE_EXIT)
|
||||
{
|
||||
cb_data->max_depth = std::max(cb_data->current_depth, cb_data->max_depth);
|
||||
cb_data->current_depth--;
|
||||
}
|
||||
else
|
||||
{
|
||||
GTEST_FAIL() << "unsupported callback tracing phase " << record.phase;
|
||||
}
|
||||
|
||||
struct info_data
|
||||
{
|
||||
uint64_t num_args = 0;
|
||||
std::stringstream arg_ss;
|
||||
} info_data_v;
|
||||
|
||||
auto info_data_cb = [](rocprofiler_callback_tracing_kind_t,
|
||||
uint32_t,
|
||||
uint32_t arg_num,
|
||||
const char* arg_name,
|
||||
const char* arg_value_str,
|
||||
const void* const arg_value_addr,
|
||||
void* data) -> int {
|
||||
auto& info = *static_cast<info_data*>(data);
|
||||
info.arg_ss << ((arg_num == 0) ? "(" : ", ");
|
||||
info.arg_ss << arg_num << ": " << arg_name << "=" << arg_value_str;
|
||||
EXPECT_NE(arg_name, nullptr);
|
||||
EXPECT_NE(arg_value_str, nullptr);
|
||||
EXPECT_NE(arg_value_addr, nullptr);
|
||||
EXPECT_EQ(arg_num, info.num_args);
|
||||
info.num_args++;
|
||||
return 0;
|
||||
};
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_iterate_callback_tracing_kind_operation_args(
|
||||
record, info_data_cb, static_cast<void*>(&info_data_v)),
|
||||
"Failure iterating trace operation args");
|
||||
if(record.kind == ROCPROFILER_CALLBACK_TRACING_MARKER_API)
|
||||
{
|
||||
if(record.operation != ROCPROFILER_MARKER_API_ID_roctxRangePop)
|
||||
{
|
||||
EXPECT_GT(info_data_v.num_args, 0)
|
||||
<< name_map.operation_names[record.kind][record.operation]
|
||||
<< info_data_v.arg_ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
if(record.phase == ROCPROFILER_CALLBACK_PHASE_EXIT && cb_data->current_depth == 0)
|
||||
{
|
||||
cb_data->client_elapsed += (get_timestamp() - user_data->value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tool_tracing_buffered(rocprofiler_context_id_t context,
|
||||
rocprofiler_buffer_id_t buffer_id,
|
||||
rocprofiler_record_header_t** headers,
|
||||
size_t num_headers,
|
||||
void* buffer_data,
|
||||
uint64_t drop_count)
|
||||
{
|
||||
auto* cb_data = static_cast<callback_data*>(buffer_data);
|
||||
|
||||
static auto name_map = get_buffer_tracing_names();
|
||||
|
||||
EXPECT_EQ(name_map.kind_names.size(), ROCPROFILER_BUFFER_TRACING_LAST);
|
||||
EXPECT_EQ(name_map.operation_names.at(ROCPROFILER_BUFFER_TRACING_MARKER_API).size(),
|
||||
ROCPROFILER_MARKER_API_ID_LAST);
|
||||
|
||||
auto v_records = std::vector<rocprofiler_buffer_tracing_marker_api_record_t*>{};
|
||||
v_records.reserve(num_headers);
|
||||
|
||||
for(size_t i = 0; i < num_headers; ++i)
|
||||
{
|
||||
auto* header = headers[i];
|
||||
|
||||
ASSERT_TRUE(header != nullptr);
|
||||
auto hash = rocprofiler_record_header_compute_hash(header->category, header->kind);
|
||||
EXPECT_EQ(header->hash, hash);
|
||||
EXPECT_TRUE(header->category == ROCPROFILER_BUFFER_CATEGORY_TRACING &&
|
||||
header->kind == ROCPROFILER_BUFFER_TRACING_MARKER_API);
|
||||
|
||||
v_records.emplace_back(
|
||||
static_cast<rocprofiler_buffer_tracing_marker_api_record_t*>(header->payload));
|
||||
}
|
||||
|
||||
std::sort(v_records.begin(), v_records.end(), [](auto lhs, auto rhs) {
|
||||
return (lhs->start_timestamp == rhs->start_timestamp)
|
||||
? (lhs->end_timestamp < rhs->end_timestamp)
|
||||
: (lhs->start_timestamp < rhs->start_timestamp);
|
||||
});
|
||||
|
||||
for(auto* record : v_records)
|
||||
{
|
||||
auto info = std::stringstream{};
|
||||
info << "tid=" << record->thread_id << ", context=" << context.handle
|
||||
<< ", buffer_id=" << buffer_id.handle << ", cid=" << record->correlation_id.internal
|
||||
<< ", kind=" << name_map.kind_names.at(record->kind) << "(" << record->kind
|
||||
<< "), operation=" << name_map.operation_names.at(record->kind).at(record->operation)
|
||||
<< "(" << record->operation << "), drop_count=" << drop_count
|
||||
<< ", start=" << record->start_timestamp << ", stop=" << record->end_timestamp;
|
||||
|
||||
static int64_t last_corr_id = -1;
|
||||
auto corr_id = static_cast<int64_t>(record->correlation_id.internal);
|
||||
|
||||
std::cout << info.str() << "\n" << std::flush;
|
||||
EXPECT_GE(context.handle, 0) << info.str();
|
||||
EXPECT_GT(record->thread_id, 0) << info.str();
|
||||
EXPECT_GT(record->kind, 0) << info.str();
|
||||
EXPECT_GT(corr_id, last_corr_id) << info.str();
|
||||
EXPECT_GT(record->start_timestamp, 0) << info.str();
|
||||
EXPECT_GT(record->end_timestamp, 0) << info.str();
|
||||
EXPECT_LE(record->start_timestamp, record->end_timestamp) << info.str();
|
||||
|
||||
cb_data->client_callback_count++;
|
||||
last_corr_id = corr_id;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
thread_precreate(rocprofiler_runtime_library_t /*lib*/, void* tool_data)
|
||||
{
|
||||
auto* cb_data = static_cast<callback_data*>(tool_data);
|
||||
cb_data->client_workflow_count++;
|
||||
}
|
||||
|
||||
void
|
||||
thread_postcreate(rocprofiler_runtime_library_t /*lib*/, void* tool_data)
|
||||
{
|
||||
auto* cb_data = static_cast<callback_data*>(tool_data);
|
||||
cb_data->client_workflow_count++;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(rocprofiler_lib, roctx_callback_tracing)
|
||||
{
|
||||
using init_func_t = int (*)(rocprofiler_client_finalize_t, void*);
|
||||
using fini_func_t = void (*)(void*);
|
||||
|
||||
auto cmd_line = rocprofiler::common::read_command_line(getpid());
|
||||
|
||||
ASSERT_FALSE(cmd_line.empty());
|
||||
|
||||
static init_func_t tool_init = [](rocprofiler_client_finalize_t fini_func,
|
||||
void* client_data) -> int {
|
||||
auto* cb_data = static_cast<callback_data*>(client_data);
|
||||
|
||||
cb_data->client_workflow_count++;
|
||||
cb_data->client_fini_func = fini_func;
|
||||
|
||||
auto pause_resume_ctx = rocprofiler_context_id_t{};
|
||||
ROCPROFILER_CALL(rocprofiler_create_context(&pause_resume_ctx), "failed to create context");
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_create_context(&cb_data->client_ctx),
|
||||
"failed to create context");
|
||||
|
||||
auto operations = std::vector<uint32_t>{};
|
||||
rocprofiler_iterate_callback_tracing_kind_operations(
|
||||
ROCPROFILER_CALLBACK_TRACING_MARKER_API,
|
||||
[](rocprofiler_callback_tracing_kind_t, uint32_t operation, void* data) {
|
||||
auto* _ops = static_cast<std::vector<uint32_t>*>(data);
|
||||
if(operation != ROCPROFILER_MARKER_API_ID_roctxProfilerPause &&
|
||||
operation != ROCPROFILER_MARKER_API_ID_roctxProfilerResume)
|
||||
_ops->emplace_back(operation);
|
||||
return 0;
|
||||
},
|
||||
&operations);
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_configure_callback_tracing_service(cb_data->client_ctx,
|
||||
ROCPROFILER_CALLBACK_TRACING_MARKER_API,
|
||||
operations.data(),
|
||||
operations.size(),
|
||||
tool_tracing_callback,
|
||||
client_data),
|
||||
"callback tracing service failed to configure");
|
||||
|
||||
auto pause_resume_ops =
|
||||
std::array<uint32_t, 2>{ROCPROFILER_MARKER_API_ID_roctxProfilerPause,
|
||||
ROCPROFILER_MARKER_API_ID_roctxProfilerResume};
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_configure_callback_tracing_service(pause_resume_ctx,
|
||||
ROCPROFILER_CALLBACK_TRACING_MARKER_API,
|
||||
pause_resume_ops.data(),
|
||||
pause_resume_ops.size(),
|
||||
tool_tracing_ctrl_callback,
|
||||
client_data),
|
||||
"callback tracing service failed to configure");
|
||||
|
||||
int valid_ctx = 0;
|
||||
ROCPROFILER_CALL(rocprofiler_context_is_valid(cb_data->client_ctx, &valid_ctx),
|
||||
"failure checking context validity");
|
||||
|
||||
EXPECT_EQ(valid_ctx, 1);
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_start_context(pause_resume_ctx),
|
||||
"rocprofiler context start failed");
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_start_context(cb_data->client_ctx),
|
||||
"rocprofiler context start failed");
|
||||
|
||||
// no errors
|
||||
return 0;
|
||||
};
|
||||
|
||||
static fini_func_t tool_fini = [](void* client_data) -> void {
|
||||
auto* cb_data = static_cast<callback_data*>(client_data);
|
||||
ROCPROFILER_CALL(rocprofiler_stop_context(cb_data->client_ctx),
|
||||
"rocprofiler context stop failed");
|
||||
|
||||
static_cast<callback_data*>(client_data)->client_workflow_count++;
|
||||
};
|
||||
|
||||
static auto cb_data = callback_data{};
|
||||
|
||||
static auto cfg_result =
|
||||
rocprofiler_tool_configure_result_t{sizeof(rocprofiler_tool_configure_result_t),
|
||||
tool_init,
|
||||
tool_fini,
|
||||
static_cast<void*>(&cb_data)};
|
||||
|
||||
static rocprofiler_configure_func_t rocp_init =
|
||||
[](uint32_t version,
|
||||
const char* runtime_version,
|
||||
uint32_t prio,
|
||||
rocprofiler_client_id_t* client_id) -> rocprofiler_tool_configure_result_t* {
|
||||
auto expected_version = ROCPROFILER_VERSION;
|
||||
EXPECT_EQ(expected_version, version);
|
||||
EXPECT_EQ(std::string_view{runtime_version}, std::string_view{ROCPROFILER_VERSION_STRING});
|
||||
EXPECT_EQ(prio, 0);
|
||||
EXPECT_EQ(client_id->name, nullptr);
|
||||
cb_data.client_id = client_id;
|
||||
cb_data.client_id->name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
|
||||
return &cfg_result;
|
||||
};
|
||||
|
||||
EXPECT_EQ(rocprofiler_force_configure(rocp_init), ROCPROFILER_STATUS_SUCCESS);
|
||||
|
||||
run_roctx_functions();
|
||||
|
||||
ASSERT_NE(cb_data.client_id, nullptr);
|
||||
ASSERT_NE(cb_data.client_fini_func, nullptr);
|
||||
|
||||
cb_data.client_fini_func(*cb_data.client_id);
|
||||
|
||||
// expected callback count is two for hsa_iterate_agents and two callbacks for
|
||||
// hsa_agent_get_info for each agent.
|
||||
constexpr uint64_t expected_cb_count = 18;
|
||||
|
||||
EXPECT_EQ(cb_data.client_workflow_count, 2);
|
||||
EXPECT_EQ(cb_data.client_callback_count, expected_cb_count);
|
||||
EXPECT_EQ(cb_data.current_depth, 0);
|
||||
EXPECT_EQ(cb_data.max_depth, 1);
|
||||
}
|
||||
|
||||
TEST(rocprofiler_lib, roctx_buffered_tracing)
|
||||
{
|
||||
using init_func_t = int (*)(rocprofiler_client_finalize_t, void*);
|
||||
using fini_func_t = void (*)(void*);
|
||||
|
||||
auto cmd_line = rocprofiler::common::read_command_line(getpid());
|
||||
ASSERT_FALSE(cmd_line.empty());
|
||||
|
||||
static init_func_t tool_init = [](rocprofiler_client_finalize_t fini_func,
|
||||
void* client_data) -> int {
|
||||
auto* cb_data = static_cast<callback_data*>(client_data);
|
||||
|
||||
cb_data->client_workflow_count++;
|
||||
cb_data->client_fini_func = fini_func;
|
||||
|
||||
auto pause_resume_ctx = rocprofiler_context_id_t{};
|
||||
auto pause_resume_ops =
|
||||
std::array<uint32_t, 2>{ROCPROFILER_MARKER_API_ID_roctxProfilerPause,
|
||||
ROCPROFILER_MARKER_API_ID_roctxProfilerResume};
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_create_context(&pause_resume_ctx), "failed to create context");
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_configure_callback_tracing_service(pause_resume_ctx,
|
||||
ROCPROFILER_CALLBACK_TRACING_MARKER_API,
|
||||
pause_resume_ops.data(),
|
||||
pause_resume_ops.size(),
|
||||
tool_tracing_ctrl_callback,
|
||||
client_data),
|
||||
"callback tracing service failed to configure");
|
||||
ROCPROFILER_CALL(rocprofiler_start_context(pause_resume_ctx),
|
||||
"rocprofiler context start failed");
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_create_context(&cb_data->client_ctx),
|
||||
"failed to create context");
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_create_buffer(cb_data->client_ctx,
|
||||
4096,
|
||||
2048,
|
||||
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
|
||||
tool_tracing_buffered,
|
||||
client_data,
|
||||
&cb_data->client_buffer),
|
||||
"buffer creation failed");
|
||||
|
||||
auto operations = std::vector<uint32_t>{};
|
||||
rocprofiler_iterate_buffer_tracing_kind_operations(
|
||||
ROCPROFILER_BUFFER_TRACING_MARKER_API,
|
||||
[](rocprofiler_buffer_tracing_kind_t, uint32_t operation, void* data) {
|
||||
auto* _ops = static_cast<std::vector<uint32_t>*>(data);
|
||||
if(operation != ROCPROFILER_MARKER_API_ID_roctxProfilerPause &&
|
||||
operation != ROCPROFILER_MARKER_API_ID_roctxProfilerResume)
|
||||
_ops->emplace_back(operation);
|
||||
return 0;
|
||||
},
|
||||
&operations);
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_configure_buffer_tracing_service(cb_data->client_ctx,
|
||||
ROCPROFILER_BUFFER_TRACING_MARKER_API,
|
||||
operations.data(),
|
||||
operations.size(),
|
||||
cb_data->client_buffer),
|
||||
"buffer tracing service failed to configure");
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_create_callback_thread(&cb_data->client_thread),
|
||||
"failure creating callback thread");
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_assign_callback_thread(cb_data->client_buffer, cb_data->client_thread),
|
||||
"failed to assign thread for buffer");
|
||||
|
||||
int valid_ctx = 0;
|
||||
ROCPROFILER_CALL(rocprofiler_context_is_valid(cb_data->client_ctx, &valid_ctx),
|
||||
"failure checking context validity");
|
||||
|
||||
EXPECT_EQ(valid_ctx, 1);
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_start_context(cb_data->client_ctx),
|
||||
"rocprofiler context start failed");
|
||||
|
||||
// no errors
|
||||
return 0;
|
||||
};
|
||||
|
||||
static fini_func_t tool_fini = [](void* client_data) -> void {
|
||||
auto* cb_data = static_cast<callback_data*>(client_data);
|
||||
ROCPROFILER_CALL(rocprofiler_flush_buffer(cb_data->client_buffer),
|
||||
"rocprofiler context stop failed");
|
||||
ROCPROFILER_CALL(rocprofiler_stop_context(cb_data->client_ctx),
|
||||
"rocprofiler context stop failed");
|
||||
|
||||
static_cast<callback_data*>(client_data)->client_workflow_count++;
|
||||
};
|
||||
|
||||
static auto cb_data = callback_data{};
|
||||
|
||||
static auto cfg_result =
|
||||
rocprofiler_tool_configure_result_t{sizeof(rocprofiler_tool_configure_result_t),
|
||||
tool_init,
|
||||
tool_fini,
|
||||
static_cast<void*>(&cb_data)};
|
||||
|
||||
static rocprofiler_configure_func_t rocp_init =
|
||||
[](uint32_t version,
|
||||
const char* runtime_version,
|
||||
uint32_t prio,
|
||||
rocprofiler_client_id_t* client_id) -> rocprofiler_tool_configure_result_t* {
|
||||
auto expected_version = ROCPROFILER_VERSION;
|
||||
EXPECT_EQ(expected_version, version);
|
||||
EXPECT_EQ(std::string_view{runtime_version}, std::string_view{ROCPROFILER_VERSION_STRING});
|
||||
EXPECT_EQ(prio, 0);
|
||||
EXPECT_EQ(client_id->name, nullptr);
|
||||
cb_data.client_id = client_id;
|
||||
cb_data.client_id->name = ::testing::UnitTest::GetInstance()->current_test_info()->name();
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_at_internal_thread_create(thread_precreate,
|
||||
thread_postcreate,
|
||||
ROCPROFILER_LIBRARY,
|
||||
static_cast<void*>(&cb_data)),
|
||||
"failed to register for thread creation notifications");
|
||||
|
||||
return &cfg_result;
|
||||
};
|
||||
|
||||
EXPECT_EQ(rocprofiler_force_configure(rocp_init), ROCPROFILER_STATUS_SUCCESS);
|
||||
|
||||
run_roctx_functions();
|
||||
|
||||
ASSERT_NE(cb_data.client_id, nullptr);
|
||||
ASSERT_NE(cb_data.client_fini_func, nullptr);
|
||||
|
||||
cb_data.client_fini_func(*cb_data.client_id);
|
||||
|
||||
constexpr uint64_t expected_cb_count = 9;
|
||||
|
||||
EXPECT_EQ(cb_data.client_workflow_count, 6);
|
||||
EXPECT_EQ(cb_data.client_callback_count, expected_cb_count);
|
||||
EXPECT_EQ(cb_data.current_depth, 0);
|
||||
EXPECT_EQ(cb_data.max_depth, 0);
|
||||
}
|
||||
@@ -5,6 +5,10 @@ cmake_minimum_required(VERSION 3.21.0 FATAL_ERROR)
|
||||
|
||||
project(rocprofiler-test-apps LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_BUILD_RPATH
|
||||
"\$ORIGIN:\$ORIGIN/../lib:$<TARGET_FILE_DIR:rocprofiler-sdk-roctx::rocprofiler-sdk-roctx-shared-library>"
|
||||
)
|
||||
|
||||
# applications used by integration tests
|
||||
add_subdirectory(reproducible-runtime)
|
||||
add_subdirectory(transpose)
|
||||
|
||||
@@ -43,6 +43,10 @@ target_compile_options(reproducible-runtime PRIVATE -W -Wall -Wextra -Wpedantic
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(reproducible-runtime PRIVATE Threads::Threads)
|
||||
|
||||
find_package(rocprofiler-sdk-roctx REQUIRED)
|
||||
target_link_libraries(reproducible-runtime
|
||||
PRIVATE rocprofiler-sdk-roctx::rocprofiler-sdk-roctx)
|
||||
|
||||
if(REPRODUCIBLE_RUNTIME_USE_MPI)
|
||||
find_package(MPI REQUIRED)
|
||||
target_compile_definitions(reproducible-runtime PRIVATE USE_MPI)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include "hip/hip_runtime.h"
|
||||
#include "rocprofiler-sdk-roctx/roctx.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <chrono>
|
||||
@@ -124,6 +125,8 @@ reproducible_runtime(uint32_t nspin_v)
|
||||
void
|
||||
run(int tid, int devid)
|
||||
{
|
||||
auto roctx_range_id = roctxRangeStart("run");
|
||||
|
||||
constexpr int min_sa = 8;
|
||||
constexpr int min_avail_simd = 24;
|
||||
dim3 grid(min_sa * min_avail_simd);
|
||||
@@ -140,6 +143,7 @@ run(int tid, int devid)
|
||||
|
||||
do
|
||||
{
|
||||
roctxMark("iteration");
|
||||
uint32_t cyclesleft = 2000 * 1000 * (nruntime - static_cast<double>(time));
|
||||
HIP_API_CALL(hipEventRecord(start, stream));
|
||||
reproducible_runtime<<<grid, block, 0, stream>>>(std::min<uint32_t>(nspin, cyclesleft));
|
||||
@@ -166,6 +170,8 @@ run(int tid, int devid)
|
||||
|
||||
HIP_API_CALL(hipStreamSynchronize(stream));
|
||||
HIP_API_CALL(hipStreamDestroy(stream));
|
||||
|
||||
roctxRangeStop(roctx_range_id);
|
||||
}
|
||||
|
||||
namespace
|
||||
|
||||
@@ -42,6 +42,9 @@ target_compile_options(transpose PRIVATE -W -Wall -Wextra -Wpedantic -Wshadow -W
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(transpose PRIVATE Threads::Threads)
|
||||
|
||||
find_package(rocprofiler-sdk-roctx REQUIRED)
|
||||
target_link_libraries(transpose PRIVATE rocprofiler-sdk-roctx::rocprofiler-sdk-roctx)
|
||||
|
||||
if(TRANSPOSE_USE_MPI)
|
||||
find_package(MPI REQUIRED)
|
||||
target_compile_definitions(transpose PRIVATE USE_MPI)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
// THE SOFTWARE.
|
||||
|
||||
#include "hip/hip_runtime.h"
|
||||
#include "rocprofiler-sdk-roctx/roctx.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
@@ -173,6 +174,8 @@ transpose(const int* in, int* out, int M, int N)
|
||||
void
|
||||
run(int rank, int tid, int devid, int argc, char** argv)
|
||||
{
|
||||
roctxRangePush("run");
|
||||
|
||||
constexpr unsigned int M = 4960 * 2;
|
||||
constexpr unsigned int N = 4960 * 2;
|
||||
|
||||
@@ -243,6 +246,8 @@ run(int rank, int tid, int devid, int argc, char** argv)
|
||||
|
||||
delete[] inp_matrix;
|
||||
delete[] out_matrix;
|
||||
|
||||
roctxRangePop();
|
||||
}
|
||||
|
||||
namespace
|
||||
|
||||
@@ -19,17 +19,17 @@ endif()
|
||||
|
||||
add_test(NAME test-async-copy-tracing-execute COMMAND $<TARGET_FILE:transpose>)
|
||||
|
||||
set(async-copy-tracing-env
|
||||
"${PRELOAD_ENV}"
|
||||
"HSA_TOOLS_LIB=$<TARGET_FILE:rocprofiler::rocprofiler-shared-library>"
|
||||
"ROCPROFILER_TOOL_OUTPUT_FILE=async-copy-tracing-test.json"
|
||||
"LD_LIBRARY_PATH=$<TARGET_FILE_DIR:rocprofiler::rocprofiler-shared-library>:$ENV{LD_LIBRARY_PATH}"
|
||||
)
|
||||
|
||||
set_tests_properties(
|
||||
test-async-copy-tracing-execute
|
||||
PROPERTIES
|
||||
TIMEOUT
|
||||
45
|
||||
LABELS
|
||||
"integration-tests"
|
||||
ENVIRONMENT
|
||||
"${PRELOAD_ENV};HSA_TOOLS_LIB=$<TARGET_FILE:rocprofiler::rocprofiler-shared-library>;ROCPROFILER_TOOL_OUTPUT_FILE=async-copy-tracing-test.json"
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"threw an exception")
|
||||
PROPERTIES TIMEOUT 45 LABELS "integration-tests" ENVIRONMENT
|
||||
"${async-copy-tracing-env}" FAIL_REGULAR_EXPRESSION "threw an exception")
|
||||
|
||||
foreach(FILENAME validate.py pytest.ini conftest.py)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}
|
||||
|
||||
@@ -16,45 +16,50 @@ def test_data_structure(input_data):
|
||||
data = input_data
|
||||
|
||||
node_exists("rocprofiler-sdk-json-tool", data)
|
||||
node_exists("agents", data["rocprofiler-sdk-json-tool"])
|
||||
node_exists("call_stack", data["rocprofiler-sdk-json-tool"])
|
||||
node_exists("callback_records", data["rocprofiler-sdk-json-tool"])
|
||||
node_exists("buffer_records", data["rocprofiler-sdk-json-tool"])
|
||||
|
||||
node_exists("names", data["rocprofiler-sdk-json-tool"]["callback_records"])
|
||||
node_exists("code_objects", data["rocprofiler-sdk-json-tool"]["callback_records"])
|
||||
node_exists("kernel_symbols", data["rocprofiler-sdk-json-tool"]["callback_records"])
|
||||
node_exists("hsa_api_traces", data["rocprofiler-sdk-json-tool"]["callback_records"])
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
node_exists("names", data["rocprofiler-sdk-json-tool"]["buffer_records"])
|
||||
node_exists("kernel_dispatches", data["rocprofiler-sdk-json-tool"]["buffer_records"])
|
||||
node_exists("memory_copies", data["rocprofiler-sdk-json-tool"]["buffer_records"], 4)
|
||||
node_exists("hsa_api_traces", data["rocprofiler-sdk-json-tool"]["buffer_records"])
|
||||
node_exists("agents", sdk_data)
|
||||
node_exists("call_stack", sdk_data)
|
||||
node_exists("callback_records", sdk_data)
|
||||
node_exists("buffer_records", sdk_data)
|
||||
|
||||
node_exists("names", sdk_data["callback_records"])
|
||||
node_exists("code_objects", sdk_data["callback_records"])
|
||||
node_exists("kernel_symbols", sdk_data["callback_records"])
|
||||
node_exists("hsa_api_traces", sdk_data["callback_records"])
|
||||
|
||||
node_exists("names", sdk_data["buffer_records"])
|
||||
node_exists("kernel_dispatches", sdk_data["buffer_records"])
|
||||
node_exists("memory_copies", sdk_data["buffer_records"], 4)
|
||||
node_exists("hsa_api_traces", sdk_data["buffer_records"])
|
||||
|
||||
|
||||
def test_timestamps(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
cb_start = {}
|
||||
cb_end = {}
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["callback_records"]["hsa_api_traces"]:
|
||||
cid = itr["record"]["correlation_id"]["internal"]
|
||||
phase = itr["record"]["phase"]
|
||||
if phase == 1:
|
||||
cb_start[cid] = itr["timestamp"]
|
||||
elif phase == 2:
|
||||
cb_end[cid] = itr["timestamp"]
|
||||
assert cb_start[cid] <= itr["timestamp"]
|
||||
else:
|
||||
assert phase == 1 or phase == 2
|
||||
for titr in ["hsa_api_traces", "marker_api_traces"]:
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
cid = itr["record"]["correlation_id"]["internal"]
|
||||
phase = itr["record"]["phase"]
|
||||
if phase == 1:
|
||||
cb_start[cid] = itr["timestamp"]
|
||||
elif phase == 2:
|
||||
cb_end[cid] = itr["timestamp"]
|
||||
assert cb_start[cid] <= itr["timestamp"]
|
||||
else:
|
||||
assert phase == 1 or phase == 2
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["hsa_api_traces"]:
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
assert itr["start_timestamp"] <= itr["end_timestamp"]
|
||||
|
||||
for itr in sdk_data["buffer_records"]["memory_copies"]:
|
||||
assert itr["start_timestamp"] <= itr["end_timestamp"]
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["memory_copies"]:
|
||||
assert itr["start_timestamp"] <= itr["end_timestamp"]
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["kernel_dispatches"]:
|
||||
for itr in sdk_data["buffer_records"]["kernel_dispatches"]:
|
||||
assert itr["start_timestamp"] < itr["end_timestamp"]
|
||||
assert itr["correlation_id"]["internal"] > 0
|
||||
assert itr["correlation_id"]["external"] > 0
|
||||
@@ -67,21 +72,23 @@ def test_timestamps(input_data):
|
||||
|
||||
def test_internal_correlation_ids(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
api_corr_ids = []
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["callback_records"]["hsa_api_traces"]:
|
||||
api_corr_ids.append(itr["record"]["correlation_id"]["internal"])
|
||||
for titr in ["hsa_api_traces", "marker_api_traces"]:
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
api_corr_ids.append(itr["record"]["correlation_id"]["internal"])
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["hsa_api_traces"]:
|
||||
api_corr_ids.append(itr["correlation_id"]["internal"])
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
api_corr_ids.append(itr["correlation_id"]["internal"])
|
||||
|
||||
api_corr_ids_sorted = sorted(api_corr_ids)
|
||||
api_corr_ids_unique = list(set(api_corr_ids))
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["kernel_dispatches"]:
|
||||
for itr in sdk_data["buffer_records"]["kernel_dispatches"]:
|
||||
assert itr["correlation_id"]["internal"] in api_corr_ids_unique
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["memory_copies"]:
|
||||
for itr in sdk_data["buffer_records"]["memory_copies"]:
|
||||
assert itr["correlation_id"]["internal"] in api_corr_ids_unique
|
||||
|
||||
len_corr_id_unq = len(api_corr_ids_unique)
|
||||
@@ -91,34 +98,40 @@ def test_internal_correlation_ids(input_data):
|
||||
|
||||
def test_external_correlation_ids(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
extern_corr_ids = []
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["callback_records"]["hsa_api_traces"]:
|
||||
assert itr["record"]["correlation_id"]["external"] > 0
|
||||
assert itr["record"]["thread_id"] == itr["record"]["correlation_id"]["external"]
|
||||
extern_corr_ids.append(itr["record"]["correlation_id"]["external"])
|
||||
for titr in ["hsa_api_traces", "marker_api_traces"]:
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
assert itr["record"]["correlation_id"]["external"] > 0
|
||||
assert (
|
||||
itr["record"]["thread_id"] == itr["record"]["correlation_id"]["external"]
|
||||
)
|
||||
extern_corr_ids.append(itr["record"]["correlation_id"]["external"])
|
||||
|
||||
extern_corr_ids = list(set(sorted(extern_corr_ids)))
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["hsa_api_traces"]:
|
||||
assert itr["correlation_id"]["external"] > 0
|
||||
assert itr["thread_id"] == itr["correlation_id"]["external"]
|
||||
assert itr["thread_id"] in extern_corr_ids
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids
|
||||
for titr in ["hsa_api_traces", "marker_api_traces"]:
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
assert itr["correlation_id"]["external"] > 0
|
||||
assert itr["thread_id"] == itr["correlation_id"]["external"]
|
||||
assert itr["thread_id"] in extern_corr_ids
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["kernel_dispatches"]:
|
||||
for itr in sdk_data["buffer_records"]["kernel_dispatches"]:
|
||||
assert itr["correlation_id"]["external"] > 0
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["memory_copies"]:
|
||||
for itr in sdk_data["buffer_records"]["memory_copies"]:
|
||||
assert itr["correlation_id"]["external"] > 0
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids
|
||||
|
||||
|
||||
def test_kernel_ids(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
symbol_info = {}
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["callback_records"]["kernel_symbols"]:
|
||||
for itr in sdk_data["callback_records"]["kernel_symbols"]:
|
||||
phase = itr["record"]["phase"]
|
||||
payload = itr["payload"]
|
||||
kern_id = payload["kernel_id"]
|
||||
@@ -132,12 +145,13 @@ def test_kernel_ids(input_data):
|
||||
assert payload["kernel_id"] in symbol_info.keys()
|
||||
assert payload["kernel_name"] == symbol_info[kern_id]["kernel_name"]
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["kernel_dispatches"]:
|
||||
for itr in sdk_data["buffer_records"]["kernel_dispatches"]:
|
||||
assert itr["kernel_id"] in symbol_info.keys()
|
||||
|
||||
|
||||
def test_async_copy_direction(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
# Direction values:
|
||||
# -1 == ??? (unknown)
|
||||
@@ -146,7 +160,7 @@ def test_async_copy_direction(input_data):
|
||||
# 2 == D2H (device to host)
|
||||
# 3 == D2D (device to device)
|
||||
async_dir_cnt = dict([(idx, 0) for idx in range(-1, 4)])
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["memory_copies"]:
|
||||
for itr in sdk_data["buffer_records"]["memory_copies"]:
|
||||
op_id = itr["operation"]
|
||||
assert op_id > 0
|
||||
assert op_id < 3
|
||||
|
||||
@@ -158,6 +158,13 @@ save(ArchiveT& ar, rocprofiler_hsa_api_retval_t data)
|
||||
SAVE_DATA_FIELD(uint64_t_retval);
|
||||
}
|
||||
|
||||
template <typename ArchiveT>
|
||||
void
|
||||
save(ArchiveT& ar, rocprofiler_marker_api_retval_t data)
|
||||
{
|
||||
SAVE_DATA_FIELD(int64_t_retval);
|
||||
}
|
||||
|
||||
template <typename ArchiveT>
|
||||
void
|
||||
save(ArchiveT& ar, rocprofiler_callback_tracing_hsa_api_data_t data)
|
||||
@@ -167,6 +174,15 @@ save(ArchiveT& ar, rocprofiler_callback_tracing_hsa_api_data_t data)
|
||||
SAVE_DATA_FIELD(retval);
|
||||
}
|
||||
|
||||
template <typename ArchiveT>
|
||||
void
|
||||
save(ArchiveT& ar, rocprofiler_callback_tracing_marker_api_data_t data)
|
||||
{
|
||||
SAVE_DATA_FIELD(size);
|
||||
// SAVE_DATA_FIELD(args);
|
||||
SAVE_DATA_FIELD(retval);
|
||||
}
|
||||
|
||||
template <typename ArchiveT>
|
||||
void
|
||||
save(ArchiveT& ar, rocprofiler_callback_tracing_record_t data)
|
||||
|
||||
@@ -19,17 +19,17 @@ endif()
|
||||
|
||||
add_test(NAME test-kernel-tracing-execute COMMAND $<TARGET_FILE:reproducible-runtime>)
|
||||
|
||||
set(kernel-tracing-env
|
||||
"${PRELOAD_ENV}"
|
||||
"HSA_TOOLS_LIB=$<TARGET_FILE:rocprofiler::rocprofiler-shared-library>"
|
||||
"ROCPROFILER_TOOL_OUTPUT_FILE=kernel-tracing-test.json"
|
||||
"LD_LIBRARY_PATH=$<TARGET_FILE_DIR:rocprofiler::rocprofiler-shared-library>:$ENV{LD_LIBRARY_PATH}"
|
||||
)
|
||||
|
||||
set_tests_properties(
|
||||
test-kernel-tracing-execute
|
||||
PROPERTIES
|
||||
TIMEOUT
|
||||
45
|
||||
LABELS
|
||||
"integration-tests"
|
||||
ENVIRONMENT
|
||||
"${PRELOAD_ENV};HSA_TOOLS_LIB=$<TARGET_FILE:rocprofiler::rocprofiler-shared-library>;ROCPROFILER_TOOL_OUTPUT_FILE=kernel-tracing-test.json"
|
||||
FAIL_REGULAR_EXPRESSION
|
||||
"threw an exception")
|
||||
PROPERTIES TIMEOUT 45 LABELS "integration-tests" ENVIRONMENT "${kernel-tracing-env}"
|
||||
FAIL_REGULAR_EXPRESSION "threw an exception")
|
||||
|
||||
foreach(FILENAME validate.py pytest.ini conftest.py)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}
|
||||
|
||||
@@ -16,45 +16,52 @@ def test_data_structure(input_data):
|
||||
data = input_data
|
||||
|
||||
node_exists("rocprofiler-sdk-json-tool", data)
|
||||
node_exists("agents", data["rocprofiler-sdk-json-tool"])
|
||||
node_exists("call_stack", data["rocprofiler-sdk-json-tool"])
|
||||
node_exists("callback_records", data["rocprofiler-sdk-json-tool"])
|
||||
node_exists("buffer_records", data["rocprofiler-sdk-json-tool"])
|
||||
|
||||
node_exists("names", data["rocprofiler-sdk-json-tool"]["callback_records"])
|
||||
node_exists("code_objects", data["rocprofiler-sdk-json-tool"]["callback_records"])
|
||||
node_exists("kernel_symbols", data["rocprofiler-sdk-json-tool"]["callback_records"])
|
||||
node_exists("hsa_api_traces", data["rocprofiler-sdk-json-tool"]["callback_records"])
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
node_exists("names", data["rocprofiler-sdk-json-tool"]["buffer_records"])
|
||||
node_exists("kernel_dispatches", data["rocprofiler-sdk-json-tool"]["buffer_records"])
|
||||
node_exists("memory_copies", data["rocprofiler-sdk-json-tool"]["buffer_records"], 0)
|
||||
node_exists("hsa_api_traces", data["rocprofiler-sdk-json-tool"]["buffer_records"])
|
||||
node_exists("agents", sdk_data)
|
||||
node_exists("call_stack", sdk_data)
|
||||
node_exists("callback_records", sdk_data)
|
||||
node_exists("buffer_records", sdk_data)
|
||||
|
||||
node_exists("names", sdk_data["callback_records"])
|
||||
node_exists("code_objects", sdk_data["callback_records"])
|
||||
node_exists("kernel_symbols", sdk_data["callback_records"])
|
||||
node_exists("hsa_api_traces", sdk_data["callback_records"])
|
||||
node_exists("marker_api_traces", sdk_data["callback_records"])
|
||||
|
||||
node_exists("names", sdk_data["buffer_records"])
|
||||
node_exists("kernel_dispatches", sdk_data["buffer_records"])
|
||||
node_exists("memory_copies", sdk_data["buffer_records"], 0)
|
||||
node_exists("hsa_api_traces", sdk_data["buffer_records"])
|
||||
node_exists("marker_api_traces", sdk_data["buffer_records"])
|
||||
|
||||
|
||||
def test_timestamps(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
cb_start = {}
|
||||
cb_end = {}
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["callback_records"]["hsa_api_traces"]:
|
||||
cid = itr["record"]["correlation_id"]["internal"]
|
||||
phase = itr["record"]["phase"]
|
||||
if phase == 1:
|
||||
cb_start[cid] = itr["timestamp"]
|
||||
elif phase == 2:
|
||||
cb_end[cid] = itr["timestamp"]
|
||||
assert cb_start[cid] <= itr["timestamp"]
|
||||
else:
|
||||
assert phase == 1 or phase == 2
|
||||
for titr in ["hsa_api_traces", "marker_api_traces"]:
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
cid = itr["record"]["correlation_id"]["internal"]
|
||||
phase = itr["record"]["phase"]
|
||||
if phase == 1:
|
||||
cb_start[cid] = itr["timestamp"]
|
||||
elif phase == 2:
|
||||
cb_end[cid] = itr["timestamp"]
|
||||
assert cb_start[cid] <= itr["timestamp"]
|
||||
else:
|
||||
assert phase == 1 or phase == 2
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["hsa_api_traces"]:
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
assert itr["start_timestamp"] <= itr["end_timestamp"]
|
||||
|
||||
for itr in sdk_data["buffer_records"]["memory_copies"]:
|
||||
assert itr["start_timestamp"] <= itr["end_timestamp"]
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["memory_copies"]:
|
||||
assert itr["start_timestamp"] <= itr["end_timestamp"]
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["kernel_dispatches"]:
|
||||
for itr in sdk_data["buffer_records"]["kernel_dispatches"]:
|
||||
assert itr["start_timestamp"] < itr["end_timestamp"]
|
||||
assert itr["correlation_id"]["internal"] > 0
|
||||
assert itr["correlation_id"]["external"] > 0
|
||||
@@ -67,21 +74,23 @@ def test_timestamps(input_data):
|
||||
|
||||
def test_internal_correlation_ids(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
api_corr_ids = []
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["callback_records"]["hsa_api_traces"]:
|
||||
api_corr_ids.append(itr["record"]["correlation_id"]["internal"])
|
||||
for titr in ["hsa_api_traces", "marker_api_traces"]:
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
api_corr_ids.append(itr["record"]["correlation_id"]["internal"])
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["hsa_api_traces"]:
|
||||
api_corr_ids.append(itr["correlation_id"]["internal"])
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
api_corr_ids.append(itr["correlation_id"]["internal"])
|
||||
|
||||
api_corr_ids_sorted = sorted(api_corr_ids)
|
||||
api_corr_ids_unique = list(set(api_corr_ids))
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["kernel_dispatches"]:
|
||||
for itr in sdk_data["buffer_records"]["kernel_dispatches"]:
|
||||
assert itr["correlation_id"]["internal"] in api_corr_ids_unique
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["memory_copies"]:
|
||||
for itr in sdk_data["buffer_records"]["memory_copies"]:
|
||||
assert itr["correlation_id"]["internal"] in api_corr_ids_unique
|
||||
|
||||
len_corr_id_unq = len(api_corr_ids_unique)
|
||||
@@ -91,34 +100,40 @@ def test_internal_correlation_ids(input_data):
|
||||
|
||||
def test_external_correlation_ids(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
extern_corr_ids = []
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["callback_records"]["hsa_api_traces"]:
|
||||
assert itr["record"]["correlation_id"]["external"] > 0
|
||||
assert itr["record"]["thread_id"] == itr["record"]["correlation_id"]["external"]
|
||||
extern_corr_ids.append(itr["record"]["correlation_id"]["external"])
|
||||
for titr in ["hsa_api_traces", "marker_api_traces"]:
|
||||
for itr in sdk_data["callback_records"][titr]:
|
||||
assert itr["record"]["correlation_id"]["external"] > 0
|
||||
assert (
|
||||
itr["record"]["thread_id"] == itr["record"]["correlation_id"]["external"]
|
||||
)
|
||||
extern_corr_ids.append(itr["record"]["correlation_id"]["external"])
|
||||
|
||||
extern_corr_ids = list(set(sorted(extern_corr_ids)))
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["hsa_api_traces"]:
|
||||
assert itr["correlation_id"]["external"] > 0
|
||||
assert itr["thread_id"] == itr["correlation_id"]["external"]
|
||||
assert itr["thread_id"] in extern_corr_ids
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids
|
||||
for titr in ["hsa_api_traces", "marker_api_traces"]:
|
||||
for itr in sdk_data["buffer_records"][titr]:
|
||||
assert itr["correlation_id"]["external"] > 0
|
||||
assert itr["thread_id"] == itr["correlation_id"]["external"]
|
||||
assert itr["thread_id"] in extern_corr_ids
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["kernel_dispatches"]:
|
||||
for itr in sdk_data["buffer_records"]["kernel_dispatches"]:
|
||||
assert itr["correlation_id"]["external"] > 0
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["memory_copies"]:
|
||||
for itr in sdk_data["buffer_records"]["memory_copies"]:
|
||||
assert itr["correlation_id"]["external"] > 0
|
||||
assert itr["correlation_id"]["external"] in extern_corr_ids
|
||||
|
||||
|
||||
def test_kernel_ids(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
symbol_info = {}
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["callback_records"]["kernel_symbols"]:
|
||||
for itr in sdk_data["callback_records"]["kernel_symbols"]:
|
||||
phase = itr["record"]["phase"]
|
||||
payload = itr["payload"]
|
||||
kern_id = payload["kernel_id"]
|
||||
@@ -132,12 +147,13 @@ def test_kernel_ids(input_data):
|
||||
assert payload["kernel_id"] in symbol_info.keys()
|
||||
assert payload["kernel_name"] == symbol_info[kern_id]["kernel_name"]
|
||||
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["kernel_dispatches"]:
|
||||
for itr in sdk_data["buffer_records"]["kernel_dispatches"]:
|
||||
assert itr["kernel_id"] in symbol_info.keys()
|
||||
|
||||
|
||||
def test_async_copy_direction(input_data):
|
||||
data = input_data
|
||||
sdk_data = data["rocprofiler-sdk-json-tool"]
|
||||
|
||||
# Direction values:
|
||||
# -1 == ??? (unknown)
|
||||
@@ -146,7 +162,7 @@ def test_async_copy_direction(input_data):
|
||||
# 2 == D2H (device to host)
|
||||
# 3 == D2D (device to device)
|
||||
async_dir_cnt = dict([(idx, 0) for idx in range(-1, 4)])
|
||||
for itr in data["rocprofiler-sdk-json-tool"]["buffer_records"]["memory_copies"]:
|
||||
for itr in sdk_data["buffer_records"]["memory_copies"]:
|
||||
op_id = itr["operation"]
|
||||
async_dir_cnt[op_id] += 1
|
||||
|
||||
|
||||
@@ -18,20 +18,13 @@ target_link_libraries(
|
||||
rocprofiler::tests-common-library)
|
||||
set_target_properties(
|
||||
rocprofiler-sdk-json-tool
|
||||
PROPERTIES INSTALL_RPATH "\$ORIGIN:\$ORIGIN/.."
|
||||
INSTALL_RPATH_USE_LINK_PATH ON
|
||||
PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/rocprofiler-sdk"
|
||||
SOVERSION ${PROJECT_VERSION_MINOR}
|
||||
VERSION
|
||||
${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
|
||||
${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}
|
||||
INSTALL_RPATH "\$ORIGIN:\$ORIGIN/..")
|
||||
|
||||
install(
|
||||
TARGETS rocprofiler-sdk-json-tool
|
||||
DESTINATION lib/rocprofiler-sdk
|
||||
COMPONENT tests)
|
||||
|
||||
if(ROCPROFILER_MEMCHECK_PRELOAD_ENV)
|
||||
set(PRELOAD_ENV
|
||||
"${ROCPROFILER_MEMCHECK_PRELOAD_ENV}:$<TARGET_FILE:rocprofiler-sdk-json-tool>")
|
||||
else()
|
||||
set(PRELOAD_ENV "LD_PRELOAD=$<TARGET_FILE:rocprofiler-sdk-json-tool>")
|
||||
endif()
|
||||
|
||||
+99
-53
@@ -128,6 +128,9 @@ rocprofiler_client_finalize_t client_fini_func = nullptr;
|
||||
callback_name_info
|
||||
get_callback_tracing_names()
|
||||
{
|
||||
static const auto supported = std::unordered_set<rocprofiler_callback_tracing_kind_t>{
|
||||
ROCPROFILER_CALLBACK_TRACING_HSA_API, ROCPROFILER_CALLBACK_TRACING_MARKER_API};
|
||||
|
||||
auto cb_name_info = callback_name_info{};
|
||||
//
|
||||
// callback for each kind operation
|
||||
@@ -136,7 +139,7 @@ get_callback_tracing_names()
|
||||
[](rocprofiler_callback_tracing_kind_t kindv, uint32_t operation, void* data_v) {
|
||||
auto* name_info_v = static_cast<callback_name_info*>(data_v);
|
||||
|
||||
if(kindv == ROCPROFILER_CALLBACK_TRACING_HSA_API)
|
||||
if(supported.count(kindv) > 0)
|
||||
{
|
||||
const char* name = nullptr;
|
||||
ROCPROFILER_CALL(rocprofiler_query_callback_tracing_kind_operation_name(
|
||||
@@ -158,7 +161,7 @@ get_callback_tracing_names()
|
||||
"query buffer tracing kind operation name");
|
||||
if(name) name_info_v->kind_names[kind] = name;
|
||||
|
||||
if(kind == ROCPROFILER_CALLBACK_TRACING_HSA_API)
|
||||
if(supported.count(kind) > 0)
|
||||
{
|
||||
ROCPROFILER_CALL(rocprofiler_iterate_callback_tracing_kind_operations(
|
||||
kind, tracing_kind_operation_cb, static_cast<void*>(data)),
|
||||
@@ -177,6 +180,9 @@ get_callback_tracing_names()
|
||||
buffer_name_info
|
||||
get_buffer_tracing_names()
|
||||
{
|
||||
static const auto supported = std::unordered_set<rocprofiler_buffer_tracing_kind_t>{
|
||||
ROCPROFILER_BUFFER_TRACING_HSA_API, ROCPROFILER_BUFFER_TRACING_MARKER_API};
|
||||
|
||||
auto cb_name_info = buffer_name_info{};
|
||||
//
|
||||
// callback for each kind operation
|
||||
@@ -185,7 +191,7 @@ get_buffer_tracing_names()
|
||||
[](rocprofiler_buffer_tracing_kind_t kindv, uint32_t operation, void* data_v) {
|
||||
auto* name_info_v = static_cast<buffer_name_info*>(data_v);
|
||||
|
||||
if(kindv == ROCPROFILER_BUFFER_TRACING_HSA_API)
|
||||
if(supported.count(kindv) > 0)
|
||||
{
|
||||
const char* name = nullptr;
|
||||
ROCPROFILER_CALL(rocprofiler_query_buffer_tracing_kind_operation_name(
|
||||
@@ -207,7 +213,7 @@ get_buffer_tracing_names()
|
||||
"query buffer tracing kind operation name");
|
||||
if(name) name_info_v->kind_names[kind] = name;
|
||||
|
||||
if(kind == ROCPROFILER_BUFFER_TRACING_HSA_API)
|
||||
if(supported.count(kind) > 0)
|
||||
{
|
||||
ROCPROFILER_CALL(rocprofiler_iterate_buffer_tracing_kind_operations(
|
||||
kind, tracing_kind_operation_cb, static_cast<void*>(data)),
|
||||
@@ -226,7 +232,8 @@ get_buffer_tracing_names()
|
||||
using callback_payload_t =
|
||||
std::variant<rocprofiler_callback_tracing_code_object_load_data_t,
|
||||
rocprofiler_callback_tracing_code_object_kernel_symbol_register_data_t,
|
||||
rocprofiler_callback_tracing_hsa_api_data_t>;
|
||||
rocprofiler_callback_tracing_hsa_api_data_t,
|
||||
rocprofiler_callback_tracing_marker_api_data_t>;
|
||||
|
||||
struct code_object_callback_record_t
|
||||
{
|
||||
@@ -273,9 +280,25 @@ struct hsa_api_callback_record_t
|
||||
}
|
||||
};
|
||||
|
||||
struct marker_api_callback_record_t
|
||||
{
|
||||
uint64_t timestamp = 0;
|
||||
rocprofiler_callback_tracing_record_t record = {};
|
||||
rocprofiler_callback_tracing_marker_api_data_t payload = {};
|
||||
|
||||
template <typename ArchiveT>
|
||||
void save(ArchiveT& ar) const
|
||||
{
|
||||
ar(cereal::make_nvp("timestamp", timestamp));
|
||||
ar(cereal::make_nvp("record", record));
|
||||
ar(cereal::make_nvp("payload", payload));
|
||||
}
|
||||
};
|
||||
|
||||
auto code_object_records = std::deque<code_object_callback_record_t>{};
|
||||
auto kernel_symbol_records = std::deque<kernel_symbol_callback_record_t>{};
|
||||
auto hsa_api_cb_records = std::deque<hsa_api_callback_record_t>{};
|
||||
auto marker_api_cb_records = std::deque<marker_api_callback_record_t>{};
|
||||
|
||||
rocprofiler_thread_id_t
|
||||
push_external_correlation();
|
||||
@@ -303,14 +326,12 @@ tool_tracing_callback(rocprofiler_callback_tracing_record_t record,
|
||||
{
|
||||
auto data_v =
|
||||
*static_cast<rocprofiler_callback_tracing_code_object_load_data_t*>(record.payload);
|
||||
data_v.uri = ::strdup(data_v.uri);
|
||||
code_object_records.emplace_back(code_object_callback_record_t{ts, record, data_v});
|
||||
}
|
||||
else if(record.operation ==
|
||||
ROCPROFILER_CALLBACK_TRACING_CODE_OBJECT_DEVICE_KERNEL_SYMBOL_REGISTER)
|
||||
{
|
||||
auto data_v = *static_cast<kernel_symbol_data_t*>(record.payload);
|
||||
data_v.kernel_name = ::strdup(data_v.kernel_name);
|
||||
auto data_v = *static_cast<kernel_symbol_data_t*>(record.payload);
|
||||
kernel_symbol_records.emplace_back(kernel_symbol_callback_record_t{ts, record, data_v});
|
||||
}
|
||||
}
|
||||
@@ -319,6 +340,11 @@ tool_tracing_callback(rocprofiler_callback_tracing_record_t record,
|
||||
auto* data = static_cast<rocprofiler_callback_tracing_hsa_api_data_t*>(record.payload);
|
||||
hsa_api_cb_records.emplace_back(hsa_api_callback_record_t{ts, record, *data});
|
||||
}
|
||||
else if(record.kind == ROCPROFILER_CALLBACK_TRACING_MARKER_API)
|
||||
{
|
||||
auto* data = static_cast<rocprofiler_callback_tracing_marker_api_data_t*>(record.payload);
|
||||
marker_api_cb_records.emplace_back(marker_api_callback_record_t{ts, record, *data});
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error{"unsupported callback kind"};
|
||||
@@ -326,6 +352,7 @@ tool_tracing_callback(rocprofiler_callback_tracing_record_t record,
|
||||
}
|
||||
|
||||
auto hsa_api_bf_records = std::deque<rocprofiler_buffer_tracing_hsa_api_record_t>{};
|
||||
auto marker_api_bf_records = std::deque<rocprofiler_buffer_tracing_marker_api_record_t>{};
|
||||
auto kernel_dispatch_records = std::deque<rocprofiler_buffer_tracing_kernel_dispatch_record_t>{};
|
||||
auto memory_copy_records = std::deque<rocprofiler_buffer_tracing_memory_copy_record_t>{};
|
||||
|
||||
@@ -377,6 +404,13 @@ tool_tracing_buffered(rocprofiler_context_id_t /*context*/,
|
||||
|
||||
hsa_api_bf_records.emplace_back(*record);
|
||||
}
|
||||
else if(header->kind == ROCPROFILER_BUFFER_TRACING_MARKER_API)
|
||||
{
|
||||
auto* record =
|
||||
static_cast<rocprofiler_buffer_tracing_marker_api_record_t*>(header->payload);
|
||||
|
||||
marker_api_bf_records.emplace_back(*record);
|
||||
}
|
||||
else if(header->kind == ROCPROFILER_BUFFER_TRACING_KERNEL_DISPATCH)
|
||||
{
|
||||
auto* record = static_cast<rocprofiler_buffer_tracing_kernel_dispatch_record_t*>(
|
||||
@@ -444,23 +478,29 @@ void
|
||||
flush();
|
||||
|
||||
// contexts
|
||||
rocprofiler_context_id_t api_callback_ctx = {};
|
||||
rocprofiler_context_id_t code_object_ctx = {};
|
||||
rocprofiler_context_id_t api_buffered_ctx = {};
|
||||
rocprofiler_context_id_t kernel_dispatch_ctx = {};
|
||||
rocprofiler_context_id_t memory_copy_ctx = {};
|
||||
rocprofiler_context_id_t hsa_api_callback_ctx = {};
|
||||
rocprofiler_context_id_t marker_api_callback_ctx = {};
|
||||
rocprofiler_context_id_t code_object_ctx = {};
|
||||
rocprofiler_context_id_t hsa_api_buffered_ctx = {};
|
||||
rocprofiler_context_id_t marker_api_buffered_ctx = {};
|
||||
rocprofiler_context_id_t kernel_dispatch_ctx = {};
|
||||
rocprofiler_context_id_t memory_copy_ctx = {};
|
||||
// buffers
|
||||
rocprofiler_buffer_id_t api_buffered_buffer = {};
|
||||
rocprofiler_buffer_id_t kernel_dispatch_buffer = {};
|
||||
rocprofiler_buffer_id_t memory_copy_buffer = {};
|
||||
rocprofiler_buffer_id_t hsa_api_buffered_buffer = {};
|
||||
rocprofiler_buffer_id_t marker_api_buffered_buffer = {};
|
||||
rocprofiler_buffer_id_t kernel_dispatch_buffer = {};
|
||||
rocprofiler_buffer_id_t memory_copy_buffer = {};
|
||||
|
||||
auto contexts = std::unordered_map<std::string_view, rocprofiler_context_id_t*>{
|
||||
{"API_CALLBACK", &api_callback_ctx},
|
||||
{"HSA_API_CALLBACK", &hsa_api_callback_ctx},
|
||||
{"MARKER_API_CALLBACK", &marker_api_callback_ctx},
|
||||
{"CODE_OBJECT", &code_object_ctx},
|
||||
{"API_BUFFERED", &api_buffered_ctx},
|
||||
{"HSA_API_BUFFERED", &hsa_api_buffered_ctx},
|
||||
{"MARKER_API_BUFFERED", &marker_api_buffered_ctx},
|
||||
{"KERNEL_DISPATCH", &kernel_dispatch_ctx},
|
||||
{"MEMORY_COPY", &memory_copy_ctx}};
|
||||
auto buffers = std::array<rocprofiler_buffer_id_t*, 3>{&api_buffered_buffer,
|
||||
auto buffers = std::array<rocprofiler_buffer_id_t*, 4>{&hsa_api_buffered_buffer,
|
||||
&marker_api_buffered_buffer,
|
||||
&kernel_dispatch_buffer,
|
||||
&memory_copy_buffer};
|
||||
|
||||
@@ -475,14 +515,7 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
|
||||
[](const rocprofiler_agent_t** agents_arr, size_t num_agents, void* user_data) {
|
||||
auto* agents_v = static_cast<std::vector<rocprofiler_agent_t>*>(user_data);
|
||||
for(size_t i = 0; i < num_agents; ++i)
|
||||
{
|
||||
const auto* agent = agents_arr[i];
|
||||
auto& val = agents_v->emplace_back(*agent);
|
||||
val.name = ::strdup(agent->name);
|
||||
val.vendor_name = ::strdup(agent->vendor_name);
|
||||
val.product_name = ::strdup(agent->product_name);
|
||||
val.model_name = ::strdup(agent->model_name);
|
||||
}
|
||||
agents_v->emplace_back(*agents_arr[i]);
|
||||
return ROCPROFILER_STATUS_SUCCESS;
|
||||
};
|
||||
|
||||
@@ -504,7 +537,7 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
|
||||
}
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_configure_callback_tracing_service(api_callback_ctx,
|
||||
rocprofiler_configure_callback_tracing_service(hsa_api_callback_ctx,
|
||||
ROCPROFILER_CALLBACK_TRACING_HSA_API,
|
||||
nullptr,
|
||||
0,
|
||||
@@ -521,16 +554,34 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
|
||||
nullptr),
|
||||
"code object tracing service configure");
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_configure_callback_tracing_service(marker_api_callback_ctx,
|
||||
ROCPROFILER_CALLBACK_TRACING_MARKER_API,
|
||||
nullptr,
|
||||
0,
|
||||
tool_tracing_callback,
|
||||
nullptr),
|
||||
"hsa api tracing service configure");
|
||||
|
||||
constexpr auto buffer_size = 8192;
|
||||
constexpr auto watermark = 7936;
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_create_buffer(api_buffered_ctx,
|
||||
ROCPROFILER_CALL(rocprofiler_create_buffer(hsa_api_buffered_ctx,
|
||||
buffer_size,
|
||||
watermark,
|
||||
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
|
||||
tool_tracing_buffered,
|
||||
tool_data,
|
||||
&api_buffered_buffer),
|
||||
&hsa_api_buffered_buffer),
|
||||
"buffer creation");
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_create_buffer(marker_api_buffered_ctx,
|
||||
buffer_size,
|
||||
watermark,
|
||||
ROCPROFILER_BUFFER_POLICY_LOSSLESS,
|
||||
tool_tracing_buffered,
|
||||
tool_data,
|
||||
&marker_api_buffered_buffer),
|
||||
"buffer creation");
|
||||
|
||||
ROCPROFILER_CALL(rocprofiler_create_buffer(kernel_dispatch_ctx,
|
||||
@@ -552,8 +603,19 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data)
|
||||
"buffer creation");
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_configure_buffer_tracing_service(
|
||||
api_buffered_ctx, ROCPROFILER_BUFFER_TRACING_HSA_API, nullptr, 0, api_buffered_buffer),
|
||||
rocprofiler_configure_buffer_tracing_service(hsa_api_buffered_ctx,
|
||||
ROCPROFILER_BUFFER_TRACING_HSA_API,
|
||||
nullptr,
|
||||
0,
|
||||
hsa_api_buffered_buffer),
|
||||
"buffer tracing service configure");
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
rocprofiler_configure_buffer_tracing_service(marker_api_buffered_ctx,
|
||||
ROCPROFILER_BUFFER_TRACING_MARKER_API,
|
||||
nullptr,
|
||||
0,
|
||||
marker_api_buffered_buffer),
|
||||
"buffer tracing service configure");
|
||||
|
||||
ROCPROFILER_CALL(
|
||||
@@ -650,9 +712,11 @@ tool_fini(void* tool_data)
|
||||
<< ", code_object_callback_records=" << code_object_records.size()
|
||||
<< ", kernel_symbol_callback_records=" << kernel_symbol_records.size()
|
||||
<< ", hsa_api_callback_records=" << hsa_api_cb_records.size()
|
||||
<< ", marker_api_callback_records=" << marker_api_cb_records.size()
|
||||
<< ", kernel_dispatch_records=" << kernel_dispatch_records.size()
|
||||
<< ", memory_copy_records=" << memory_copy_records.size()
|
||||
<< ", hsa_api_bf_records=" << hsa_api_bf_records.size() << " ...\n"
|
||||
<< ", hsa_api_bf_records=" << hsa_api_bf_records.size()
|
||||
<< ", marker_api_bf_records=" << marker_api_bf_records.size() << " ...\n"
|
||||
<< std::flush;
|
||||
|
||||
auto* _call_stack = static_cast<call_stack_t*>(tool_data);
|
||||
@@ -713,6 +777,7 @@ tool_fini(void* tool_data)
|
||||
json_ar(cereal::make_nvp("code_objects", code_object_records));
|
||||
json_ar(cereal::make_nvp("kernel_symbols", kernel_symbol_records));
|
||||
json_ar(cereal::make_nvp("hsa_api_traces", hsa_api_cb_records));
|
||||
json_ar(cereal::make_nvp("marker_api_traces", marker_api_cb_records));
|
||||
} catch(std::exception& e)
|
||||
{
|
||||
std::cerr << "[" << getpid() << "][" << __FUNCTION__
|
||||
@@ -729,6 +794,7 @@ tool_fini(void* tool_data)
|
||||
json_ar(cereal::make_nvp("kernel_dispatches", kernel_dispatch_records));
|
||||
json_ar(cereal::make_nvp("memory_copies", memory_copy_records));
|
||||
json_ar(cereal::make_nvp("hsa_api_traces", hsa_api_bf_records));
|
||||
json_ar(cereal::make_nvp("marker_api_traces", marker_api_bf_records));
|
||||
} catch(std::exception& e)
|
||||
{
|
||||
std::cerr << "[" << getpid() << "][" << __FUNCTION__
|
||||
@@ -748,26 +814,6 @@ tool_fini(void* tool_data)
|
||||
<< std::flush;
|
||||
|
||||
delete _call_stack;
|
||||
|
||||
auto free_cstr = [](const char*& val) {
|
||||
::free(const_cast<char*>(val));
|
||||
val = nullptr;
|
||||
};
|
||||
|
||||
// clean up our strdups to avoid triggering our leak sanitizer during CI
|
||||
for(auto& itr : code_object_records)
|
||||
free_cstr(itr.payload.uri);
|
||||
|
||||
for(auto& itr : kernel_symbol_records)
|
||||
free_cstr(itr.payload.kernel_name);
|
||||
|
||||
for(auto& itr : agents)
|
||||
{
|
||||
free_cstr(itr.name);
|
||||
free_cstr(itr.vendor_name);
|
||||
free_cstr(itr.product_name);
|
||||
free_cstr(itr.model_name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user