Change amd_smi and cpu_freq modules to use trace cache for rocpd (#690)

* Move amd-smi to use caching mechanism

* Add VCN and JPEG activity to rocpd

* Switch cpu_freq to use caching mechanism

* Different approach with xcp activity & applied suggestions from code review

* Applied suggestions from code review

* Fix shadowing

* Applied suggestions from code review
Цей коміт міститься в:
Milan Radosavljevic
2025-08-26 20:00:04 +02:00
зафіксовано GitHub
джерело 7601798fa7
коміт 96a46962ad
10 змінених файлів з 697 додано та 144 видалено
+1 -1
Переглянути файл
@@ -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)
+26 -13
Переглянути файл
@@ -26,6 +26,7 @@
#include "PTL/ThreadPool.hh"
#include "cache_utility.hpp"
#include "sample_type.hpp"
#include <PTL/PTL.hh>
#include <cassert>
#include <condition_variable>
#include <cstdlib>
@@ -37,7 +38,6 @@
#include <string.h>
#include <thread>
#include <type_traits>
#include <PTL/PTL.hh>
#include <unistd.h>
namespace rocprofsys
@@ -63,7 +63,8 @@ public:
constexpr bool is_supported_type = (supported_types::is_supported<T> && ...);
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<unsigned char> 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::decay_t<Type>, std::vector<uint8_t>>)
{
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<decltype(val)>;
@@ -110,7 +118,8 @@ private:
(std::is_same_v<std::decay_t<T>, Types> || ...);
};
using supported_types = typelist<const char*, char*, uint64_t, int32_t, uint32_t>;
using supported_types = typelist<const char*, char*, uint64_t, int32_t, uint32_t,
std::vector<uint8_t>, uint8_t, int64_t>;
template <typename T>
static constexpr bool is_string_literal_v =
@@ -129,6 +138,10 @@ private:
}
return ++size;
}
else if constexpr(std::is_same_v<std::decay_t<T>, std::vector<uint8_t>>)
{
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_ptr<PTL::ThreadPool>m_thread_pool;
std::unique_ptr<PTL::ThreadPool> m_thread_pool;
std::unique_ptr<PTL::TaskGroup<void>> m_task_group;
size_t m_head{ 0 };
size_t m_tail{ 0 };
std::unique_ptr<buffer_array_t> m_buffer{ std::make_unique<buffer_array_t>() };
pid_t m_created_process;
size_t m_head{ 0 };
size_t m_tail{ 0 };
std::unique_ptr<buffer_array_t> m_buffer{ std::make_unique<buffer_array_t>() };
pid_t m_created_process;
};
} // namespace trace_cache
+29
Переглянути файл
@@ -24,6 +24,7 @@
#include "common/synchronized.hpp"
#include "core/agent.hpp"
#include "core/categories.hpp"
#include <cassert>
#include <cstdint>
@@ -35,6 +36,7 @@
# include <rocprofiler-sdk/cxx/name_info.hpp>
#endif
#include <set>
#include <sstream>
#include <stdint.h>
#include <string.h>
#include <string>
@@ -53,6 +55,19 @@ struct process
pid_t ppid;
std::string command;
};
template <typename Category>
inline std::string
annotate_category(std::optional<int> first_section = std::nullopt,
std::optional<int> second_section = std::nullopt)
{
std::stringstream ss;
ss << std::string(tim::trait::name<Category>::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 <typename Category>
inline std::string
annotate_with_device_id(uint32_t device_id,
std::optional<int> first_section = std::nullopt,
std::optional<int> second_section = std::nullopt)
{
std::stringstream ss;
ss << std::string(tim::trait::name<Category>::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
+264
Переглянути файл
@@ -33,6 +33,7 @@
#include "trace_cache/storage_parser.hpp"
#include <cstdint>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <string>
#include <timemory/utility/demangle.hpp>
@@ -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<uint16_t> vcn_busy;
std::vector<uint16_t> jpeg_busy;
};
auto deserialize_xcp_metrics = [](const std::vector<uint8_t>& serialized_data,
bool& _is_vcn_supported, bool& _is_jpeg_supported,
std::vector<xcp_metrics_t>& 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<bool>(serialized_data[offset++]);
_is_jpeg_supported = static_cast<bool>(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<uint8_t>& data,
size_t& _offset, int array_size) {
std::vector<uint16_t> _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<uint16_t>(data[_offset]) |
(static_cast<uint16_t>(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<const struct amd_smi_sample&>(parsed);
auto& data_processor = get_data_processor();
const auto* _name = trait::name<category::amd_smi>::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<int>(pos::busy));
bool is_temp_enabled = settings_bits.test(static_cast<int>(pos::temp));
bool is_power_enabled = settings_bits.test(static_cast<int>(pos::power));
bool is_mem_usage_enabled = settings_bits.test(static_cast<int>(pos::mem_usage));
bool is_vcn_enabled = settings_bits.test(static_cast<int>(pos::vcn_activity));
bool is_jpeg_enabled = settings_bits.test(static_cast<int>(pos::jpeg_activity));
insert_event_and_sample(
is_busy_enabled, trait::name<category::amd_smi_gfx_busy>::value,
info::annotate_with_device_id<category::amd_smi_gfx_busy>(_amd_smi.device_id)
.c_str(),
_amd_smi.gfx_activity);
insert_event_and_sample(
is_busy_enabled, trait::name<category::amd_smi_umc_busy>::value,
info::annotate_with_device_id<category::amd_smi_umc_busy>(_amd_smi.device_id)
.c_str(),
_amd_smi.umc_activity);
insert_event_and_sample(
is_busy_enabled, trait::name<category::amd_smi_mm_busy>::value,
info::annotate_with_device_id<category::amd_smi_mm_busy>(_amd_smi.device_id)
.c_str(),
_amd_smi.mm_activity);
insert_event_and_sample(
is_temp_enabled, trait::name<category::amd_smi_temp>::value,
info::annotate_with_device_id<category::amd_smi_temp>(_amd_smi.device_id)
.c_str(),
_amd_smi.temperature);
insert_event_and_sample(
is_power_enabled, trait::name<category::amd_smi_power>::value,
info::annotate_with_device_id<category::amd_smi_power>(_amd_smi.device_id)
.c_str(),
_amd_smi.power);
insert_event_and_sample(
is_mem_usage_enabled, trait::name<category::amd_smi_memory_usage>::value,
info::annotate_with_device_id<category::amd_smi_memory_usage>(
_amd_smi.device_id)
.c_str(),
_amd_smi.mem_usage);
if(!is_vcn_enabled && !is_jpeg_enabled)
{
return;
}
std::vector<xcp_metrics_t> 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<uint16_t>& data,
std::optional<size_t> _idx = std::nullopt) {
if(!_is_enabled)
{
return;
}
using Category = std::decay_t<decltype(category)>;
for(size_t clk = 0; clk < data.size(); ++clk)
{
const auto value = data[clk];
if(value == std::numeric_limits<uint16_t>::max())
{
continue;
}
auto pmc_name = info::annotate_category<Category>(_idx, clk);
auto track_name = info::annotate_with_device_id<Category>(
_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<size_t>(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<uint8_t>& buffer) {
std::vector<core_freq_sample> 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<const struct cpu_freq_sample&>(parsed);
auto& data_processor = get_data_processor();
const auto* _name = trait::name<category::cpu_freq>::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<category::process_page>::value,
_cpu_freq_sample.page_rss);
insert_event_and_sample(trait::name<category::process_virt>::value,
_cpu_freq_sample.virt_mem_usage);
insert_event_and_sample(trait::name<category::process_peak>::value,
_cpu_freq_sample.peak_rss);
insert_event_and_sample(trait::name<category::process_context_switch>::value,
_cpu_freq_sample.context_switch_count);
insert_event_and_sample(trait::name<category::process_page_fault>::value,
_cpu_freq_sample.page_faults);
insert_event_and_sample(trait::name<category::process_user_mode_time>::value,
_cpu_freq_sample.user_mode_time);
insert_event_and_sample(trait::name<category::process_kernel_mode_time>::value,
_cpu_freq_sample.kernel_mode_time);
auto get_track_name = [](const auto& cpu_id) {
return std::string(trait::name<category::cpu_freq>::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
}
+2
Переглянути файл
@@ -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;
};
+42
Переглянути файл
@@ -21,10 +21,13 @@
// SOFTWARE.
#pragma once
#include <cstdint>
#include <stdint.h>
#include <string>
#include <unistd.h>
#include <utility>
#include <variant>
#include <vector>
#if ROCPROFSYS_USE_ROCM > 0
# include <rocprofiler-sdk/version.h>
@@ -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<uint8_t> 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<uint8_t> 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
+25
Переглянути файл
@@ -23,6 +23,7 @@
#include "storage_parser.hpp"
#include "debug.hpp"
#include "trace_cache/sample_type.hpp"
#include <cstdint>
#include <cstdio>
#include <fstream>
#include <sstream>
@@ -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;
}
}
+9
Переглянути файл
@@ -28,6 +28,7 @@
#include <cstdlib>
#include <cstring>
#include <functional>
#include <iterator>
#include <map>
#include <rocprofiler-systems/categories.h>
#include <stdint.h>
@@ -60,6 +61,14 @@ private:
arg = std::string((const char*) data_pos);
data_pos += arg.size() + 1;
}
else if constexpr(std::is_same_v<T, std::vector<uint8_t>>)
{
size_t vector_size = *reinterpret_cast<const size_t*>(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<const T*>(data_pos);
+253 -64
Переглянути файл
@@ -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 <amd_smi/amdsmi.h>
#include <cstdint>
#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<bundle_t, category::amd_smi>;
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<category::amd_smi_mm_busy>::value, thread_id, "{}" });
{ trace_cache::info::annotate_with_device_id<category::amd_smi_gfx_busy>(gpu_id),
thread_id, "{}" });
trace_cache::get_metadata_registry().add_track(
{ trait::name<category::amd_smi_power>::value, thread_id, "{}" });
{ trace_cache::info::annotate_with_device_id<category::amd_smi_umc_busy>(gpu_id),
thread_id, "{}" });
trace_cache::get_metadata_registry().add_track(
{ trait::name<category::amd_smi_temp>::value, thread_id, "{}" });
{ trace_cache::info::annotate_with_device_id<category::amd_smi_mm_busy>(gpu_id),
thread_id, "{}" });
trace_cache::get_metadata_registry().add_track(
{ trait::name<category::amd_smi_memory_usage>::value, thread_id, "{}" });
{ trace_cache::info::annotate_with_device_id<category::amd_smi_power>(gpu_id),
thread_id, "{}" });
trace_cache::get_metadata_registry().add_track(
{ trace_cache::info::annotate_with_device_id<category::amd_smi_temp>(gpu_id),
thread_id, "{}" });
trace_cache::get_metadata_registry().add_track(
{ trace_cache::info::annotate_with_device_id<category::amd_smi_memory_usage>(
gpu_id),
thread_id, "{}" });
auto add_vcn_track = [&](std::optional<int> 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<int> 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<category::amd_smi_mm_busy>::value, "Busy",
trait::name<category::amd_smi_gfx_busy>::value, "GFX Busy",
trait::name<category::amd_smi_gfx_busy>::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<category::amd_smi_umc_busy>::value, "UMC Busy",
trait::name<category::amd_smi_umc_busy>::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<category::amd_smi_mm_busy>::value, "MM Busy",
trait::name<category::amd_smi_mm_busy>::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<category::amd_smi_memory_usage>::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<int> xcp_idx) {
for(int clk = 0; clk < AMDSMI_MAX_NUM_VCN; ++clk)
{
std::stringstream name_ss;
name_ss << trait::name<category::amd_smi_vcn_activity>::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<category::amd_smi>::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<category::amd_smi_vcn_activity>::description,
LONG_DESCRIPTION, COMPONENT, trace_cache::PERCENTAGE,
rocprofsys::trace_cache::ABSOLUTE, BLOCK, EXPRESSION, 0, 0 });
}
};
insert_event_and_sample(settings.busy, trait::name<category::amd_smi_mm_busy>::value,
busy);
insert_event_and_sample(settings.temp, trait::name<category::amd_smi_temp>::value,
temp);
insert_event_and_sample(settings.power, trait::name<category::amd_smi_power>::value,
power);
insert_event_and_sample(settings.mem_usage,
trait::name<category::amd_smi_memory_usage>::value, usage);
auto add_jpeg_pmc = [&](std::optional<int> xcp_idx) {
for(auto clk = 0; clk < AMDSMI_MAX_NUM_JPEG; ++clk)
{
std::stringstream name_ss;
name_ss << trait::name<category::amd_smi_jpeg_activity>::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<category::amd_smi_jpeg_activity>::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<State> _v{ State::PreInit };
return _v;
}
std::vector<uint8_t>
serialize_xcp_metrics(const bool& use_vcn_activity, const bool& use_jpeg_activity,
const amdsmi_gpu_metrics_t& gpu_metrics)
{
// Chunk:
// <vcn_data_0>..<vcn_data_[vcn_count]> // lower and higher byte
// <jpeg_data_0>..<jpeg_data_[jpeg_count]> // lower and higher byte
// Serialized:
// <is_vcn_supported>
// <is_jpeg_supported>
// <xcp_count>
// <vcn_count>
// <jpeg_count>
// 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<uint8_t>& data, const uint16_t* arr,
int array_size) {
for(int i = 0; i < array_size; ++i)
{
data.push_back(static_cast<uint8_t>(arr[i] & 0xFF));
data.push_back(static_cast<uint8_t>((arr[i] >> 8) & 0xFF));
}
};
std::vector<uint8_t> 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<int>(trace_cache::amd_smi_sample::settings_positions::busy),
settings.busy);
settings_bits.set(
static_cast<int>(trace_cache::amd_smi_sample::settings_positions::temp),
settings.temp);
settings_bits.set(
static_cast<int>(trace_cache::amd_smi_sample::settings_positions::power),
settings.power);
settings_bits.set(
static_cast<int>(trace_cache::amd_smi_sample::settings_positions::mem_usage),
settings.mem_usage);
settings_bits.set(
static_cast<int>(trace_cache::amd_smi_sample::settings_positions::vcn_activity),
settings.vcn_activity);
settings_bits.set(
static_cast<int>(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::promise_t> 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<size_t, std::nano>();
assert(_ts < std::numeric_limits<int64_t>::max());
auto _timestamp = tim::get_clock_real_now<size_t, std::nano>();
assert(_timestamp < std::numeric_limits<int64_t>::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<category::amd_smi>() };
// 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);
}
}
}
+46 -66
Переглянути файл
@@ -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 <cstddef>
#include <cstdlib>
#include <cstring>
#include <string>
#include <sys/resource.h>
#include <tuple>
#include <utility>
#include <vector>
namespace rocprofsys
{
@@ -67,14 +70,6 @@ init_perfetto_counter_tracks(type_list<Types...>)
(perfetto_counter_track<Types>::init(), ...);
}
template <typename Category>
inline std::string
get_cpu_freq_track_name(uint64_t cpu_id)
{
return std::string(trait::name<Category>::value) + " [" + std::to_string(cpu_id) +
"]";
}
template <typename Func>
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<category::cpu_freq>(cpu_id).c_str(), std::nullopt,
"{}" });
{ trace_cache::info::annotate_with_device_id<category::cpu_freq>(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<category::cpu_freq>(cpu_id).c_str(), "Frequency",
trait::name<category::cpu_freq>::description, LONG_DESCRIPTION, COMPONENT,
component::cpu_freq::display_unit().c_str(),
trace_cache::info::annotate_with_device_id<category::cpu_freq>(cpu_id)
.c_str(),
"Frequency", trait::name<category::cpu_freq>::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<uint8_t>
serialize_freqs(const component::cpu_freq& freq)
{
auto& data_processor = get_data_processor();
const auto* _name = trait::name<category::cpu_freq>::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<uint8_t> 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<category::cpu_freq>(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<category::process_page>::value, mem_page);
insert_event_and_sample(trait::name<category::process_virt>::value, virt_mem_page);
insert_event_and_sample(trait::name<category::process_peak>::value, peak_mem);
insert_event_and_sample(trait::name<category::process_context_switch>::value,
context_switch);
insert_event_and_sample(trait::name<category::process_page_fault>::value, page_fault);
insert_event_and_sample(trait::name<category::process_user_mode_time>::value,
user_time);
insert_event_and_sample(trait::name<category::process_kernel_mode_time>::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<size_t, std::nano>();
auto _timestamp = tim::get_clock_real_now<size_t, std::nano>();
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<category::process_kernel_mode_time>(_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())