Files
TheRock/rocm-systems/projects/rocprofiler-systems/source/lib/backends/amd_smi/device.hpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

326 lines
12 KiB
C++

// Copyright (c) Advanced Micro Devices, Inc.
// SPDX-License-Identifier: MIT
#pragma once
#include "backends/amd_smi/gpu_types.hpp"
#include "backends/amd_smi/nic_types.hpp"
#include "backends/amd_smi/sdma_feature.hpp"
#include <algorithm>
#include <concepts>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
namespace rocprofsys::backends::amd_smi
{
using gpu::asic_info;
using gpu::MAX_NUM_JPEG_V1;
using gpu::MAX_NUM_XCP;
using gpu::MAX_NUM_XGMI_LINKS;
using gpu::metrics;
using gpu::populate_if_supported;
template <typename T>
concept session_types = requires {
typename T::processor_handle;
typename T::asic_info_t;
typename T::gpu_metrics_t;
typename T::memory_type_t;
typename T::temperature_type_t;
typename T::temperature_metric_t;
{ T::sdma_supported } -> std::convertible_to<bool>;
{ T::ainic_feature_gate } -> std::convertible_to<bool>;
};
template <typename T>
concept session_gpu_queries =
requires(T sess, typename T::processor_handle ph, typename T::asic_info_t* aip,
typename T::memory_type_t mt, std::uint64_t* u64p,
typename T::temperature_type_t tt, typename T::temperature_metric_t tm) {
{ T::MEM_TYPE_VRAM } -> std::convertible_to<typename T::memory_type_t>;
{ T::TEMP_CURRENT } -> std::convertible_to<typename T::temperature_metric_t>;
{
T::TEMPERATURE_TYPE_HOTSPOT
} -> std::convertible_to<typename T::temperature_type_t>;
{
T::TEMPERATURE_TYPE_EDGE
} -> std::convertible_to<typename T::temperature_type_t>;
{ sess.get_gpu_asic_info(ph, aip) };
{ sess.get_metrics_info(ph) } -> std::convertible_to<typename T::gpu_metrics_t>;
{ sess.get_memory_usage(ph, mt, u64p) };
{ sess.get_temp_metric(ph, tt, tm) } -> std::convertible_to<std::int64_t>;
};
template <typename T>
concept sdma_session_types = requires { typename T::proc_info_t; };
template <typename T>
concept sdma_session_queries = requires(T sess, typename T::processor_handle ph) {
{ sess.probe_sdma_support(ph) } -> std::convertible_to<bool>;
{
sess.get_gpu_process_list(ph)
} -> std::same_as<std::vector<typename T::proc_info_t>>;
};
template <typename T>
concept sdma_session_contract = sdma_session_types<T> && sdma_session_queries<T>;
template <typename T>
concept nic_session_types = requires {
typename T::nic_asic_info_t;
typename T::nic_port_info_t;
typename T::nic_rdma_devices_info_t;
typename T::nic_stat_t;
};
template <typename T>
concept nic_session_queries =
requires(T sess, typename T::processor_handle ph, typename T::nic_asic_info_t* nap,
typename T::nic_port_info_t* npp, typename T::nic_rdma_devices_info_t* ndp,
std::uint8_t port_idx, std::uint32_t* cp, typename T::nic_stat_t* nsp) {
{ sess.get_nic_asic_info(ph, nap) };
{ sess.get_nic_port_info(ph, npp) };
{ sess.get_nic_rdma_dev_info(ph, ndp) };
{ sess.get_nic_rdma_port_statistics(ph, port_idx, cp, nsp) };
};
template <typename T>
concept nic_session_contract = nic_session_types<T> && nic_session_queries<T>;
/**
* @brief Concept that a Backend session type passed to device must satisfy.
*
* Enumerates every expression device<T> evaluates on its session pointer,
* so a missing method is caught at the template boundary rather than deep inside
* the template body.
*/
template <typename T>
concept backend_session_contract = session_types<T> && session_gpu_queries<T> &&
(!T::sdma_supported || sdma_session_contract<T>) &&
(!T::ainic_feature_gate || nic_session_contract<T>);
/**
* @brief Per-device proxy — bridges a shared backend session to one device handle.
*
* Holds a @c shared_ptr<Backend> session and one processor handle. Forwards
* per-device calls through the session (which throws on failure) and converts
* raw AMD SMI structs to domain types.
*
* Lives in the PMC layer; the concrete @c Backend type is named only at the
* integration point (sampler.cpp).
*
* @tparam Backend Session type satisfying @c backend_session_contract
* (e.g. @c backends::amd_smi::backend<wrapper>).
*/
template <backend_session_contract Backend>
class device
{
public:
static constexpr bool sdma_supported = Backend::sdma_supported;
device(std::shared_ptr<Backend> session, Backend::processor_handle handle)
: m_session{ std::move(session) }
, m_handle{ handle }
{}
// ── Per-device GPU queries ────────────────────────────────────────────────
[[nodiscard]] asic_info get_gpu_asic_info() const
{
typename Backend::asic_info_t raw{};
m_session->get_gpu_asic_info(m_handle, &raw);
return { raw.market_name, raw.vendor_name };
}
[[nodiscard]] metrics get_metrics() const
{
const auto raw = m_session->get_metrics_info(m_handle);
metrics out{};
convert_power(raw, out);
convert_temperature(raw, out);
convert_activity(raw, out);
convert_xcp(raw, out);
convert_xgmi(raw, out);
convert_pcie(raw, out);
convert_clocks(raw, out);
return out;
}
[[nodiscard]] std::int64_t get_hotspot_temperature() const
{
return m_session->get_temp_metric(m_handle, Backend::TEMPERATURE_TYPE_HOTSPOT,
Backend::TEMP_CURRENT);
}
[[nodiscard]] std::int64_t get_edge_temperature() const
{
return m_session->get_temp_metric(m_handle, Backend::TEMPERATURE_TYPE_EDGE,
Backend::TEMP_CURRENT);
}
[[nodiscard]] std::uint64_t get_memory_usage() const
{
std::uint64_t usage = 0;
m_session->get_memory_usage(m_handle, Backend::MEM_TYPE_VRAM, &usage);
return usage;
}
// One-time GPU-level SDMA capability probe (available = library has the API,
// supported = this GPU actually provides data). Always returns false when
// sdma_supported == false so callers need no #ifdef.
[[nodiscard]] bool probe_sdma_gpu_support() const noexcept
{
if constexpr(sdma_supported) return m_session->probe_sdma_support(m_handle);
return false;
}
[[nodiscard]] std::uint64_t get_raw_sdma_usage() const
{
if constexpr(Backend::sdma_supported)
{
std::uint64_t cumulative = 0;
auto procs = m_session->get_gpu_process_list(m_handle);
for(const auto& proc : procs)
cumulative += proc.sdma_usage;
return cumulative;
}
return 0;
}
#if defined(ROCPROFSYS_BUILD_AINIC) && ROCPROFSYS_BUILD_AINIC == 1
// ── Per-device NIC queries ────────────────────────────────────────────────
[[nodiscard]] nic::asic_info get_nic_asic_info() const
{
typename Backend::nic_asic_info_t raw{};
m_session->get_nic_asic_info(m_handle, &raw);
return { raw.product_name, raw.vendor_name };
}
[[nodiscard]] nic::port_info get_nic_port_info() const
{
typename Backend::nic_port_info_t raw{};
m_session->get_nic_port_info(m_handle, &raw);
if(raw.num_ports == 0) return {};
return { raw.ports[0].netdev };
}
[[nodiscard]] nic::rdma_info get_nic_rdma_info() const
{
auto raw = std::make_unique<typename Backend::nic_rdma_devices_info_t>();
m_session->get_nic_rdma_dev_info(m_handle, raw.get());
if(raw->num_rdma_dev == 0) return { 0 };
return { raw->rdma_dev_info[0].num_rdma_ports };
}
[[nodiscard]] std::vector<nic::stat_entry> get_nic_rdma_port_statistics(
std::uint8_t rdma_port_idx) const
{
std::uint32_t count = 0;
m_session->get_nic_rdma_port_statistics(m_handle, rdma_port_idx, &count, nullptr);
if(count == 0) return {};
std::vector<typename Backend::nic_stat_t> raw_stats(count);
m_session->get_nic_rdma_port_statistics(m_handle, rdma_port_idx, &count,
raw_stats.data());
std::vector<nic::stat_entry> result;
result.reserve(count);
for(const auto& stat : raw_stats)
result.emplace_back(nic::stat_entry{ stat.name, stat.value });
return result;
}
#endif
private:
using gpu_metrics_t = typename Backend::gpu_metrics_t;
// ── Metric conversion ─────────────────────────────────────────────────────
static void convert_power(const gpu_metrics_t& raw, metrics& out)
{
out.current_socket_power = raw.current_socket_power;
out.average_socket_power = raw.average_socket_power;
}
static void convert_temperature(const gpu_metrics_t& raw, metrics& out)
{
out.hotspot_temperature = raw.temperature_hotspot;
out.edge_temperature = raw.temperature_edge;
}
static void convert_activity(const gpu_metrics_t& raw, metrics& out)
{
out.gfx_activity = raw.average_gfx_activity;
out.umc_activity = raw.average_umc_activity;
out.mm_activity = raw.average_mm_activity;
}
static void convert_xcp(const gpu_metrics_t& raw, metrics& out)
{
for(std::size_t xcp = 0; xcp < MAX_NUM_XCP; ++xcp)
{
std::copy(std::begin(raw.xcp_stats[xcp].vcn_busy),
std::end(raw.xcp_stats[xcp].vcn_busy),
out.xcp_stats[xcp].vcn_busy.begin());
constexpr std::size_t copy_count =
std::min(static_cast<std::size_t>(sizeof(raw.xcp_stats[0].jpeg_busy) /
sizeof(std::uint16_t)),
gpu::MAX_NUM_JPEG_V1);
std::copy_n(std::begin(raw.xcp_stats[xcp].jpeg_busy), copy_count,
out.xcp_stats[xcp].jpeg_busy.begin());
}
std::copy(std::begin(raw.vcn_activity), std::end(raw.vcn_activity),
out.vcn_activity.begin());
std::copy(std::begin(raw.jpeg_activity), std::end(raw.jpeg_activity),
out.jpeg_activity.begin());
}
static void convert_xgmi(const gpu_metrics_t& raw, metrics& out)
{
populate_if_supported(out.xgmi.link.width, raw.xgmi_link_width);
populate_if_supported(out.xgmi.link.speed, raw.xgmi_link_speed);
for(std::size_t idx = 0; idx < MAX_NUM_XGMI_LINKS; ++idx)
{
populate_if_supported(out.xgmi.data_acc.read[idx],
raw.xgmi_read_data_acc[idx]);
populate_if_supported(out.xgmi.data_acc.write[idx],
raw.xgmi_write_data_acc[idx]);
}
}
static void convert_pcie(const gpu_metrics_t& raw, metrics& out)
{
populate_if_supported(out.pcie.link.width, raw.pcie_link_width);
populate_if_supported(out.pcie.link.speed, raw.pcie_link_speed);
populate_if_supported(out.pcie.bandwidth.acc, raw.pcie_bandwidth_acc);
populate_if_supported(out.pcie.bandwidth.inst, raw.pcie_bandwidth_inst);
}
static void convert_clocks(const gpu_metrics_t& raw, metrics& out)
{
constexpr auto sentinel = static_cast<std::uint32_t>(0xFFFFU);
populate_if_supported(out.gfx_clock_mhz,
static_cast<std::uint32_t>(raw.current_gfxclk), sentinel);
populate_if_supported(out.mem_clock_mhz,
static_cast<std::uint32_t>(raw.current_uclk), sentinel);
}
// ── Members ───────────────────────────────────────────────────────────────
std::shared_ptr<Backend> m_session;
typename Backend::processor_handle m_handle;
};
} // namespace rocprofsys::backends::amd_smi