From 249c50fc40fb30b83a09f56bb8812b26c8c79cc8 Mon Sep 17 00:00:00 2001 From: "Jonathan R. Madsen" Date: Mon, 18 Nov 2024 20:50:29 -0600 Subject: [PATCH] Runtime Initialization Tracing (#1105) * Runtime initialization tracing - calbacks and buffer entries notifying when a runtime has been initialized * Minor cleanup to registration.cpp * JSON tool implementation * Increase perfetto_reader timeout * Handle perfetto_reader timeout when attr doesn't exist * clang-tidy fixes to memory_allocation.cpp --- .../include/rocprofiler-sdk/buffer_tracing.h | 46 ++++- .../rocprofiler-sdk/callback_tracing.h | 15 ++ .../rocprofiler-sdk/cxx/serialization.hpp | 23 +++ source/include/rocprofiler-sdk/fwd.h | 22 ++- source/lib/rocprofiler-sdk/CMakeLists.txt | 8 +- source/lib/rocprofiler-sdk/buffer_tracing.cpp | 26 ++- .../lib/rocprofiler-sdk/callback_tracing.cpp | 27 ++- source/lib/rocprofiler-sdk/hsa/async_copy.cpp | 4 +- .../rocprofiler-sdk/hsa/memory_allocation.cpp | 4 +- source/lib/rocprofiler-sdk/registration.cpp | 41 ++++- .../runtime_initialization.cpp | 162 ++++++++++++++++++ .../runtime_initialization.hpp | 51 ++++++ .../pytest_utils/perfetto_reader.py | 14 +- tests/tools/json-tool.cpp | 102 +++++++++-- 14 files changed, 496 insertions(+), 49 deletions(-) create mode 100644 source/lib/rocprofiler-sdk/runtime_initialization.cpp create mode 100644 source/lib/rocprofiler-sdk/runtime_initialization.hpp diff --git a/source/include/rocprofiler-sdk/buffer_tracing.h b/source/include/rocprofiler-sdk/buffer_tracing.h index 3074ce12f4..7be1c33756 100644 --- a/source/include/rocprofiler-sdk/buffer_tracing.h +++ b/source/include/rocprofiler-sdk/buffer_tracing.h @@ -157,6 +157,7 @@ typedef struct /// @brief ::ROCPROFILER_CALLBACK_TRACING_MARKER_CORE_API, /// ::ROCPROFILER_CALLBACK_TRACING_MARKER_CONTROL_API, or /// ::ROCPROFILER_CALLBACK_TRACING_MARKER_NAME_API + /// @var operation /// @brief Specification of the API function, e.g., ::rocprofiler_marker_core_api_id_t, /// ::rocprofiler_marker_control_api_id_t, or /// ::rocprofiler_marker_name_api_id_t @@ -176,8 +177,9 @@ typedef struct rocprofiler_thread_id_t thread_id; ///< id for thread generating this record /// @var kind - /// @brief ::ROCPROFILER_CALLBACK_TRACING_RCCL_API, - /// @brief Specification of the API function, e.g., ::rocprofiler_rccl_api_id_t, + /// @brief ::ROCPROFILER_CALLBACK_TRACING_RCCL_API + /// @var operation + /// @brief Specification of the API function, e.g., ::rocprofiler_rccl_api_id_t } rocprofiler_buffer_tracing_rccl_api_record_t; /** @@ -265,13 +267,13 @@ typedef struct { uint64_t size; ///< size of this struct rocprofiler_buffer_tracing_kind_t kind; ///< ::ROCPROFILER_BUFFER_TRACING_SCRATCH_MEMORY - rocprofiler_scratch_memory_operation_t operation; ///< specification of the kind - rocprofiler_agent_id_t agent_id; ///< agent kernel was dispatched on - rocprofiler_queue_id_t queue_id; ///< queue kernel was dispatched on + rocprofiler_scratch_memory_operation_t operation; ///< specification of the kind + rocprofiler_correlation_id_t correlation_id; ///< correlation ids for record + rocprofiler_agent_id_t agent_id; ///< agent kernel was dispatched on + rocprofiler_queue_id_t queue_id; ///< queue kernel was dispatched on rocprofiler_thread_id_t thread_id; ///< id for thread generating this record rocprofiler_timestamp_t start_timestamp; ///< start time in nanoseconds rocprofiler_timestamp_t end_timestamp; ///< end time in nanoseconds - rocprofiler_correlation_id_t correlation_id; ///< correlation ids for record rocprofiler_scratch_alloc_flag_t flags; } rocprofiler_buffer_tracing_scratch_memory_record_t; @@ -296,6 +298,38 @@ typedef struct /// @brief Only internal correlation ID is provided } rocprofiler_buffer_tracing_correlation_id_retirement_record_t; +/** + * @brief ROCProfiler Buffer Runtime Initialization Tracer Record. + */ +typedef struct rocprofiler_buffer_tracing_runtime_initialization_record_t +{ + uint64_t size; ///< size of this struct + rocprofiler_buffer_tracing_kind_t kind; + rocprofiler_runtime_initialization_operation_t operation; + rocprofiler_correlation_id_t correlation_id; + rocprofiler_thread_id_t thread_id; + rocprofiler_timestamp_t timestamp; + uint64_t version; + uint64_t instance; + + /// @var kind + /// @brief ::ROCPROFILER_BUFFER_TRACING_RUNTIME_INITIALIZATION + /// @var operation + /// @brief Indicates which runtime was initialized/loaded + /// @var correlation_id + /// @brief Correlation ID for these records are always zero + /// @var thread_id + /// @brief ID for thread which loaded this runtime + /// @var timestamp + /// @brief Timestamp (in nanosec) of when runtime was initialized/loaded + /// @var version + /// @brief The version number of the runtime + /// + /// Version number is encoded as: (10000 * MAJOR) + (100 * MINOR) + PATCH + /// @var instance + /// @brief Number of times this runtime had been loaded previously +} rocprofiler_buffer_tracing_runtime_initialization_record_t; + /** * @brief Callback function for mapping @ref rocprofiler_buffer_tracing_kind_t ids to * string names. @see rocprofiler_iterate_buffer_trace_kind_names. diff --git a/source/include/rocprofiler-sdk/callback_tracing.h b/source/include/rocprofiler-sdk/callback_tracing.h index 633e7fb393..a3f282f140 100644 --- a/source/include/rocprofiler-sdk/callback_tracing.h +++ b/source/include/rocprofiler-sdk/callback_tracing.h @@ -236,6 +236,21 @@ typedef struct rocprofiler_callback_tracing_scratch_memory_data_t rocprofiler_scratch_memory_args_t args; } rocprofiler_callback_tracing_scratch_memory_data_t; +/** + * @brief ROCProfiler Runtime Initialization Data. + */ +typedef struct rocprofiler_callback_tracing_runtime_initialization_data_t +{ + uint64_t size; ///< size of this struct + uint64_t version; + uint64_t instance; ///< Number of times this runtime had been loaded previously + + /// @var version + /// @brief The version number of the library + /// + /// Version number is encoded as: (10000 * MAJOR) + (100 * MINOR) + PATCH +} rocprofiler_callback_tracing_runtime_initialization_data_t; + /** * @brief API Tracing callback function. This function is invoked twice per API function: once * before the function is invoked and once after the function is invoked. The external correlation diff --git a/source/include/rocprofiler-sdk/cxx/serialization.hpp b/source/include/rocprofiler-sdk/cxx/serialization.hpp index e8034fbddf..ff62fc7d9d 100644 --- a/source/include/rocprofiler-sdk/cxx/serialization.hpp +++ b/source/include/rocprofiler-sdk/cxx/serialization.hpp @@ -871,6 +871,29 @@ save(ArchiveT& ar, rocprofiler_record_dimension_info_t data) ROCP_SDK_SAVE_DATA_CSTR(name); } +template +void +save(ArchiveT& ar, rocprofiler_callback_tracing_runtime_initialization_data_t data) +{ + ROCP_SDK_SAVE_DATA_FIELD(size); + ROCP_SDK_SAVE_DATA_FIELD(version); + ROCP_SDK_SAVE_DATA_FIELD(instance); +} + +template +void +save(ArchiveT& ar, rocprofiler_buffer_tracing_runtime_initialization_record_t data) +{ + ROCP_SDK_SAVE_DATA_FIELD(size); + ROCP_SDK_SAVE_DATA_FIELD(kind); + ROCP_SDK_SAVE_DATA_FIELD(operation); + ROCP_SDK_SAVE_DATA_FIELD(correlation_id); + ROCP_SDK_SAVE_DATA_FIELD(timestamp); + ROCP_SDK_SAVE_DATA_FIELD(thread_id); + ROCP_SDK_SAVE_DATA_FIELD(version); + ROCP_SDK_SAVE_DATA_FIELD(instance); +} + template void save(ArchiveT& ar, const rocprofiler::sdk::utility::name_info& data) diff --git a/source/include/rocprofiler-sdk/fwd.h b/source/include/rocprofiler-sdk/fwd.h index a4453a7ed8..d2206c1784 100644 --- a/source/include/rocprofiler-sdk/fwd.h +++ b/source/include/rocprofiler-sdk/fwd.h @@ -173,6 +173,8 @@ typedef enum // NOLINT(performance-enum-size) ROCPROFILER_CALLBACK_TRACING_OPENMP, ///< @see ::rocprofiler_ompt_operation_t ROCPROFILER_CALLBACK_TRACING_MEMORY_ALLOCATION, ///< @see ///< ::rocprofiler_memory_allocation_operation_t + ROCPROFILER_CALLBACK_TRACING_RUNTIME_INITIALIZATION, ///< Callback notifying that a runtime + ///< library has been initialized ROCPROFILER_CALLBACK_TRACING_LAST, } rocprofiler_callback_tracing_kind_t; @@ -201,11 +203,14 @@ typedef enum // NOLINT(performance-enum-size) ROCPROFILER_BUFFER_TRACING_OPENMP, ///< @see ::rocprofiler_ompt_operation_t ROCPROFILER_BUFFER_TRACING_MEMORY_ALLOCATION, ///< @see ///< ::rocprofiler_memory_allocation_operation_t + ROCPROFILER_BUFFER_TRACING_RUNTIME_INITIALIZATION, ///< Record indicating a runtime library has + ///< been initialized. @see + ///< ::rocprofiler_runtime_initialization_operation_t ROCPROFILER_BUFFER_TRACING_LAST, } rocprofiler_buffer_tracing_kind_t; /** - * @brief ROCProfiler Code Object Tracer Operation. + * @brief ROCProfiler Code Object Tracer Operations. */ typedef enum // NOLINT(performance-enum-size) { @@ -216,7 +221,7 @@ typedef enum // NOLINT(performance-enum-size) } rocprofiler_code_object_operation_t; /** - * @brief Memory Copy Operation. + * @brief Memory Copy Operations. */ typedef enum // NOLINT(performance-enum-size) { @@ -378,6 +383,19 @@ typedef enum ROCPROFILER_TABLE_LAST = ROCPROFILER_RCCL_TABLE, } rocprofiler_intercept_table_t; +/** + * @brief ROCProfiler Runtime Initialization Tracer Operations. + */ +typedef enum // NOLINT(performance-enum-size) +{ + ROCPROFILER_RUNTIME_INITIALIZATION_NONE = 0, ///< Unknown runtime initialization + ROCPROFILER_RUNTIME_INITIALIZATION_HSA, ///< Application loaded HSA runtime + ROCPROFILER_RUNTIME_INITIALIZATION_HIP, ///< Application loaded HIP runtime + ROCPROFILER_RUNTIME_INITIALIZATION_MARKER, ///< Application loaded Marker (ROCTx) runtime + ROCPROFILER_RUNTIME_INITIALIZATION_RCCL, ///< Application loaded RCCL runtime + ROCPROFILER_RUNTIME_INITIALIZATION_LAST, +} rocprofiler_runtime_initialization_operation_t; + /** * @brief Enumeration for specifying the counter info struct version you want. */ diff --git a/source/lib/rocprofiler-sdk/CMakeLists.txt b/source/lib/rocprofiler-sdk/CMakeLists.txt index cef63334cf..449737e03a 100644 --- a/source/lib/rocprofiler-sdk/CMakeLists.txt +++ b/source/lib/rocprofiler-sdk/CMakeLists.txt @@ -3,8 +3,9 @@ # rocprofiler_activate_clang_tidy() -set(ROCPROFILER_LIB_HEADERS agent.hpp buffer.hpp external_correlation.hpp - intercept_table.hpp internal_threading.hpp registration.hpp) +set(ROCPROFILER_LIB_HEADERS + agent.hpp buffer.hpp external_correlation.hpp intercept_table.hpp + internal_threading.hpp registration.hpp runtime_initialization.hpp) set(ROCPROFILER_LIB_SOURCES agent.cpp buffer.cpp @@ -19,8 +20,9 @@ set(ROCPROFILER_LIB_SOURCES internal_threading.cpp pc_sampling.cpp profile_config.cpp + registration.cpp rocprofiler.cpp - registration.cpp) + runtime_initialization.cpp) # ----------------------------------------------------------------------------------------# # diff --git a/source/lib/rocprofiler-sdk/buffer_tracing.cpp b/source/lib/rocprofiler-sdk/buffer_tracing.cpp index 52ea8d43da..fe2e004f9e 100644 --- a/source/lib/rocprofiler-sdk/buffer_tracing.cpp +++ b/source/lib/rocprofiler-sdk/buffer_tracing.cpp @@ -20,13 +20,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include -#include -#include -#include -#include - #include "lib/common/logging.hpp" #include "lib/rocprofiler-sdk/context/context.hpp" #include "lib/rocprofiler-sdk/context/domain.hpp" @@ -40,6 +33,14 @@ #include "lib/rocprofiler-sdk/page_migration/page_migration.hpp" #include "lib/rocprofiler-sdk/rccl/rccl.hpp" #include "lib/rocprofiler-sdk/registration.hpp" +#include "lib/rocprofiler-sdk/runtime_initialization.hpp" + +#include +#include +#include +#include +#include +#include #include #include @@ -88,6 +89,7 @@ ROCPROFILER_BUFFER_TRACING_KIND_STRING(SCRATCH_MEMORY) ROCPROFILER_BUFFER_TRACING_KIND_STRING(CORRELATION_ID_RETIREMENT) ROCPROFILER_BUFFER_TRACING_KIND_STRING(RCCL_API) ROCPROFILER_BUFFER_TRACING_KIND_STRING(OPENMP) +ROCPROFILER_BUFFER_TRACING_KIND_STRING(RUNTIME_INITIALIZATION) template std::pair @@ -271,6 +273,11 @@ rocprofiler_query_buffer_tracing_kind_operation_name(rocprofiler_buffer_tracing_ val = rocprofiler::page_migration::name_by_id(operation); break; } + case ROCPROFILER_BUFFER_TRACING_RUNTIME_INITIALIZATION: + { + val = rocprofiler::runtime_init::name_by_id(operation); + break; + } case ROCPROFILER_BUFFER_TRACING_CORRELATION_ID_RETIREMENT: { return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED; @@ -396,6 +403,11 @@ rocprofiler_iterate_buffer_tracing_kind_operations( ops = rocprofiler::page_migration::get_ids(); break; } + case ROCPROFILER_BUFFER_TRACING_RUNTIME_INITIALIZATION: + { + ops = rocprofiler::runtime_init::get_ids(); + break; + } case ROCPROFILER_BUFFER_TRACING_CORRELATION_ID_RETIREMENT: { return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED; diff --git a/source/lib/rocprofiler-sdk/callback_tracing.cpp b/source/lib/rocprofiler-sdk/callback_tracing.cpp index e3ce91b635..9e6f3b7aa0 100644 --- a/source/lib/rocprofiler-sdk/callback_tracing.cpp +++ b/source/lib/rocprofiler-sdk/callback_tracing.cpp @@ -20,14 +20,6 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include -#include -#include -#include -#include -#include -#include - #include "lib/rocprofiler-sdk/code_object/code_object.hpp" #include "lib/rocprofiler-sdk/context/context.hpp" #include "lib/rocprofiler-sdk/context/domain.hpp" @@ -40,6 +32,15 @@ #include "lib/rocprofiler-sdk/marker/marker.hpp" #include "lib/rocprofiler-sdk/rccl/rccl.hpp" #include "lib/rocprofiler-sdk/registration.hpp" +#include "lib/rocprofiler-sdk/runtime_initialization.hpp" + +#include +#include +#include +#include +#include +#include +#include #include #include @@ -85,6 +86,7 @@ ROCPROFILER_CALLBACK_TRACING_KIND_STRING(MEMORY_COPY) ROCPROFILER_CALLBACK_TRACING_KIND_STRING(MEMORY_ALLOCATION) ROCPROFILER_CALLBACK_TRACING_KIND_STRING(RCCL_API) ROCPROFILER_CALLBACK_TRACING_KIND_STRING(OPENMP) +ROCPROFILER_CALLBACK_TRACING_KIND_STRING(RUNTIME_INITIALIZATION) template std::pair @@ -263,6 +265,10 @@ rocprofiler_query_callback_tracing_kind_operation_name(rocprofiler_callback_trac val = rocprofiler::hsa::memory_allocation::name_by_id(operation); break; } + case ROCPROFILER_CALLBACK_TRACING_RUNTIME_INITIALIZATION: + { + val = rocprofiler::runtime_init::name_by_id(operation); + } }; if(!val) @@ -387,6 +393,10 @@ rocprofiler_iterate_callback_tracing_kind_operations( ops = rocprofiler::hsa::memory_allocation::get_ids(); break; } + case ROCPROFILER_CALLBACK_TRACING_RUNTIME_INITIALIZATION: + { + ops = rocprofiler::runtime_init::get_ids(); + } }; for(const auto& itr : ops) @@ -519,6 +529,7 @@ rocprofiler_iterate_callback_tracing_kind_operation_args( case ROCPROFILER_CALLBACK_TRACING_MEMORY_ALLOCATION: case ROCPROFILER_CALLBACK_TRACING_RCCL_API: case ROCPROFILER_CALLBACK_TRACING_OPENMP: + case ROCPROFILER_CALLBACK_TRACING_RUNTIME_INITIALIZATION: { return ROCPROFILER_STATUS_ERROR_NOT_IMPLEMENTED; } diff --git a/source/lib/rocprofiler-sdk/hsa/async_copy.cpp b/source/lib/rocprofiler-sdk/hsa/async_copy.cpp index a8e4c4da80..f8a116d512 100644 --- a/source/lib/rocprofiler-sdk/hsa/async_copy.cpp +++ b/source/lib/rocprofiler-sdk/hsa/async_copy.cpp @@ -105,7 +105,7 @@ id_by_name(const char* name, std::index_sequence) if constexpr(sizeof...(IdxTail) > 0) return id_by_name(name, std::index_sequence{}); else - return ROCPROFILER_HSA_AMD_EXT_API_ID_NONE; + return ROCPROFILER_MEMORY_COPY_LAST; } template @@ -113,7 +113,7 @@ void get_ids(std::vector& _id_list, std::index_sequence) { auto _emplace = [](auto& _vec, uint32_t _v) { - if(_v < static_cast(ROCPROFILER_HSA_AMD_EXT_API_ID_LAST)) _vec.emplace_back(_v); + if(_v < static_cast(ROCPROFILER_MEMORY_COPY_LAST)) _vec.emplace_back(_v); }; (_emplace(_id_list, async_copy_info::operation_idx), ...); diff --git a/source/lib/rocprofiler-sdk/hsa/memory_allocation.cpp b/source/lib/rocprofiler-sdk/hsa/memory_allocation.cpp index 8226ed2e77..38648d6477 100644 --- a/source/lib/rocprofiler-sdk/hsa/memory_allocation.cpp +++ b/source/lib/rocprofiler-sdk/hsa/memory_allocation.cpp @@ -318,12 +318,12 @@ get_agent(T val, IterateFunc iterate_func, CallbackFunc callback) if(existing.count(val) == 0) { auto agents = rocprofiler::agent::get_agents(); - for(auto itr : agents) + for(const auto* itr : agents) { auto hsa_agent = rocprofiler::agent::get_hsa_agent(itr); if(hsa_agent) { - auto rocprof_agent = rocprofiler::agent::get_rocprofiler_agent(*hsa_agent); + const auto* rocprof_agent = rocprofiler::agent::get_rocprofiler_agent(*hsa_agent); if(rocprof_agent) { auto data = typename memory_allocation_info::pairtype{&existing, diff --git a/source/lib/rocprofiler-sdk/registration.cpp b/source/lib/rocprofiler-sdk/registration.cpp index 192ddb3c0b..9b26f3b9e8 100644 --- a/source/lib/rocprofiler-sdk/registration.cpp +++ b/source/lib/rocprofiler-sdk/registration.cpp @@ -45,6 +45,7 @@ #include "lib/rocprofiler-sdk/pc_sampling/code_object.hpp" #include "lib/rocprofiler-sdk/pc_sampling/service.hpp" #include "lib/rocprofiler-sdk/rccl/rccl.hpp" +#include "lib/rocprofiler-sdk/runtime_initialization.hpp" #include #include @@ -52,6 +53,9 @@ #include #include +#include +#include + #include #include @@ -59,9 +63,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -732,6 +736,11 @@ rocprofiler_set_api_table(const char* name, // install rocprofiler API wrappers rocprofiler::hip::update_table(hip_runtime_api_table); + // Tracing notifications the runtime has initialized + rocprofiler::runtime_init::initialize( + ROCPROFILER_RUNTIME_INITIALIZATION_HIP, lib_version, lib_instance); + + // allow tools to install API wrappers rocprofiler::intercept_table::notify_intercept_table_registration( ROCPROFILER_HIP_RUNTIME_TABLE, lib_version, @@ -754,6 +763,7 @@ rocprofiler_set_api_table(const char* name, // install rocprofiler API wrappers rocprofiler::hip::update_table(hip_compiler_api_table); + // allow tools to install API wrappers rocprofiler::intercept_table::notify_intercept_table_registration( ROCPROFILER_HIP_COMPILER_TABLE, lib_version, @@ -773,6 +783,12 @@ rocprofiler_set_api_table(const char* name, auto* hsa_api_table = static_cast(*tables); +#if ROCPROFILER_SDK_HSA_PC_SAMPLING > 0 + auto hsa_api_table_size = hsa_api_table->version.minor_id; + auto runtime_pc_sampling_table = + (offsetof(::HsaApiTable, pc_sampling_ext_) < hsa_api_table_size); +#endif + // store a reference of the HsaApiTable implementations for invoking these functions // without going through tracing wrappers rocprofiler::hsa::copy_table(hsa_api_table->core_, lib_instance); @@ -781,7 +797,8 @@ rocprofiler_set_api_table(const char* name, rocprofiler::hsa::copy_table(hsa_api_table->finalizer_ext_, lib_instance); rocprofiler::hsa::copy_table(hsa_api_table->tools_, lib_instance); #if ROCPROFILER_SDK_HSA_PC_SAMPLING > 0 - rocprofiler::hsa::copy_table(hsa_api_table->pc_sampling_ext_, lib_instance); + if(runtime_pc_sampling_table) + rocprofiler::hsa::copy_table(hsa_api_table->pc_sampling_ext_, lib_instance); #endif // need to construct agent mappings before initializing the queue controller @@ -796,7 +813,8 @@ rocprofiler_set_api_table(const char* name, rocprofiler::code_object::initialize(hsa_api_table); rocprofiler::thread_trace::initialize(hsa_api_table); #if ROCPROFILER_SDK_HSA_PC_SAMPLING > 0 - rocprofiler::pc_sampling::code_object::initialize(hsa_api_table); + if(runtime_pc_sampling_table) + rocprofiler::pc_sampling::code_object::initialize(hsa_api_table); #endif // install rocprofiler API wrappers @@ -808,9 +826,14 @@ rocprofiler_set_api_table(const char* name, #if ROCPROFILER_SDK_HSA_PC_SAMPLING > 0 // Initialize PC sampling service if configured - rocprofiler::pc_sampling::post_hsa_init_start_active_service(); + if(runtime_pc_sampling_table) + rocprofiler::pc_sampling::post_hsa_init_start_active_service(); #endif + // Tracing notifications the runtime has initialized + rocprofiler::runtime_init::initialize( + ROCPROFILER_RUNTIME_INITIALIZATION_HSA, lib_version, lib_instance); + // allow tools to install API wrappers rocprofiler::intercept_table::notify_intercept_table_registration( ROCPROFILER_HSA_TABLE, lib_version, lib_instance, std::make_tuple(hsa_api_table)); @@ -839,6 +862,11 @@ rocprofiler_set_api_table(const char* name, rocprofiler::marker::update_table(roctx_ctrl); rocprofiler::marker::update_table(roctx_name); + // Tracing notifications the runtime has initialized + rocprofiler::runtime_init::initialize( + ROCPROFILER_RUNTIME_INITIALIZATION_MARKER, lib_version, lib_instance); + + // allow tools to install API wrappers rocprofiler::intercept_table::notify_intercept_table_registration( ROCPROFILER_MARKER_CORE_TABLE, lib_version, lib_instance, std::make_tuple(roctx_core)); @@ -867,6 +895,11 @@ rocprofiler_set_api_table(const char* name, // install rocprofiler API wrappers rocprofiler::rccl::update_table(rccl_api); + // Tracing notifications the runtime has initialized + rocprofiler::runtime_init::initialize( + ROCPROFILER_RUNTIME_INITIALIZATION_RCCL, lib_version, lib_instance); + + // allow tools to install API wrappers rocprofiler::intercept_table::notify_intercept_table_registration( ROCPROFILER_RCCL_TABLE, lib_version, lib_instance, std::make_tuple(rccl_api)); } diff --git a/source/lib/rocprofiler-sdk/runtime_initialization.cpp b/source/lib/rocprofiler-sdk/runtime_initialization.cpp new file mode 100644 index 0000000000..46d7f233a4 --- /dev/null +++ b/source/lib/rocprofiler-sdk/runtime_initialization.cpp @@ -0,0 +1,162 @@ +// 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/runtime_initialization.hpp" +#include "lib/common/utility.hpp" +#include "lib/rocprofiler-sdk/context/context.hpp" +#include "lib/rocprofiler-sdk/tracing/fwd.hpp" +#include "lib/rocprofiler-sdk/tracing/tracing.hpp" + +#include + +#include +#include +#include +#include +#include + +namespace rocprofiler +{ +namespace runtime_init +{ +namespace +{ +template +struct runtime_init_info; + +#define SPECIALIZE_RUNTIME_INIT_INFO(NAME, PRETTY_NAME) \ + template <> \ + struct runtime_init_info \ + { \ + static constexpr auto operation_idx = ROCPROFILER_RUNTIME_INITIALIZATION_##NAME; \ + static constexpr auto name = "RUNTIME_INITIALIZATION_" #NAME; \ + static constexpr auto pretty_name = PRETTY_NAME; \ + }; + +SPECIALIZE_RUNTIME_INIT_INFO(NONE, "") +SPECIALIZE_RUNTIME_INIT_INFO(HSA, "HSA runtime") +SPECIALIZE_RUNTIME_INIT_INFO(HIP, "HIP runtime") +SPECIALIZE_RUNTIME_INIT_INFO(MARKER, "Marker (ROCTx) runtime") +SPECIALIZE_RUNTIME_INIT_INFO(RCCL, "RCCL runtime") + +#undef SPECIALIZE_RUNTIME_INIT_INFO + +template +std::pair +name_by_id(const uint32_t id, std::index_sequence) +{ + if(Idx == id) return {runtime_init_info::name, runtime_init_info::pretty_name}; + if constexpr(sizeof...(IdxTail) > 0) + return name_by_id(id, std::index_sequence{}); + else + return {nullptr, nullptr}; +} + +template +void +get_ids(std::vector& _id_list, std::index_sequence) +{ + auto _emplace = [](auto& _vec, uint32_t _v) { + if(_v < static_cast(ROCPROFILER_RUNTIME_INITIALIZATION_LAST)) + _vec.emplace_back(_v); + }; + + (_emplace(_id_list, runtime_init_info::operation_idx), ...); +} +} // namespace + +const char* +name_by_id(uint32_t id) +{ + return name_by_id(id, std::make_index_sequence{}) + .first; +} + +const char* +pretty_name_by_id(uint32_t id) +{ + return name_by_id(id, std::make_index_sequence{}) + .second; +} + +std::vector +get_ids() +{ + auto _data = std::vector{}; + _data.reserve(ROCPROFILER_RUNTIME_INITIALIZATION_LAST); + get_ids(_data, std::make_index_sequence{}); + return _data; +} + +void +initialize(rocprofiler_runtime_initialization_operation_t operation_idx, + uint64_t lib_version, + uint64_t lib_instance) +{ + using runtime_init_record_t = rocprofiler_buffer_tracing_runtime_initialization_record_t; + using runtime_init_data_t = rocprofiler_callback_tracing_runtime_initialization_data_t; + + constexpr auto callback_domain_idx = ROCPROFILER_CALLBACK_TRACING_RUNTIME_INITIALIZATION; + constexpr auto buffered_domain_idx = ROCPROFILER_BUFFER_TRACING_RUNTIME_INITIALIZATION; + constexpr auto corr_id = rocprofiler_correlation_id_t{0, rocprofiler_user_data_t{.value = 0}}; + + ROCP_INFO << pretty_name_by_id(operation_idx) << " has been initialized"; + + auto thr_id = common::get_tid(); + auto data = tracing::tracing_data{}; + + tracing::populate_contexts(callback_domain_idx, buffered_domain_idx, operation_idx, data); + + auto tracer_data = common::init_public_api_struct(runtime_init_data_t{}); + auto buffer_record = common::init_public_api_struct(runtime_init_record_t{}); + + { + tracer_data.version = lib_version; + tracer_data.instance = lib_instance; + tracing::execute_phase_none_callbacks(data.callback_contexts, + thr_id, + corr_id.internal, + data.external_correlation_ids, + callback_domain_idx, + operation_idx, + tracer_data); + } + + { + buffer_record.version = lib_version; + buffer_record.instance = lib_instance; + buffer_record.timestamp = common::timestamp_ns(); + tracing::execute_buffer_record_emplace(data.buffered_contexts, + thr_id, + corr_id.internal, + data.external_correlation_ids, + buffered_domain_idx, + operation_idx, + buffer_record); + } +} + +void +finalize() +{} +} // namespace runtime_init +} // namespace rocprofiler diff --git a/source/lib/rocprofiler-sdk/runtime_initialization.hpp b/source/lib/rocprofiler-sdk/runtime_initialization.hpp new file mode 100644 index 0000000000..035ad8ab20 --- /dev/null +++ b/source/lib/rocprofiler-sdk/runtime_initialization.hpp @@ -0,0 +1,51 @@ +// 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 + +#include +#include + +namespace rocprofiler +{ +namespace runtime_init +{ +const char* +name_by_id(uint32_t id); + +const char* +pretty_name_by_id(uint32_t id); + +std::vector +get_ids(); + +void +initialize(rocprofiler_runtime_initialization_operation_t _runtime, + uint64_t lib_version, + uint64_t lib_instance); + +void +finalize(); +} // namespace runtime_init +} // namespace rocprofiler diff --git a/tests/pytest-packages/pytest_utils/perfetto_reader.py b/tests/pytest-packages/pytest_utils/perfetto_reader.py index 48656771ec..8a7618dcdb 100644 --- a/tests/pytest-packages/pytest_utils/perfetto_reader.py +++ b/tests/pytest-packages/pytest_utils/perfetto_reader.py @@ -159,11 +159,15 @@ class PerfettoReader: _new_filenames = [x for x in self.filename if x not in _filenames] - def construct_trace_processor(trace_v): + _timeout = kwargs.get("timeout", 3) + + def construct_trace_processor(trace_v, timeout_v): for i in range(4): try: verbosity = True if i > 0 else False cfg = TraceProcessorConfig(verbose=verbosity) + if hasattr(cfg, "load_timeout"): + cfg.load_timeout = timeout_v + i return TraceProcessor(trace=(trace_v), config=cfg) except Exception as e: nwait = i + 1 @@ -176,9 +180,13 @@ class PerfettoReader: raise RuntimeError(f"Failed to construct trace processor for '{trace_v}'") if len(self.filename) + len(_new_filenames) != len(self.trace_processor): - self.trace_processor = [construct_trace_processor(f) for f in self.filename] + self.trace_processor = [ + construct_trace_processor(f, _timeout) for f in self.filename + ] elif _new_filenames: - self.trace_processor += [construct_trace_processor(f) for f in _new_filenames] + self.trace_processor += [ + construct_trace_processor(f, _timeout) for f in _new_filenames + ] self.max_depth = kwargs.get("max_depth", None) diff --git a/tests/tools/json-tool.cpp b/tests/tools/json-tool.cpp index f1b2d2dcea..8eb0c8af41 100644 --- a/tests/tools/json-tool.cpp +++ b/tests/tools/json-tool.cpp @@ -293,6 +293,23 @@ struct kernel_symbol_callback_record_t } }; +struct runtime_init_callback_record_t +{ + uint64_t timestamp = 0; + rocprofiler_callback_tracing_record_t record = {}; + rocprofiler_callback_tracing_runtime_initialization_data_t payload = {}; + callback_arg_array_t args = {}; + + template + void save(ArchiveT& ar) const + { + ar(cereal::make_nvp("timestamp", timestamp)); + cereal::save(ar, record); + ar(cereal::make_nvp("payload", payload)); + serialize_args(ar, args); + } +}; + struct hsa_api_callback_record_t { uint64_t timestamp = 0; @@ -489,6 +506,7 @@ struct profile_counting_record }; auto counter_info = std::deque{}; +auto runtime_init_cb_records = std::deque{}; auto code_object_records = std::deque{}; auto kernel_symbol_records = std::deque{}; auto hsa_api_cb_records = std::deque{}; @@ -735,12 +753,28 @@ tool_tracing_callback(rocprofiler_callback_tracing_record_t record, rccl_api_cb_records.emplace_back( rccl_api_callback_record_t{ts, record, *data, std::move(args)}); } + else if(record.kind == ROCPROFILER_CALLBACK_TRACING_RUNTIME_INITIALIZATION) + { + auto* data = static_cast( + record.payload); + auto args = callback_arg_array_t{}; + if(record.phase == ROCPROFILER_CALLBACK_PHASE_EXIT) + rocprofiler_iterate_callback_tracing_kind_operation_args( + record, save_args, record.phase, &args); + + static auto _mutex = std::mutex{}; + auto _lk = std::unique_lock{_mutex}; + runtime_init_cb_records.emplace_back( + runtime_init_callback_record_t{ts, record, *data, std::move(args)}); + } else { throw std::runtime_error{"unsupported callback kind"}; } } +auto runtime_init_bf_records = + std::deque{}; auto hsa_api_bf_records = std::deque{}; auto marker_api_bf_records = std::deque{}; auto hip_api_bf_records = std::deque{}; @@ -864,6 +898,14 @@ tool_tracing_buffered(rocprofiler_context_id_t /*context*/, rccl_api_bf_records.emplace_back(*record); } + else if(header->kind == ROCPROFILER_BUFFER_TRACING_RUNTIME_INITIALIZATION) + { + auto* record = + static_cast( + header->payload); + + runtime_init_bf_records.emplace_back(*record); + } else { throw std::runtime_error{ @@ -958,20 +1000,24 @@ rocprofiler_context_id_t corr_id_retire_ctx = {0}; rocprofiler_context_id_t kernel_dispatch_callback_ctx = {0}; rocprofiler_context_id_t kernel_dispatch_buffered_ctx = {0}; rocprofiler_context_id_t page_migration_ctx = {0}; +rocprofiler_context_id_t runtime_init_callback_ctx = {}; +rocprofiler_context_id_t runtime_init_buffered_ctx = {}; // buffers -rocprofiler_buffer_id_t hsa_api_buffered_buffer = {}; -rocprofiler_buffer_id_t hip_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 = {}; -rocprofiler_buffer_id_t memory_allocation_buffer = {}; -rocprofiler_buffer_id_t page_migration_buffer = {}; -rocprofiler_buffer_id_t counter_collection_buffer = {}; -rocprofiler_buffer_id_t scratch_memory_buffer = {}; -rocprofiler_buffer_id_t corr_id_retire_buffer = {}; -rocprofiler_buffer_id_t rccl_api_buffered_buffer = {}; +rocprofiler_buffer_id_t runtime_init_buffered_buffer = {}; +rocprofiler_buffer_id_t hsa_api_buffered_buffer = {}; +rocprofiler_buffer_id_t hip_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 = {}; +rocprofiler_buffer_id_t memory_allocation_buffer = {}; +rocprofiler_buffer_id_t page_migration_buffer = {}; +rocprofiler_buffer_id_t counter_collection_buffer = {}; +rocprofiler_buffer_id_t scratch_memory_buffer = {}; +rocprofiler_buffer_id_t corr_id_retire_buffer = {}; +rocprofiler_buffer_id_t rccl_api_buffered_buffer = {}; auto contexts = std::unordered_map{ + {"RUNTIME_INIT_CALLBACK", &runtime_init_callback_ctx}, {"HSA_API_CALLBACK", &hsa_api_callback_ctx}, {"HIP_API_CALLBACK", &hip_api_callback_ctx}, {"MARKER_API_CALLBACK", &marker_api_callback_ctx}, @@ -980,6 +1026,7 @@ auto contexts = std::unordered_map{ {"MEMORY_COPY_CALLBACK", &memory_copy_callback_ctx}, {"MEMORY_ALLOCATION_CALLBACK", &memory_allocation_callback_ctx}, {"RCCL_API_CALLBACK", &rccl_api_callback_ctx}, + {"RUNTIME_INIT_BUFFERED", &runtime_init_buffered_ctx}, {"HSA_API_BUFFERED", &hsa_api_buffered_ctx}, {"HIP_API_BUFFERED", &hip_api_buffered_ctx}, {"MARKER_API_BUFFERED", &marker_api_buffered_ctx}, @@ -993,7 +1040,8 @@ auto contexts = std::unordered_map{ {"RCCL_API_BUFFERED", &rccl_api_buffered_ctx}, }; -auto buffers = std::array{&hsa_api_buffered_buffer, +auto buffers = std::array{&runtime_init_buffered_buffer, + &hsa_api_buffered_buffer, &hip_api_buffered_buffer, &marker_api_buffered_buffer, &kernel_dispatch_buffer, @@ -1057,6 +1105,15 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data) "external correlation id request service configure"); } + ROCPROFILER_CALL(rocprofiler_configure_callback_tracing_service( + runtime_init_callback_ctx, + ROCPROFILER_CALLBACK_TRACING_RUNTIME_INITIALIZATION, + nullptr, + 0, + tool_tracing_callback, + nullptr), + "runtime init callback tracing service configure"); + for(auto itr : {ROCPROFILER_CALLBACK_TRACING_HSA_CORE_API, ROCPROFILER_CALLBACK_TRACING_HSA_AMD_EXT_API, ROCPROFILER_CALLBACK_TRACING_HSA_IMAGE_EXT_API, @@ -1163,6 +1220,15 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data) constexpr auto buffer_size = 8192; constexpr auto watermark = 7936; + ROCPROFILER_CALL(rocprofiler_create_buffer(runtime_init_buffered_ctx, + buffer_size, + watermark, + ROCPROFILER_BUFFER_POLICY_LOSSLESS, + tool_tracing_buffered, + tool_data, + &runtime_init_buffered_buffer), + "buffer creation"); + ROCPROFILER_CALL(rocprofiler_create_buffer(hsa_api_buffered_ctx, buffer_size, watermark, @@ -1262,6 +1328,14 @@ tool_init(rocprofiler_client_finalize_t fini_func, void* tool_data) &rccl_api_buffered_buffer), "buffer creation"); + ROCPROFILER_CALL(rocprofiler_configure_buffer_tracing_service( + runtime_init_buffered_ctx, + ROCPROFILER_BUFFER_TRACING_RUNTIME_INITIALIZATION, + nullptr, + 0, + runtime_init_buffered_buffer), + "buffer tracing service configure"); + for(auto itr : {ROCPROFILER_BUFFER_TRACING_HSA_CORE_API, ROCPROFILER_BUFFER_TRACING_HSA_AMD_EXT_API, ROCPROFILER_BUFFER_TRACING_HSA_IMAGE_EXT_API, @@ -1507,6 +1581,7 @@ tool_fini(void* tool_data) std::cerr << "[" << getpid() << "][" << __FUNCTION__ << "] Finalizing... agents=" << agents.size() + << ", runtime_init_callback_records=" << runtime_init_cb_records.size() << ", 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() @@ -1522,6 +1597,7 @@ tool_fini(void* tool_data) << ", memory_allocation_bf_records=" << memory_allocation_bf_records.size() << ", scratch_memory_records=" << scratch_memory_records.size() << ", page_migration=" << page_migration_records.size() + << ", runtime_init_bf_records=" << runtime_init_bf_records.size() << ", hsa_api_bf_records=" << hsa_api_bf_records.size() << ", hip_api_bf_records=" << hip_api_bf_records.size() << ", marker_api_bf_records=" << marker_api_bf_records.size() @@ -1611,6 +1687,7 @@ write_json(call_stack_t* _call_stack) try { json_ar(cereal::make_nvp("names", callbk_names)); + json_ar(cereal::make_nvp("runtime_init", runtime_init_cb_records)); 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)); @@ -1634,6 +1711,7 @@ write_json(call_stack_t* _call_stack) try { json_ar(cereal::make_nvp("names", buffer_names)); + json_ar(cereal::make_nvp("runtime_init", runtime_init_bf_records)); json_ar(cereal::make_nvp("kernel_dispatch", kernel_dispatch_bf_records)); json_ar(cereal::make_nvp("memory_copies", memory_copy_bf_records)); json_ar(cereal::make_nvp("memory_allocations", memory_allocation_bf_records));