Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/runtime_src/core/common/info_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "xrt/detail/xclbin.h"

#include <boost/algorithm/string.hpp>
#include <limits>

// Too much typing
using ptree_type = boost::property_tree::ptree;
Expand Down Expand Up @@ -194,6 +195,25 @@ add_host_mem_info(const xrt_core::device* device, ptree_type& pt)
pt.add("host_memory_status", get_host_mem_status(device));
}

void
add_aie_load_info(const xrt_core::device* device, ptree_type& pt)
{
try {
const xq::aie_load::args args{}; // sample_duration_ms = 0 -> driver default
const auto data = xrt_core::device_query<xq::aie_load>(device, args);

ptree_type pt_aie_load;
if (data.load_percent == std::numeric_limits<uint32_t>::max())
pt_aie_load.put("load_percent", "N/A");
else
pt_aie_load.put("load_percent", data.load_percent);
pt.put_child("aie_load", pt_aie_load);
}
catch (const xq::exception&) {
// Ignoring if not available: older driver/DLL or unsupported device
}
}

void
add_status_info(const xrt_core::device* device, ptree_type& pt)
{
Expand Down Expand Up @@ -431,6 +451,7 @@ add_platform_info(const xrt_core::device* device, ptree_type& pt_platform_array)
{
add_electrical_info(device, pt_platform);
add_thermal_info(device, pt_platform);
add_aie_load_info(device, pt_platform);
break;
}
default:
Expand Down
27 changes: 26 additions & 1 deletion src/runtime_src/core/common/query_requests.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,8 @@ enum class key_type

aie_read,
aie_write,
aie_coredump
aie_coredump,
aie_load
};

struct pcie_vendor : request
Expand Down Expand Up @@ -4316,6 +4317,30 @@ struct aie_coredump : request
std::any
get(const device*, const std::any&) const override = 0;
};

// AIE array hardware utilization, computed from two consecutive firmware
// activity-counter snapshots separated by sample_duration_ms milliseconds.
struct aie_load : request
{
struct result_type {
uint32_t load_percent; // 0-100, or UINT32_MAX if unavailable
uint64_t timestamp_ms; // FW uptime when second snapshot was taken
uint64_t activity_counters[8]; // raw counter values from second snapshot

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 8 is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

    uint64_t activity_counters[8];  // raw counter values from second snapshot
                               ^

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays]

    uint64_t activity_counters[8];  // raw counter values from second snapshot
    ^

uint64_t operations_per_second; // total counter change across 8 counters per second
};

struct args {
uint32_t sample_duration_ms = 0; // 0 = driver default (XRT_AIE_LOAD_SAMPLE_INTERVAL_MS)
};

static const key_type key = key_type::aie_load;

virtual std::any
get(const device*) const override = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 'virtual' is redundant since the function is already declared 'override' [cppcoreguidelines-explicit-virtual-functions]

src/runtime_src/core/common/query_requests.h:4337:

-   virtual std::any
+   std::any


virtual std::any
get(const device*, const std::any&) const override = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 'virtual' is redundant since the function is already declared 'override' [cppcoreguidelines-explicit-virtual-functions]

src/runtime_src/core/common/query_requests.h:4340:

-   virtual std::any
+   std::any

};
} // query

} // xrt_core
Expand Down
44 changes: 5 additions & 39 deletions src/runtime_src/core/common/smi/smi_ryzen.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.

#define XRT_CORE_COMMON_SOURCE

Expand All @@ -15,6 +15,7 @@ config_gen_ryzen::
config_gen_ryzen()
{
examine_report_desc = {
{"aie-load", "AIE array load utilization", "common"},
{"aie-partitions", "AIE partition information", "common"},
{"all", "All known reports are produced", "common"},
{"host", "Host information (default)", "common"},
Expand Down Expand Up @@ -63,7 +64,7 @@ config_gen_ryzen::create_validate_subcommand()
validate_suboptions.emplace("device", std::make_shared<option>("device", "d", "The Bus:Device.Function (e.g., 0000:d8:00.0) device of interest", "common", "", "string"));
validate_suboptions.emplace("format", std::make_shared<option>("format", "f", "Report output format. Valid values are:\n"
"\tJSON - Latest JSON schema\n"
"\tJSON-2020.2 - JSON 2020.2 schema (legacy)", "common", "JSON", "string"));
"\tJSON-2020.2 - JSON 2020.2 schema", "common", "JSON", "string"));
validate_suboptions.emplace("output", std::make_shared<option>("output", "o", "Direct the output to the given file", "common", "", "string"));
validate_suboptions.emplace("help", std::make_shared<option>("help", "h", "Help to use this sub-command", "common", "", "none"));
validate_suboptions.emplace("run", std::make_shared<listable_description_option>("run", "r", "Run a subset of the test suite. Valid options are:\n",
Expand All @@ -82,7 +83,7 @@ config_gen_ryzen::create_examine_subcommand()
examine_suboptions.emplace("device", std::make_shared<option>("device", "d", "The Bus:Device.Function (e.g., 0000:d8:00.0) device of interest", "common", "", "string"));
examine_suboptions.emplace("format", std::make_shared<option>("format", "f", "Report output format. Valid values are:\n"
"\tJSON - Latest JSON schema\n"
"\tJSON-2020.2 - JSON 2020.2 schema (legacy)", "common", "JSON", "string"));
"\tJSON-2020.2 - JSON 2020.2 schema", "common", "JSON", "string"));
examine_suboptions.emplace("output", std::make_shared<option>("output", "o", "Direct the output to the given file", "common", "", "string"));
examine_suboptions.emplace("help", std::make_shared<option>("help", "h", "Help to use this sub-command", "common", "", "none"));
examine_suboptions.emplace("watch", std::make_shared<option>("watch", "", "Refresh interval in seconds between examine updates. Exit with Ctrl+C.", "hidden", "0", "string"));
Expand Down Expand Up @@ -113,6 +114,7 @@ config_gen_npu3::
config_gen_npu3()
{
examine_report_desc = {
{"aie-load", "AIE array load utilization", "common"},
{"aie-partitions", "AIE partition information", "common"},
{"all", "All known reports are produced", "common"},
{"host", "Host information", "common"},
Expand All @@ -139,42 +141,6 @@ config_gen_npu3()
};
}

subcommand
config_gen_npu3::create_validate_subcommand()
{
std::map<std::string, std::shared_ptr<option>> validate_suboptions;
validate_suboptions.emplace("device", std::make_shared<option>("device", "d", "The Bus:Device.Function (e.g., 0000:d8:00.0) device of interest", "common", "", "string"));
validate_suboptions.emplace("json", std::make_shared<option>("json", "", "JSON ABI version for file output. Valid values are:\n"
"\tdefault - Latest JSON schema (default)", "common", "default", "string"));
validate_suboptions.emplace("output", std::make_shared<option>("output", "o", "Direct the output to the given file", "common", "", "string"));
validate_suboptions.emplace("help", std::make_shared<option>("help", "h", "Help to use this sub-command", "common", "", "none"));
validate_suboptions.emplace("run", std::make_shared<listable_description_option>("run", "r", "Run a subset of the test suite. Valid options are:\n",
"common", "", "array", get_validate_test_desc()));
validate_suboptions.emplace("param", std::make_shared<option>("param", "", "Extended parameter for a given test. Format: <test-name>:<key>:<value>", "param", "", "string"));
validate_suboptions.emplace("pmode", std::make_shared<option>("pmode", "", "Specify which power mode to run the benchmarks in. Note: Some tests might be unavailable for some modes", "hidden", "", "string"));
validate_suboptions.emplace("loop", std::make_shared<option>("loop", "", "Number of iterations to run the test", "hidden", "", "string"));

return {"validate", "Validates the given device by executing the platform's validate executable", "common", std::move(validate_suboptions)};
}

subcommand
config_gen_npu3::create_examine_subcommand()
{
std::map<std::string, std::shared_ptr<option>> examine_suboptions;
examine_suboptions.emplace("device", std::make_shared<option>("device", "d", "The Bus:Device.Function (e.g., 0000:d8:00.0) device of interest", "common", "", "string"));
examine_suboptions.emplace("json", std::make_shared<option>("json", "", "JSON ABI version for file output. Valid values are:\n"
"\tdefault - Latest JSON schema (default)", "common", "default", "string"));
examine_suboptions.emplace("output", std::make_shared<option>("output", "o", "Direct the output to the given file", "common", "", "string"));
examine_suboptions.emplace("help", std::make_shared<option>("help", "h", "Help to use this sub-command", "common", "", "none"));
examine_suboptions.emplace("watch", std::make_shared<option>("watch", "", "Refresh interval in seconds between examine updates. Exit with Ctrl+C.", "hidden", "0", "string"));
examine_suboptions.emplace("report", std::make_shared<listable_description_option>("report", "r", "The type of report to be produced. Reports currently available are:\n", "common", "", "array", get_examine_report_desc()));
examine_suboptions.emplace("firmware-log", std::make_shared<option>("firmware-log", "", "Show status|watch firmware log data", "hidden", "", "string", true));
examine_suboptions.emplace("event-trace", std::make_shared<option>("event-trace", "", "Show status|watch event trace data", "hidden", "", "string", true));
examine_suboptions.emplace("context-health", std::make_shared<option>("context-health", "", "Show status|watch context health data", "hidden", "", "string", true));

return {"examine", "This command will 'examine' the state of the system/device and will generate a report of interest in a text or JSON format.", "common", std::move(examine_suboptions)};
}

static std::shared_ptr<config_gen_ryzen>
create_config_generator(smi_hardware_config::hardware_family family)
{
Expand Down
82 changes: 82 additions & 0 deletions src/runtime_src/core/tools/common/reports/ReportAieLoad.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.

#include "ReportAieLoad.h"

#include "core/common/query_requests.h"

#include <boost/format.hpp>
#include <limits>

void
ReportAieLoad::getPropertyTreeInternal(const xrt_core::device* dev,
boost::property_tree::ptree& pt) const
{
getPropertyTree20202(dev, pt);
}

void
ReportAieLoad::getPropertyTree20202(const xrt_core::device* dev,
boost::property_tree::ptree& pt) const
{
boost::property_tree::ptree node;

try {
const xrt_core::query::aie_load::args args{m_duration_ms};
const auto data = xrt_core::device_query<xrt_core::query::aie_load>(dev, args);

const bool unavailable = (data.load_percent == std::numeric_limits<uint32_t>::max());
node.put("load_percent", unavailable ? "N/A" : std::to_string(data.load_percent));
node.put("timestamp_ms", data.timestamp_ms);
node.put("operations_per_second", data.operations_per_second);

boost::property_tree::ptree pt_counters;
for (size_t i = 0; i < 8; i++) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 8 is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

    for (size_t i = 0; i < 8; i++) {
                           ^

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: use range-based for loop instead [modernize-loop-convert]

Suggested change
for (size_t i = 0; i < 8; i++) {
for (unsigned long activity_counter : data.activity_counters) {

src/runtime_src/core/tools/common/reports/ReportAieLoad.cpp:35:

-       pt_counter.put("", data.activity_counters[i]);
+       pt_counter.put("", activity_counter);

boost::property_tree::ptree pt_counter;
pt_counter.put("", data.activity_counters[i]);
pt_counters.push_back({"", pt_counter});
}
node.add_child("activity_counters", pt_counters);
}
catch (const xrt_core::query::exception& e) {
node.put("error", e.what());
}

pt.add_child("aie_load", node);
}

void
ReportAieLoad::writeReport(const xrt_core::device* /*dev*/,
const boost::property_tree::ptree& pt,
const std::vector<std::string>& /*elementsFilter*/,
std::ostream& output) const
{
const auto& node = pt.get_child("aie_load");

// If the query failed, report the error and return.
auto error = node.get_optional<std::string>("error");
if (error) {
output << "AIE Load: " << *error << "\n\n";
return;
}

output << "AIE Load\n";

const auto load = node.get<std::string>("load_percent");
if (load == "N/A")
output << boost::format(" %-25s: N/A (AIE off, gated, or counters unavailable)\n") % "Utilization";
else
output << boost::format(" %-25s: %s%%\n") % "Utilization" % load;

output << boost::format(" %-25s: %s ops/s\n") % "Operations/Second"
% node.get<std::string>("operations_per_second");
output << boost::format(" %-25s: %s ms\n") % "FW Timestamp"
% node.get<std::string>("timestamp_ms");

output << " Activity Counters:\n";
int idx = 0;
for (const auto& [name, counter] : node.get_child("activity_counters"))
output << boost::format(" [%d]: %s\n") % idx++ % counter.get_value<std::string>();

output << "\n";
}
28 changes: 28 additions & 0 deletions src/runtime_src/core/tools/common/reports/ReportAieLoad.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2025 Advanced Micro Devices, Inc. All rights reserved.

#ifndef __ReportAieLoad_h_
#define __ReportAieLoad_h_

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: declaration uses identifier '_ReportAieLoad_h', which is a reserved identifier [bugprone-reserved-identifier]

Suggested change
#define __ReportAieLoad_h_
#define ReportAieLoad_h_


#include "tools/common/Report.h"

#include <cstdint>

class ReportAieLoad : public Report {
public:
ReportAieLoad() : Report("aie-load", "AIE array load utilization", true /*deviceRequired*/) {}

// Called by SubCmdExamine before produce_reports to forward --duration.
void setDuration(uint32_t duration_ms) { m_duration_ms = duration_ms; }

public:
virtual void getPropertyTreeInternal(const xrt_core::device* dev, boost::property_tree::ptree& pt) const;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' [cppcoreguidelines-explicit-virtual-functions]

Suggested change
virtual void getPropertyTreeInternal(const xrt_core::device* dev, boost::property_tree::ptree& pt) const;
void getPropertyTreeInternal(const xrt_core::device* dev, boost::property_tree::ptree& pt) const override;

virtual void getPropertyTree20202(const xrt_core::device* dev, boost::property_tree::ptree& pt) const;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' [cppcoreguidelines-explicit-virtual-functions]

Suggested change
virtual void getPropertyTree20202(const xrt_core::device* dev, boost::property_tree::ptree& pt) const;
void getPropertyTree20202(const xrt_core::device* dev, boost::property_tree::ptree& pt) const override;

virtual void writeReport(const xrt_core::device* dev, const boost::property_tree::ptree& pt,
const std::vector<std::string>& elementsFilter, std::ostream& output) const;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' [cppcoreguidelines-explicit-virtual-functions]

Suggested change
const std::vector<std::string>& elementsFilter, std::ostream& output) const;
void writeReport(const xrt_core::device* dev, const boost::property_tree::ptree& pt,
const std::vector<std::string>& elementsFilter, std::ostream& output) const override;


private:
uint32_t m_duration_ms = 0; // 0 = driver default (XRT_AIE_LOAD_SAMPLE_INTERVAL_MS)
};

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ ReportRyzenPlatform::writeReport(const xrt_core::device* /*_pDevice*/,

auto temp_c = pt_platform.get<std::string>("thermal.temp_C", "N/A");
_output << boost::format("%-23s : %s\n") % "Temperature (C)" % temp_c;

auto aie_load = pt_platform.get<std::string>("aie_load.load_percent", "N/A");
if (aie_load != "N/A")
_output << boost::format("%-23s : %s%%\n") % "AIE Load" % aie_load;
else
_output << boost::format("%-23s : %s\n") % "AIE Load" % aie_load;
}

_output << std::endl;
Expand Down
Loading
Loading