| /* |
| * SPDX-FileCopyrightText: Copyright OpenBMC Authors |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include "NvidiaGpuUtilizationMetrics.hpp" |
| |
| #include <bits/basic_string.h> |
| |
| #include <MctpRequester.hpp> |
| #include <NvidiaGpuLongRunningCommand.hpp> |
| #include <NvidiaGpuMctpVdm.hpp> |
| #include <NvidiaLongRunningHandler.hpp> |
| #include <NvidiaUtils.hpp> |
| #include <OcpMctpVdm.hpp> |
| #include <SerialQueue.hpp> |
| #include <Utils.hpp> |
| #include <phosphor-logging/lg2.hpp> |
| #include <sdbusplus/asio/object_server.hpp> |
| #include <sdbusplus/message/native_types.hpp> |
| |
| #include <cstdint> |
| #include <format> |
| #include <functional> |
| #include <memory> |
| #include <span> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| using namespace std::literals; |
| |
| NvidiaGpuUtilizationMetrics::NvidiaGpuUtilizationMetrics( |
| mctp::MctpRequester& mctpRequester, |
| sdbusplus::asio::object_server& objectServer, const std::string& deviceName, |
| uint8_t eid, std::shared_ptr<SerialQueue> longRunningQueue, |
| std::shared_ptr<NvidiaLongRunningResponseHandler> |
| longRunningResponseHandler) |
| { |
| const sdbusplus::object_path metricRoot = |
| sdbusplus::object_path(metricPath) / std::format("gpu_{}", deviceName); |
| |
| const sdbusplus::object_path processorMetricObjectPath = |
| metricRoot / "processor_bandwidth"; |
| |
| processorMetricInterface = objectServer.add_interface( |
| processorMetricObjectPath, "xyz.openbmc_project.Metric.Value"); |
| |
| processorMetricInterface->register_property( |
| "Unit", "xyz.openbmc_project.Metric.Value.Unit.Percent"s); |
| processorMetricInterface->register_property("Value", 0.0); |
| |
| const sdbusplus::object_path processorInventoryPath = |
| sdbusplus::object_path(inventoryPath) / deviceName; |
| |
| std::vector<Association> processorAssociations; |
| processorAssociations.emplace_back("measuring", "measured_by", |
| processorInventoryPath); |
| |
| processorMetricAssociationInterface = objectServer.add_interface( |
| processorMetricObjectPath, association::interface); |
| processorMetricAssociationInterface->register_property( |
| "Associations", processorAssociations); |
| |
| if (!processorMetricInterface->initialize()) |
| { |
| lg2::error( |
| "Error initializing Processor Bandwidth metric interface for GPU {NAME}, eid={EID}", |
| "NAME", deviceName, "EID", eid); |
| } |
| |
| if (!processorMetricAssociationInterface->initialize()) |
| { |
| lg2::error( |
| "Error initializing Processor Bandwidth metric association interface for GPU {NAME}, eid={EID}", |
| "NAME", deviceName, "EID", eid); |
| } |
| |
| const sdbusplus::object_path memoryMetricObjectPath = |
| metricRoot / "memory_bandwidth"; |
| |
| memoryMetricInterface = objectServer.add_interface( |
| memoryMetricObjectPath, "xyz.openbmc_project.Metric.Value"); |
| |
| memoryMetricInterface->register_property( |
| "Unit", "xyz.openbmc_project.Metric.Value.Unit.Percent"s); |
| memoryMetricInterface->register_property("Value", 0.0); |
| |
| const sdbusplus::object_path memoryInventoryPath(std::format( |
| "{}_{}", processorInventoryPath.string(), dramInventorySuffix)); |
| |
| std::vector<Association> memoryAssociations; |
| memoryAssociations.emplace_back("measuring", "measured_by", |
| memoryInventoryPath); |
| |
| memoryMetricAssociationInterface = objectServer.add_interface( |
| memoryMetricObjectPath, association::interface); |
| memoryMetricAssociationInterface->register_property("Associations", |
| memoryAssociations); |
| |
| if (!memoryMetricInterface->initialize()) |
| { |
| lg2::error( |
| "Error initializing Memory Bandwidth metric interface for GPU {NAME}, eid={EID}", |
| "NAME", deviceName, "EID", eid); |
| } |
| |
| if (!memoryMetricAssociationInterface->initialize()) |
| { |
| lg2::error( |
| "Error initializing Memory Bandwidth metric association interface for GPU {NAME}, eid={EID}", |
| "NAME", deviceName, "EID", eid); |
| } |
| |
| cmd = std::make_shared<NvidiaGpuLongRunningCommand>( |
| eid, mctpRequester, std::move(longRunningQueue), |
| std::move(longRunningResponseHandler), |
| NvidiaGpuLongRunningCommand::Config{ |
| .metricName = "GPU Utilization Metrics", |
| .messageType = gpu::MessageType::PLATFORM_ENVIRONMENTAL, |
| .commandId = |
| gpu::PlatformEnvironmentalCommands::GET_CURRENT_UTILIZATION, |
| .requestSize = gpu::getCurrentUtilizationRequestSize, |
| .encodeRequest = std::bind_front( |
| &gpu::encodeGetCurrentUtilizationModeRequest, uint8_t{0}), |
| .onImmediateSuccess = std::bind_front( |
| &NvidiaGpuUtilizationMetrics::onImmediateSuccess, |
| processorMetricInterface, memoryMetricInterface, eid), |
| .onLongRunningPayload = std::bind_front( |
| &NvidiaGpuUtilizationMetrics::onLongRunningPayload, |
| processorMetricInterface, memoryMetricInterface, eid), |
| }); |
| } |
| |
| void NvidiaGpuUtilizationMetrics::update() |
| { |
| cmd->update(); |
| } |
| |
| void NvidiaGpuUtilizationMetrics::onImmediateSuccess( |
| const std::shared_ptr<sdbusplus::asio::dbus_interface>& |
| processorMetricInterface, |
| const std::shared_ptr<sdbusplus::asio::dbus_interface>& |
| memoryMetricInterface, |
| uint8_t eid, std::span<const uint8_t> buffer) |
| { |
| ocp::accelerator_management::CompletionCode cc{}; |
| uint16_t reasonCode = 0; |
| uint32_t utilization = 0; |
| uint32_t memoryUtilization = 0; |
| |
| const int rc = gpu::decodeGetCurrentUtilizationModeResponse( |
| buffer, cc, reasonCode, utilization, memoryUtilization); |
| |
| if (rc != 0) |
| { |
| lg2::error("Error updating GPU Utilization Metrics: decode failed, " |
| "rc={RC}, cc={CC}, reasonCode={RESC}, EID={EID}", |
| "RC", rc, "CC", static_cast<uint8_t>(cc), "RESC", reasonCode, |
| "EID", eid); |
| return; |
| } |
| |
| applyUtilization(processorMetricInterface, utilization); |
| applyUtilization(memoryMetricInterface, memoryUtilization); |
| } |
| |
| void NvidiaGpuUtilizationMetrics::onLongRunningPayload( |
| const std::shared_ptr<sdbusplus::asio::dbus_interface>& |
| processorMetricInterface, |
| const std::shared_ptr<sdbusplus::asio::dbus_interface>& |
| memoryMetricInterface, |
| uint8_t eid, std::span<const uint8_t> payload) |
| { |
| uint32_t utilization = 0; |
| uint32_t memoryUtilization = 0; |
| |
| const int rc = gpu::decodeGetCurrentUtilizationModeResponse( |
| payload, utilization, memoryUtilization); |
| |
| if (rc != 0) |
| { |
| lg2::error("Error updating GPU Utilization Metrics: failed to decode " |
| "long running response data, rc={RC}, EID={EID}", |
| "RC", rc, "EID", eid); |
| return; |
| } |
| |
| applyUtilization(processorMetricInterface, utilization); |
| applyUtilization(memoryMetricInterface, memoryUtilization); |
| } |
| |
| void NvidiaGpuUtilizationMetrics::applyUtilization( |
| const std::shared_ptr<sdbusplus::asio::dbus_interface>& metricInterface, |
| uint32_t utilization) |
| { |
| metricInterface->set_property("Value", static_cast<double>(utilization)); |
| } |