diff --git a/projects/rocprofiler-systems/source/lib/core/trace_cache/buffer_storage.cpp b/projects/rocprofiler-systems/source/lib/core/trace_cache/buffer_storage.cpp index b463835fc2..7b84d4ec57 100644 --- a/projects/rocprofiler-systems/source/lib/core/trace_cache/buffer_storage.cpp +++ b/projects/rocprofiler-systems/source/lib/core/trace_cache/buffer_storage.cpp @@ -42,7 +42,7 @@ namespace trace_cache namespace { constexpr auto CACHE_FILE_FLUSH_TIMEOUT = 10ms; -constexpr auto NUM_OF_THREADS = 1; +constexpr auto NUM_OF_THREADS = 1; } // namespace buffer_storage::buffer_storage(pid_t _pid) diff --git a/projects/rocprofiler-systems/source/lib/core/trace_cache/buffer_storage.hpp b/projects/rocprofiler-systems/source/lib/core/trace_cache/buffer_storage.hpp index 1996edbe6d..fdddf14d93 100644 --- a/projects/rocprofiler-systems/source/lib/core/trace_cache/buffer_storage.hpp +++ b/projects/rocprofiler-systems/source/lib/core/trace_cache/buffer_storage.hpp @@ -26,6 +26,7 @@ #include "PTL/ThreadPool.hh" #include "cache_utility.hpp" #include "sample_type.hpp" +#include #include #include #include @@ -37,7 +38,6 @@ #include #include #include -#include #include namespace rocprofsys @@ -63,7 +63,8 @@ public: constexpr bool is_supported_type = (supported_types::is_supported && ...); static_assert(is_supported_type, "Supported types are const char*, char*, " - "unsigned long, unsigned int, and int."); + "unsigned long, unsigned int, long, unsigned " + "char, std::vector and int."); auto arg_size = get_size(values...); auto total_size = arg_size + sizeof(type) + sizeof(size_t); @@ -79,6 +80,13 @@ public: len = strlen(val) + 1; std::memcpy(dest, val, len); } + else if constexpr(std::is_same_v, std::vector>) + { + size_t elem_count = val.size(); + len = elem_count + sizeof(size_t); + std::memcpy(dest, &elem_count, sizeof(size_t)); + std::memcpy(dest + sizeof(size_t), val.data(), val.size()); + } else { using ClearType = std::decay_t; @@ -110,7 +118,8 @@ private: (std::is_same_v, Types> || ...); }; - using supported_types = typelist; + using supported_types = typelist, uint8_t, int64_t>; template static constexpr bool is_string_literal_v = @@ -129,6 +138,10 @@ private: } return ++size; } + else if constexpr(std::is_same_v, std::vector>) + { + return val.size() + sizeof(size_t); + } else { return sizeof(T); @@ -144,18 +157,18 @@ private: } private: - std::mutex m_mutex; - std::condition_variable m_exit_condition; - bool m_exit_finished{ false }; - bool m_running{ true }; - std::condition_variable m_shutdown_condition; + std::mutex m_mutex; + std::condition_variable m_exit_condition; + bool m_exit_finished{ false }; + bool m_running{ true }; + std::condition_variable m_shutdown_condition; - std::unique_ptrm_thread_pool; + std::unique_ptr m_thread_pool; std::unique_ptr> m_task_group; - size_t m_head{ 0 }; - size_t m_tail{ 0 }; - std::unique_ptr m_buffer{ std::make_unique() }; - pid_t m_created_process; + size_t m_head{ 0 }; + size_t m_tail{ 0 }; + std::unique_ptr m_buffer{ std::make_unique() }; + pid_t m_created_process; }; } // namespace trace_cache diff --git a/projects/rocprofiler-systems/source/lib/core/trace_cache/metadata_registry.hpp b/projects/rocprofiler-systems/source/lib/core/trace_cache/metadata_registry.hpp index 2c8a0471bb..6e53b34398 100644 --- a/projects/rocprofiler-systems/source/lib/core/trace_cache/metadata_registry.hpp +++ b/projects/rocprofiler-systems/source/lib/core/trace_cache/metadata_registry.hpp @@ -24,6 +24,7 @@ #include "common/synchronized.hpp" #include "core/agent.hpp" +#include "core/categories.hpp" #include #include @@ -35,6 +36,7 @@ # include #endif #include +#include #include #include #include @@ -53,6 +55,19 @@ struct process pid_t ppid; std::string command; }; + +template +inline std::string +annotate_category(std::optional first_section = std::nullopt, + std::optional second_section = std::nullopt) +{ + std::stringstream ss; + ss << std::string(tim::trait::name::value); + if(first_section) ss << "_" << std::to_string(*first_section); + if(second_section) ss << "_" << std::to_string(*second_section); + return ss.str(); +} + struct pmc { agent_type type; @@ -108,6 +123,20 @@ struct thread } }; +template +inline std::string +annotate_with_device_id(uint32_t device_id, + std::optional first_section = std::nullopt, + std::optional second_section = std::nullopt) +{ + std::stringstream ss; + ss << std::string(tim::trait::name::value) + " [" + + std::to_string(device_id) + "]"; + if(first_section) ss << "_" << std::to_string(*first_section); + if(second_section) ss << "_" << std::to_string(*second_section); + return ss.str(); +} + struct track { std::string track_name; // < Unique diff --git a/projects/rocprofiler-systems/source/lib/core/trace_cache/rocpd_post_processing.cpp b/projects/rocprofiler-systems/source/lib/core/trace_cache/rocpd_post_processing.cpp index f3777e8690..e7c4ad0115 100644 --- a/projects/rocprofiler-systems/source/lib/core/trace_cache/rocpd_post_processing.cpp +++ b/projects/rocprofiler-systems/source/lib/core/trace_cache/rocpd_post_processing.cpp @@ -33,6 +33,7 @@ #include "trace_cache/storage_parser.hpp" #include #include +#include #include #include #include @@ -375,6 +376,265 @@ rocpd_post_processing::get_pmc_event_with_sample_callback() const }; } +postprocessing_callback +rocpd_post_processing::get_amd_smi_sample_callback() const +{ + struct xcp_metrics_t + { + std::vector vcn_busy; + std::vector jpeg_busy; + }; + + auto deserialize_xcp_metrics = [](const std::vector& serialized_data, + bool& _is_vcn_supported, bool& _is_jpeg_supported, + std::vector& result) { + if(serialized_data.size() < 5) + { + throw std::runtime_error("Invalid serialized data: insufficient header size"); + } + + size_t offset = 0; + + // Read header + _is_vcn_supported = static_cast(serialized_data[offset++]); + _is_jpeg_supported = static_cast(serialized_data[offset++]); + uint8_t chunk_count = serialized_data[offset++]; + uint8_t vcn_count = serialized_data[offset++]; + uint8_t jpeg_count = serialized_data[offset++]; + + constexpr size_t elem_size = sizeof(uint16_t) / sizeof(uint8_t); + const size_t chunk_size = (vcn_count + jpeg_count) * elem_size; + + // Validate total size + const size_t expected_size = 5 + (chunk_count * chunk_size); + if(serialized_data.size() != expected_size) + { + throw std::runtime_error("Invalid serialized data: size mismatch"); + } + + auto deserialize_uint16_array = [](const std::vector& data, + size_t& _offset, int array_size) { + std::vector _result; + _result.reserve(array_size); + + for(int i = 0; i < array_size; ++i) + { + if(_offset + 1 >= data.size()) + { + throw std::runtime_error( + "Invalid serialized data: unexpected end of data"); + } + + uint16_t value = static_cast(data[_offset]) | + (static_cast(data[_offset + 1]) << 8); + _result.push_back(value); + _offset += 2; + } + + return _result; + }; + + result.reserve(chunk_count); + + for(size_t count = 0; count < chunk_count; ++count) + { + xcp_metrics_t entry; + entry.vcn_busy = deserialize_uint16_array(serialized_data, offset, vcn_count); + entry.jpeg_busy = + deserialize_uint16_array(serialized_data, offset, jpeg_count); + + result.emplace_back(std::move(entry)); + } + }; + + return [&](const storage_parsed_type_base& parsed) { + auto _amd_smi = static_cast(parsed); + + auto& data_processor = get_data_processor(); + + const auto* _name = trait::name::value; + auto name_primary_key = data_processor.insert_string(_name); + auto event_id = data_processor.insert_event(name_primary_key, 0, 0, 0); + + auto& _agent_manager = agent_manager::get_instance(); + auto base_id = + _agent_manager.get_agent_by_type_index(_amd_smi.device_id, agent_type::GPU) + .base_id; + + auto insert_event_and_sample = [&](bool enabled, const char* pmc_name, + const char* track_name, double value) { + if(!enabled) return; + data_processor.insert_pmc_event(event_id, base_id, pmc_name, value); + data_processor.insert_sample(track_name, _amd_smi.timestamp, event_id); + }; + + using pos = trace_cache::amd_smi_sample::settings_positions; + std::bitset<8> settings_bits(_amd_smi.settings); + bool is_busy_enabled = settings_bits.test(static_cast(pos::busy)); + bool is_temp_enabled = settings_bits.test(static_cast(pos::temp)); + bool is_power_enabled = settings_bits.test(static_cast(pos::power)); + bool is_mem_usage_enabled = settings_bits.test(static_cast(pos::mem_usage)); + + bool is_vcn_enabled = settings_bits.test(static_cast(pos::vcn_activity)); + bool is_jpeg_enabled = settings_bits.test(static_cast(pos::jpeg_activity)); + + insert_event_and_sample( + is_busy_enabled, trait::name::value, + info::annotate_with_device_id(_amd_smi.device_id) + .c_str(), + _amd_smi.gfx_activity); + insert_event_and_sample( + is_busy_enabled, trait::name::value, + info::annotate_with_device_id(_amd_smi.device_id) + .c_str(), + _amd_smi.umc_activity); + insert_event_and_sample( + is_busy_enabled, trait::name::value, + info::annotate_with_device_id(_amd_smi.device_id) + .c_str(), + _amd_smi.mm_activity); + insert_event_and_sample( + is_temp_enabled, trait::name::value, + info::annotate_with_device_id(_amd_smi.device_id) + .c_str(), + _amd_smi.temperature); + + insert_event_and_sample( + is_power_enabled, trait::name::value, + info::annotate_with_device_id(_amd_smi.device_id) + .c_str(), + _amd_smi.power); + insert_event_and_sample( + is_mem_usage_enabled, trait::name::value, + info::annotate_with_device_id( + _amd_smi.device_id) + .c_str(), + _amd_smi.mem_usage); + + if(!is_vcn_enabled && !is_jpeg_enabled) + { + return; + } + + std::vector xcp_metrics; + bool is_vcn_activity_supported; + bool is_jpeg_activity_supported; + deserialize_xcp_metrics(_amd_smi.xcp_activity, is_vcn_activity_supported, + is_jpeg_activity_supported, xcp_metrics); + + auto insert_xcp_metrics = [&](auto category, bool _is_enabled, + const std::vector& data, + std::optional _idx = std::nullopt) { + if(!_is_enabled) + { + return; + } + + using Category = std::decay_t; + + for(size_t clk = 0; clk < data.size(); ++clk) + { + const auto value = data[clk]; + if(value == std::numeric_limits::max()) + { + continue; + } + + auto pmc_name = info::annotate_category(_idx, clk); + auto track_name = info::annotate_with_device_id( + _amd_smi.device_id, _idx, clk); + + insert_event_and_sample(_is_enabled, pmc_name.c_str(), track_name.c_str(), + value); + } + }; + + for(size_t idx = 0; idx < xcp_metrics.size(); ++idx) + { + auto dimension = + xcp_metrics.size() == 1 ? std::nullopt : std::make_optional(idx); + + insert_xcp_metrics(category::amd_smi_vcn_activity{}, is_vcn_enabled, + xcp_metrics[idx].vcn_busy, dimension); + + insert_xcp_metrics(category::amd_smi_jpeg_activity{}, is_jpeg_enabled, + xcp_metrics[idx].jpeg_busy, dimension); + } + }; +} + +postprocessing_callback +rocpd_post_processing::get_cpu_freq_sample_callback() const +{ + struct core_freq_sample + { + size_t id; + float value; + }; + + auto deserialize_freqs = [](std::vector& buffer) { + std::vector result; + size_t offset = 0; + + while(offset + sizeof(float) + sizeof(size_t) <= buffer.size()) + { + core_freq_sample core_sample; + std::memcpy(&core_sample.id, buffer.data() + offset, sizeof(size_t)); + offset += sizeof(size_t); + std::memcpy(&core_sample.value, buffer.data() + offset, sizeof(float)); + offset += sizeof(float); + result.push_back(core_sample); + } + return result; + }; + + return [&](const storage_parsed_type_base& parsed) { + auto _cpu_freq_sample = static_cast(parsed); + + auto& data_processor = get_data_processor(); + const auto* _name = trait::name::value; + auto name_primary_key = data_processor.insert_string(_name); + auto event_id = data_processor.insert_event(name_primary_key, 0, 0, 0); + + auto device_id = 0; + + auto& agent_mngr = agent_manager::get_instance(); + auto base_id = + agent_mngr.get_agent_by_type_index(device_id, agent_type::CPU).base_id; + + auto insert_event_and_sample = [&](const char* name, double value) { + data_processor.insert_pmc_event(event_id, base_id, name, value); + data_processor.insert_sample(name, _cpu_freq_sample.timestamp, event_id); + }; + + insert_event_and_sample(trait::name::value, + _cpu_freq_sample.page_rss); + insert_event_and_sample(trait::name::value, + _cpu_freq_sample.virt_mem_usage); + insert_event_and_sample(trait::name::value, + _cpu_freq_sample.peak_rss); + insert_event_and_sample(trait::name::value, + _cpu_freq_sample.context_switch_count); + insert_event_and_sample(trait::name::value, + _cpu_freq_sample.page_faults); + insert_event_and_sample(trait::name::value, + _cpu_freq_sample.user_mode_time); + insert_event_and_sample(trait::name::value, + _cpu_freq_sample.kernel_mode_time); + + auto get_track_name = [](const auto& cpu_id) { + return std::string(trait::name::value) + " [" + + std::to_string(cpu_id) + "]"; + }; + + auto core_freq_samples = deserialize_freqs(_cpu_freq_sample.freqs); + for(const auto& core : core_freq_samples) + { + insert_event_and_sample(get_track_name(core.id).c_str(), core.value); + } + }; +} + rocpd_post_processing::rocpd_post_processing(metadata_registry& md) : m_metadata(md) {} @@ -399,6 +659,10 @@ rocpd_post_processing::register_parser_callback([[maybe_unused]] storage_parser& get_in_time_sample_callback()); parser.register_type_callback(entry_type::pmc_event_with_sample, get_pmc_event_with_sample_callback()); + parser.register_type_callback(entry_type::amd_smi_sample, + get_amd_smi_sample_callback()); + parser.register_type_callback(entry_type::cpu_freq_sample, + get_cpu_freq_sample_callback()); ROCPROFSYS_DEBUG("Buffer parser callbacks are registered.."); #endif } diff --git a/projects/rocprofiler-systems/source/lib/core/trace_cache/rocpd_post_processing.hpp b/projects/rocprofiler-systems/source/lib/core/trace_cache/rocpd_post_processing.hpp index b2d9a228e8..b968697c9a 100644 --- a/projects/rocprofiler-systems/source/lib/core/trace_cache/rocpd_post_processing.hpp +++ b/projects/rocprofiler-systems/source/lib/core/trace_cache/rocpd_post_processing.hpp @@ -52,6 +52,8 @@ private: postprocessing_callback get_region_callback() const; postprocessing_callback get_in_time_sample_callback() const; postprocessing_callback get_pmc_event_with_sample_callback() const; + postprocessing_callback get_amd_smi_sample_callback() const; + postprocessing_callback get_cpu_freq_sample_callback() const; metadata_registry& m_metadata; }; diff --git a/projects/rocprofiler-systems/source/lib/core/trace_cache/sample_type.hpp b/projects/rocprofiler-systems/source/lib/core/trace_cache/sample_type.hpp index bf7941e788..b548756643 100644 --- a/projects/rocprofiler-systems/source/lib/core/trace_cache/sample_type.hpp +++ b/projects/rocprofiler-systems/source/lib/core/trace_cache/sample_type.hpp @@ -21,10 +21,13 @@ // SOFTWARE. #pragma once +#include #include #include #include #include +#include +#include #if ROCPROFSYS_USE_ROCM > 0 # include @@ -182,6 +185,43 @@ struct pmc_event_with_sample : in_time_sample size_t value; }; +struct amd_smi_sample : storage_parsed_type_base +{ + enum class settings_positions : uint8_t + { + busy = 0, + temp, + power, + mem_usage, + vcn_activity, + jpeg_activity + }; + + uint64_t settings; // bitfield + uint32_t device_id; + size_t timestamp; + uint32_t gfx_activity; + uint32_t umc_activity; + uint32_t mm_activity; + uint32_t power; + int64_t temperature; + size_t mem_usage; + std::vector xcp_activity; +}; + +struct cpu_freq_sample : storage_parsed_type_base +{ + size_t timestamp; + int64_t page_rss; + int64_t virt_mem_usage; + int64_t peak_rss; + int64_t context_switch_count; + int64_t page_faults; + int64_t user_mode_time; + int64_t kernel_mode_time; + std::vector freqs; +}; + enum class entry_type : uint32_t { in_time_sample = 0x0000, @@ -192,6 +232,8 @@ enum class entry_type : uint32_t #if(ROCPROFSYS_USE_ROCM && ROCPROFILER_VERSION >= 600) memory_alloc = 0x0005, #endif + amd_smi_sample = 0x0006, + cpu_freq_sample = 0x0007, fragmented_space = 0xFFFF }; } // namespace trace_cache diff --git a/projects/rocprofiler-systems/source/lib/core/trace_cache/storage_parser.cpp b/projects/rocprofiler-systems/source/lib/core/trace_cache/storage_parser.cpp index 1f0d23f293..bf258548bd 100644 --- a/projects/rocprofiler-systems/source/lib/core/trace_cache/storage_parser.cpp +++ b/projects/rocprofiler-systems/source/lib/core/trace_cache/storage_parser.cpp @@ -23,6 +23,7 @@ #include "storage_parser.hpp" #include "debug.hpp" #include "trace_cache/sample_type.hpp" +#include #include #include #include @@ -201,6 +202,30 @@ storage_parser::consume_storage() invoke_callbacks(header.type, _pmc_event_with_sample); break; } + case entry_type::amd_smi_sample: + { + amd_smi_sample _amd_smi_sample; + parse_data(sample.data(), _amd_smi_sample.settings, + _amd_smi_sample.device_id, _amd_smi_sample.timestamp, + _amd_smi_sample.gfx_activity, _amd_smi_sample.umc_activity, + _amd_smi_sample.mm_activity, _amd_smi_sample.power, + _amd_smi_sample.temperature, _amd_smi_sample.mem_usage, + _amd_smi_sample.xcp_activity); + invoke_callbacks(header.type, _amd_smi_sample); + break; + } + case entry_type::cpu_freq_sample: + { + cpu_freq_sample _cpu_freq_sample; + parse_data(sample.data(), _cpu_freq_sample.timestamp, + _cpu_freq_sample.page_rss, _cpu_freq_sample.virt_mem_usage, + _cpu_freq_sample.peak_rss, + _cpu_freq_sample.context_switch_count, + _cpu_freq_sample.page_faults, _cpu_freq_sample.user_mode_time, + _cpu_freq_sample.kernel_mode_time, _cpu_freq_sample.freqs); + invoke_callbacks(header.type, _cpu_freq_sample); + break; + } default: break; } } diff --git a/projects/rocprofiler-systems/source/lib/core/trace_cache/storage_parser.hpp b/projects/rocprofiler-systems/source/lib/core/trace_cache/storage_parser.hpp index a1e342917c..7d569709e0 100644 --- a/projects/rocprofiler-systems/source/lib/core/trace_cache/storage_parser.hpp +++ b/projects/rocprofiler-systems/source/lib/core/trace_cache/storage_parser.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,14 @@ private: arg = std::string((const char*) data_pos); data_pos += arg.size() + 1; } + else if constexpr(std::is_same_v>) + { + size_t vector_size = *reinterpret_cast(data_pos); + data_pos += sizeof(size_t); + arg.reserve(vector_size); + std::copy_n(data_pos, vector_size, std::back_inserter(arg)); + data_pos += vector_size; + } else { arg = *reinterpret_cast(data_pos); diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/amd_smi.cpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/amd_smi.cpp index f27f236fb1..4e56854195 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/amd_smi.cpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/amd_smi.cpp @@ -29,11 +29,13 @@ #include "core/agent.hpp" #include "core/trace_cache/cache_manager.hpp" #include "core/trace_cache/cache_utility.hpp" +#include "core/trace_cache/sample_type.hpp" +#include +#include #if defined(NDEBUG) # undef NDEBUG #endif -#include "core/agent_manager.hpp" #include "core/common.hpp" #include "core/components/fwd.hpp" #include "core/config.hpp" @@ -41,7 +43,6 @@ #include "core/gpu.hpp" #include "core/node_info.hpp" #include "core/perfetto.hpp" -#include "core/rocpd/data_processor.hpp" #include "core/state.hpp" #include "core/trace_cache/metadata_registry.hpp" #include "library/amd_smi.hpp" @@ -74,19 +75,6 @@ using sampler_instances = thread_data; namespace { -int64_t -get_tid() -{ - static thread_local auto _v = threading::get_id(); - return _v; -} - -rocpd::data_processor& -get_data_processor() -{ - return rocpd::data_processor::get_instance(); -} - void metadata_initialize_category() { @@ -95,18 +83,73 @@ metadata_initialize_category() } void -metadata_initialize_smi_tracks() +metadata_initialize_smi_tracks(size_t gpu_id) { const auto thread_id = std::nullopt; trace_cache::get_metadata_registry().add_track( - { trait::name::value, thread_id, "{}" }); + { trace_cache::info::annotate_with_device_id(gpu_id), + thread_id, "{}" }); trace_cache::get_metadata_registry().add_track( - { trait::name::value, thread_id, "{}" }); + { trace_cache::info::annotate_with_device_id(gpu_id), + thread_id, "{}" }); trace_cache::get_metadata_registry().add_track( - { trait::name::value, thread_id, "{}" }); + { trace_cache::info::annotate_with_device_id(gpu_id), + thread_id, "{}" }); trace_cache::get_metadata_registry().add_track( - { trait::name::value, thread_id, "{}" }); + { trace_cache::info::annotate_with_device_id(gpu_id), + thread_id, "{}" }); + trace_cache::get_metadata_registry().add_track( + { trace_cache::info::annotate_with_device_id(gpu_id), + thread_id, "{}" }); + trace_cache::get_metadata_registry().add_track( + { trace_cache::info::annotate_with_device_id( + gpu_id), + thread_id, "{}" }); + + auto add_vcn_track = [&](std::optional xcp_idx) { + for(auto clk = 0; clk < AMDSMI_MAX_NUM_VCN; ++clk) + { + auto name = trace_cache::info::annotate_with_device_id< + category::amd_smi_vcn_activity>(gpu_id, xcp_idx, clk); + trace_cache::get_metadata_registry().add_track( + { name.c_str(), thread_id, "{}" }); + } + }; + + auto add_jpeg_track = [&](std::optional xcp_idx) { + for(auto clk = 0; clk < AMDSMI_MAX_NUM_JPEG; ++clk) + { + auto name = trace_cache::info::annotate_with_device_id< + category::amd_smi_jpeg_activity>(gpu_id, xcp_idx, clk); + trace_cache::get_metadata_registry().add_track( + { name.c_str(), thread_id, "{}" }); + } + }; + + if(gpu::is_vcn_activity_supported(gpu_id)) + { + add_vcn_track(std::nullopt); + } + else + { + for(int xcp = 0; xcp < AMDSMI_MAX_NUM_XCP; ++xcp) + { + add_vcn_track(xcp); + } + } + + if(gpu::is_jpeg_activity_supported(gpu_id)) + { + add_jpeg_track(std::nullopt); + } + else + { + for(auto xcp = 0; xcp < AMDSMI_MAX_NUM_XCP; ++xcp) + { + add_jpeg_track(xcp); + } + } } void @@ -125,7 +168,21 @@ metadata_initialize_smi_pmc(size_t gpu_id) trace_cache::get_metadata_registry().add_pmc_info( { agent_type::GPU, gpu_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID, - trait::name::value, "Busy", + trait::name::value, "GFX Busy", + trait::name::description, LONG_DESCRIPTION, + COMPONENT, trace_cache::PERCENTAGE, rocprofsys::trace_cache::ABSOLUTE, BLOCK, + EXPRESSION, 0, 0, "{}" }); + + trace_cache::get_metadata_registry().add_pmc_info( + { agent_type::GPU, gpu_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID, + trait::name::value, "UMC Busy", + trait::name::description, LONG_DESCRIPTION, + COMPONENT, trace_cache::PERCENTAGE, rocprofsys::trace_cache::ABSOLUTE, BLOCK, + EXPRESSION, 0, 0, "{}" }); + + trace_cache::get_metadata_registry().add_pmc_info( + { agent_type::GPU, gpu_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID, + trait::name::value, "MM Busy", trait::name::description, LONG_DESCRIPTION, COMPONENT, trace_cache::PERCENTAGE, rocprofsys::trace_cache::ABSOLUTE, BLOCK, EXPRESSION, 0, 0, "{}" }); @@ -148,39 +205,74 @@ metadata_initialize_smi_pmc(size_t gpu_id) trait::name::description, LONG_DESCRIPTION, COMPONENT, tim::units::mem_repr(tim::units::megabyte), rocprofsys::trace_cache::ABSOLUTE, BLOCK, EXPRESSION, 0, 0 }); -} -void -rocpd_process_smi_pmc_events(const uint32_t device_id, const amd_smi::settings& settings, - uint64_t timestamp, double busy, double temp, double power, - double usage) -{ - if(!(settings.busy || settings.temp || settings.power || settings.mem_usage)) return; + auto add_vcn_pmc = [&](std::optional xcp_idx) { + for(int clk = 0; clk < AMDSMI_MAX_NUM_VCN; ++clk) + { + std::stringstream name_ss; + name_ss << trait::name::value; + if(xcp_idx) name_ss << "_" << *xcp_idx; + name_ss << "_" << clk; - auto& data_processor = get_data_processor(); + std::stringstream symbol_ss; + symbol_ss << "VcnAct"; + if(xcp_idx) symbol_ss << "_" << *xcp_idx; + symbol_ss << "_" << clk; - const auto* _name = trait::name::value; - auto name_primary_key = data_processor.insert_string(_name); - auto event_id = data_processor.insert_event(name_primary_key, 0, 0, 0); - - auto& _agent_manager = agent_manager::get_instance(); - auto base_id = - _agent_manager.get_agent_by_type_index(device_id, agent_type::GPU).base_id; - - auto insert_event_and_sample = [&](bool enabled, const char* name, double value) { - if(!enabled) return; - data_processor.insert_pmc_event(event_id, base_id, name, value); - data_processor.insert_sample(name, timestamp, event_id); + trace_cache::get_metadata_registry().add_pmc_info( + { agent_type::GPU, gpu_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID, + name_ss.str(), symbol_ss.str(), + trait::name::description, + LONG_DESCRIPTION, COMPONENT, trace_cache::PERCENTAGE, + rocprofsys::trace_cache::ABSOLUTE, BLOCK, EXPRESSION, 0, 0 }); + } }; - insert_event_and_sample(settings.busy, trait::name::value, - busy); - insert_event_and_sample(settings.temp, trait::name::value, - temp); - insert_event_and_sample(settings.power, trait::name::value, - power); - insert_event_and_sample(settings.mem_usage, - trait::name::value, usage); + auto add_jpeg_pmc = [&](std::optional xcp_idx) { + for(auto clk = 0; clk < AMDSMI_MAX_NUM_JPEG; ++clk) + { + std::stringstream name_ss; + name_ss << trait::name::value; + if(xcp_idx) name_ss << "_" << *xcp_idx; + name_ss << "_" << std::to_string(clk); + + std::stringstream symbol_ss; + symbol_ss << "JpegAct"; + if(xcp_idx) symbol_ss << "_" << *xcp_idx; + symbol_ss << "_" << std::to_string(clk); + + trace_cache::get_metadata_registry().add_pmc_info( + { agent_type::GPU, gpu_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID, + name_ss.str(), symbol_ss.str(), + trait::name::description, + LONG_DESCRIPTION, COMPONENT, trace_cache::PERCENTAGE, + rocprofsys::trace_cache::ABSOLUTE, BLOCK, EXPRESSION, 0, 0 }); + } + }; + + if(gpu::is_vcn_activity_supported(gpu_id)) + { + add_vcn_pmc(std::nullopt); + } + else + { + for(int xcp = 0; xcp < AMDSMI_MAX_NUM_XCP; ++xcp) + { + add_vcn_pmc(xcp); + } + } + + if(gpu::is_jpeg_activity_supported(gpu_id)) + { + add_jpeg_pmc(std::nullopt); + } + else + { + for(auto xcp = 0; xcp < AMDSMI_MAX_NUM_XCP; ++xcp) + { + add_jpeg_pmc(xcp); + } + } } auto& @@ -241,6 +333,101 @@ get_state() static std::atomic _v{ State::PreInit }; return _v; } + +std::vector +serialize_xcp_metrics(const bool& use_vcn_activity, const bool& use_jpeg_activity, + const amdsmi_gpu_metrics_t& gpu_metrics) +{ + // Chunk: + // .. // lower and higher byte + // .. // lower and higher byte + + // Serialized: + // + // + // + // + // + // Chunk_0 + // ... + // Chunk_[xcp_count] + + constexpr uint8_t vcn_count = AMDSMI_MAX_NUM_VCN; + constexpr uint8_t jpeg_count = AMDSMI_MAX_NUM_JPEG; + constexpr uint8_t xcp_count = AMDSMI_MAX_NUM_XCP; + constexpr size_t elem_size = sizeof(uint16_t) / sizeof(uint8_t); + constexpr uint8_t vector_size_header = sizeof(uint8_t); + constexpr uint8_t serialized_data_headers = + 5 * vector_size_header; // is_vcn_supported + is_jpeg_supported + xcp_count + + // vcn_count + jpeg_count + constexpr size_t chunk_size = ((vcn_count + jpeg_count) * elem_size); + + auto serialize_uint16_array = [](std::vector& data, const uint16_t* arr, + int array_size) { + for(int i = 0; i < array_size; ++i) + { + data.push_back(static_cast(arr[i] & 0xFF)); + data.push_back(static_cast((arr[i] >> 8) & 0xFF)); + } + }; + + std::vector result; + + const bool is_vcn_jpeg_supported = (use_vcn_activity || use_jpeg_activity); + const size_t chunk_count = is_vcn_jpeg_supported ? 1 : xcp_count; + const size_t total_size = serialized_data_headers + (chunk_count * chunk_size); + + result.reserve(total_size); + + result.push_back((uint8_t) use_vcn_activity); + result.push_back((uint8_t) use_jpeg_activity); + result.push_back(chunk_count); + result.push_back(vcn_count); + result.push_back(jpeg_count); + + for(size_t count = 0; count < chunk_count; ++count) + { + const auto* vcn_data = + (is_vcn_jpeg_supported ? gpu_metrics.vcn_activity + : gpu_metrics.xcp_stats[count].vcn_busy); + const auto* jpeg_data = + (is_vcn_jpeg_supported ? gpu_metrics.jpeg_activity + : gpu_metrics.xcp_stats[count].jpeg_busy); + + serialize_uint16_array(result, vcn_data, vcn_count); + serialize_uint16_array(result, jpeg_data, jpeg_count); + } + + return result; +} + +size_t +serialize_settings(uint32_t _device_id) +{ + auto settings = get_settings(_device_id); + std::bitset<8> settings_bits; + settings_bits.reset(); + settings_bits.set( + static_cast(trace_cache::amd_smi_sample::settings_positions::busy), + settings.busy); + settings_bits.set( + static_cast(trace_cache::amd_smi_sample::settings_positions::temp), + settings.temp); + settings_bits.set( + static_cast(trace_cache::amd_smi_sample::settings_positions::power), + settings.power); + settings_bits.set( + static_cast(trace_cache::amd_smi_sample::settings_positions::mem_usage), + settings.mem_usage); + settings_bits.set( + static_cast(trace_cache::amd_smi_sample::settings_positions::vcn_activity), + settings.vcn_activity); + settings_bits.set( + static_cast(trace_cache::amd_smi_sample::settings_positions::jpeg_activity), + settings.jpeg_activity); + return settings_bits.to_ulong(); +} + } // namespace //--------------------------------------------------------------------------------------// @@ -252,12 +439,12 @@ std::unique_ptr data::polling_finished = {}; data::data(uint32_t _dev_id) { sample(_dev_id); } void -data::sample(uint32_t _dev_id) +data::sample(uint32_t _device_id) { if(is_child_process()) return; - auto _ts = tim::get_clock_real_now(); - assert(_ts < std::numeric_limits::max()); + auto _timestamp = tim::get_clock_real_now(); + assert(_timestamp < std::numeric_limits::max()); amdsmi_gpu_metrics_t _gpu_metrics; bool _vcn_or_jpeg_activity_enabled = false; @@ -265,8 +452,8 @@ data::sample(uint32_t _dev_id) if(_state != State::Active) return; - m_dev_id = _dev_id; - m_ts = _ts; + m_dev_id = _device_id; + m_ts = _timestamp; #define ROCPROFSYS_AMDSMI_GET(OPTION, FUNCTION, ...) \ if(OPTION) \ @@ -283,7 +470,7 @@ data::sample(uint32_t _dev_id) } \ } - amdsmi_processor_handle sample_handle = gpu::get_handle_from_id(_dev_id); + amdsmi_processor_handle sample_handle = gpu::get_handle_from_id(_device_id); ROCPROFSYS_AMDSMI_GET(get_settings(m_dev_id).busy, amdsmi_get_gpu_activity, sample_handle, &m_busy_perc); ROCPROFSYS_AMDSMI_GET(get_settings(m_dev_id).temp, amdsmi_get_temp_metric, @@ -354,8 +541,14 @@ data::sample(uint32_t _dev_id) } } } - #undef ROCPROFSYS_AMDSMI_GET + + trace_cache::get_buffer_storage().store( + trace_cache::entry_type::amd_smi_sample, serialize_settings(m_dev_id), _device_id, + _timestamp, m_busy_perc.gfx_activity, m_busy_perc.umc_activity, + m_busy_perc.mm_activity, m_power.current_socket_power, m_temp, m_mem_usage, + serialize_xcp_metrics(gpu::is_vcn_activity_supported(m_dev_id), + gpu::is_jpeg_activity_supported(m_dev_id), _gpu_metrics)); } void @@ -396,10 +589,10 @@ config() data::get_initial().at(itr).sample(itr); metadata_initialize_category(); - metadata_initialize_smi_tracks(); for(const auto& _dev_id : data::device_list) { + metadata_initialize_smi_tracks(_dev_id); metadata_initialize_smi_pmc(_dev_id); } } @@ -409,6 +602,9 @@ sample() { auto_lock_t _lk{ type_mutex() }; + // TODO: Reorganize amd_smi::data and sampling mechanism not to store same data in + // bundle_data and in trace_cache + for(auto itr : data::device_list) { if(amd_smi::get_state() != State::Active) continue; @@ -486,7 +682,6 @@ data::post_process(uint32_t _dev_id) auto _settings = get_settings(_dev_id); auto use_perfetto = get_use_perfetto(); - auto use_rocpd = get_use_rocpd(); for(auto& itr : _amd_smi) { @@ -661,12 +856,6 @@ data::post_process(uint32_t _dev_id) setup_perfetto_counter_tracks(); write_perfetto_metrics(); } - - if(use_rocpd) - { - rocpd_process_smi_pmc_events(_dev_id, _settings, _ts, _mmbusy, _temp, _power, - _usage); - } } } diff --git a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/cpu_freq.cpp b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/cpu_freq.cpp index 7c0e1ac20e..ce242ffbca 100644 --- a/projects/rocprofiler-systems/source/lib/rocprof-sys/library/cpu_freq.cpp +++ b/projects/rocprofiler-systems/source/lib/rocprof-sys/library/cpu_freq.cpp @@ -28,9 +28,10 @@ #include "core/debug.hpp" #include "core/node_info.hpp" #include "core/perfetto.hpp" -#include "core/rocpd/data_processor.hpp" #include "core/timemory.hpp" #include "core/trace_cache/cache_manager.hpp" +#include "core/trace_cache/metadata_registry.hpp" +#include "core/trace_cache/sample_type.hpp" #include "library/components/cpu_freq.hpp" #include "library/thread_info.hpp" @@ -42,10 +43,12 @@ #include #include +#include #include #include #include #include +#include namespace rocprofsys { @@ -67,14 +70,6 @@ init_perfetto_counter_tracks(type_list) (perfetto_counter_track::init(), ...); } -template -inline std::string -get_cpu_freq_track_name(uint64_t cpu_id) -{ - return std::string(trait::name::value) + " [" + std::to_string(cpu_id) + - "]"; -} - template void do_for_enabled_cpus(Func&& func) @@ -86,12 +81,6 @@ do_for_enabled_cpus(Func&& func) } } -rocpd::data_processor& -get_data_processor() -{ - return rocpd::data_processor::get_instance(); -} - void metadata_initialize_cpu_freq_category() { @@ -104,8 +93,9 @@ metadata_initialize_cpu_freq_tracks() { do_for_enabled_cpus([&](size_t cpu_id) { trace_cache::get_metadata_registry().add_track( - { get_cpu_freq_track_name(cpu_id).c_str(), std::nullopt, - "{}" }); + { trace_cache::info::annotate_with_device_id(cpu_id) + .c_str(), + std::nullopt, "{}" }); }); } @@ -146,9 +136,10 @@ metadata_initialize_cpu_freq_pmc(size_t dev_id) do_for_enabled_cpus([&](size_t cpu_id) { trace_cache::get_metadata_registry().add_pmc_info( { agent_type::CPU, dev_id, TARGET_ARCH, EVENT_CODE, INSTANCE_ID, - get_cpu_freq_track_name(cpu_id).c_str(), "Frequency", - trait::name::description, LONG_DESCRIPTION, COMPONENT, - component::cpu_freq::display_unit().c_str(), + trace_cache::info::annotate_with_device_id(cpu_id) + .c_str(), + "Frequency", trait::name::description, LONG_DESCRIPTION, + COMPONENT, component::cpu_freq::display_unit().c_str(), rocprofsys::trace_cache::ABSOLUTE, BLOCK, EXPRESSION, 0, 0 }); }); @@ -195,41 +186,27 @@ metadata_initialize_cpu_freq_pmc(size_t dev_id) COMPONENT, TIME, rocprofsys::trace_cache::ABSOLUTE, BLOCK, EXPRESSION, 0, 0 }); } -void -rocpd_process_cpu_usage_events(const uint32_t device_id, uint64_t timestamp, - const component::cpu_freq& freq, double mem_page, - double virt_mem_page, double peak_mem, - double context_switch, double page_fault, double user_time, - double kernel_time) +std::vector +serialize_freqs(const component::cpu_freq& freq) { - auto& data_processor = get_data_processor(); - const auto* _name = trait::name::value; - auto name_primary_key = data_processor.insert_string(_name); - auto event_id = data_processor.insert_event(name_primary_key, 0, 0, 0); + constexpr size_t idx_elements = sizeof(size_t) / sizeof(uint8_t); + constexpr size_t value_elements = sizeof(float) / sizeof(uint8_t); - auto& agent_mngr = agent_manager::get_instance(); - auto base_id = agent_mngr.get_agent_by_type_index(device_id, agent_type::CPU).base_id; + std::vector result; + const auto enabled_cpus_size = component::cpu_freq::get_enabled_cpus().size(); + const auto result_size = enabled_cpus_size * (idx_elements + value_elements); + result.resize(result_size); + result.assign(result_size, 0); - auto insert_event_and_sample = [&](const char* name, double value) { - data_processor.insert_pmc_event(event_id, base_id, name, value); - data_processor.insert_sample(name, timestamp, event_id); - }; - - do_for_enabled_cpus([&](size_t cpu_id) { - insert_event_and_sample( - get_cpu_freq_track_name(cpu_id).c_str(), freq.at(cpu_id)); + size_t offset = 0; + do_for_enabled_cpus([&](const auto& idx) { + auto value = freq.at(idx); + std::memcpy(result.data() + offset, &idx, sizeof(size_t)); + offset += sizeof(size_t); + std::memcpy(result.data() + offset, &value, sizeof(float)); + offset += sizeof(float); }); - - insert_event_and_sample(trait::name::value, mem_page); - insert_event_and_sample(trait::name::value, virt_mem_page); - insert_event_and_sample(trait::name::value, peak_mem); - insert_event_and_sample(trait::name::value, - context_switch); - insert_event_and_sample(trait::name::value, page_fault); - insert_event_and_sample(trait::name::value, - user_time); - insert_event_and_sample(trait::name::value, - kernel_time); + return result; } } // namespace @@ -251,9 +228,15 @@ setup() category::process_page_fault, category::process_user_mode_time, category::process_kernel_mode_time>{}); } - metadata_initialize_cpu_freq_category(); metadata_initialize_cpu_usage_tracks(); +} + +void +config() +{ + component::cpu_freq::configure(); + metadata_initialize_cpu_freq_tracks(); // `get_enabled_cpus()` returns the number of cores enabled for monitoring but @@ -268,23 +251,26 @@ setup() } } -void -config() -{ - component::cpu_freq::configure(); -} - void sample() { - auto _ts = tim::get_clock_real_now(); + auto _timestamp = tim::get_clock_real_now(); auto _rcache = tim::rusage_cache{ RUSAGE_SELF }; auto _freqs = component::cpu_freq{}.sample(); // user and kernel mode times are in microseconds + trace_cache::get_buffer_storage().store( + trace_cache::entry_type::cpu_freq_sample, _timestamp, tim::get_page_rss(), + tim::get_virt_mem(), _rcache.get_peak_rss(), + _rcache.get_num_priority_context_switch() + + _rcache.get_num_voluntary_context_switch(), + _rcache.get_num_major_page_faults() + _rcache.get_num_minor_page_faults(), + _rcache.get_user_mode_time() * 1000, _rcache.get_kernel_mode_time() * 1000, + serialize_freqs(_freqs)); + data.emplace_back( - _ts, tim::get_page_rss(), tim::get_virt_mem(), _rcache.get_peak_rss(), + _timestamp, tim::get_page_rss(), tim::get_virt_mem(), _rcache.get_peak_rss(), _rcache.get_num_priority_context_switch() + _rcache.get_num_voluntary_context_switch(), _rcache.get_num_major_page_faults() + _rcache.get_num_minor_page_faults(), @@ -420,12 +406,6 @@ post_process() write_perfetto_counter_track(_ts, _kern); } - if(get_use_rocpd()) - { - const auto& freq_data = std::get<8>(itr); - rocpd_process_cpu_usage_events(0, _ts, freq_data, _page, _virt, _peak, - _cntx, _flts, _user, _kern); - } } if(get_use_perfetto())