Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
54 changes: 49 additions & 5 deletions profile/plugin/aie_profile/aie_profile_metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "core/common/device.h"
#include "core/common/message.h"
#include "xdp/profile/database/database.h"
#include "xdp/profile/plugin/vp_base/profiling_runtime_config.h"
#include "xdp/profile/plugin/vp_base/vp_base_plugin.h"
#include "xdp/profile/database/parser/metrics.h"
#include "xdp/profile/database/parser/json_parser.h"
Expand Down Expand Up @@ -179,7 +180,7 @@ namespace xdp {
, m_dtraceBandwidthMode(true)
{
xrt_core::message::send(severity_level::info,
"XRT", "Parsing AIE dtrace metadata (AIE_dtrace_settings).");
"XRT", "Parsing AIE dtrace metadata.");
VPDatabase* db = VPDatabase::Instance();

metadataReader = (db->getStaticInfo()).getAIEmetadataReader(deviceID);
Expand All @@ -195,18 +196,61 @@ namespace xdp {

clockFreqMhz = (db->getStaticInfo()).getClockRateMHz(deviceID, false);

// Polling interval and the "start" control always come from xrt.ini.
pollingInterval = xrt_core::config::get_aie_dtrace_settings_interval_us();

setProfileStartControl(compilerOptions.graph_iterator_event, false, nullptr);

// Metric-set source precedence:
// 1. If Debug.profiling_runtime_config carries a control_instrumentation
// section, it wins. Only interface_tile is wired today; aie_tile and
// mem_tile entries are logged for a follow-up.
// 2. Otherwise fall back to the legacy AIE_dtrace_settings.* xrt.ini
// options.
const bool usingBlob = profiling_runtime_config::has_control_instrumentation();
const auto& ci = profiling_runtime_config::control_instrumentation();

if (usingBlob) {
xrt_core::message::send(severity_level::info, "XRT",
"AIE dtrace: using control_instrumentation from "
"Debug.profiling_runtime_config; AIE_dtrace_settings.* will be ignored "
"for metric sets.");

if (ci.aie_tile.has_value() && !ci.aie_tile->empty()) {
xrt_core::message::send(severity_level::info, "XRT",
"AIE dtrace: core tile metric '" + *ci.aie_tile
+ "' from profiling_runtime_config will be supported in a follow-up.");
}
if (ci.mem_tile.has_value() && !ci.mem_tile->empty()) {
xrt_core::message::send(severity_level::info, "XRT",
"AIE dtrace: mem tile metric '" + *ci.mem_tile
+ "' from profiling_runtime_config will be supported in a follow-up.");
}
}

for (int module = 0; module < NUM_MODULES; ++module) {
if (moduleTypes[module] != module_type::shim)
continue;

auto metricsSettings =
getSettingsVector(xrt_core::config::get_aie_dtrace_settings_tile_based_interface_tile_metrics());
auto graphMetricsSettings =
getSettingsVector(xrt_core::config::get_aie_dtrace_settings_graph_based_interface_tile_metrics());
std::vector<std::string> metricsSettings;
std::vector<std::string> graphMetricsSettings;

if (usingBlob) {
if (ci.interface_tile.has_value() && !ci.interface_tile->empty()) {
// Blob carries a bare metric name (e.g. "ddr_bandwidth"). Synthesize
// an "all:<metric>" tile-based selection so the existing parser
// applies it to every interface tile.
metricsSettings = getSettingsVector("all:" + *ci.interface_tile);
}
// If interface_tile is unset/empty in the blob, the blob wins and
// leaves shim tiles unconfigured (no xrt.ini fallback for this knob).
}
else {
metricsSettings =
getSettingsVector(xrt_core::config::get_aie_dtrace_settings_tile_based_interface_tile_metrics());
graphMetricsSettings =
getSettingsVector(xrt_core::config::get_aie_dtrace_settings_graph_based_interface_tile_metrics());
}

getConfigMetricsForInterfaceTiles(module, metricsSettings, graphMetricsSettings);
}
Expand Down
149 changes: 149 additions & 0 deletions profile/plugin/vp_base/profiling_runtime_config.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved

#define XDP_CORE_SOURCE

#include <set>
#include <sstream>
#include <string>

#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>

#include "core/common/config_reader.h"
#include "core/common/message.h"

#include "xdp/profile/plugin/vp_base/profiling_runtime_config.h"

namespace xdp::profiling_runtime_config {

using severity_level = xrt_core::message::severity_level;
namespace pt = boost::property_tree;

namespace {

struct parsed_blob_t {
bool is_set = false;
bool has_ci = false;
control_instrumentation_t ci{};
};

// These helpers are only called from inside get_parsed()'s cached static
// initializer, so every message they emit fires at most once per process.
void
warn(const std::string& msg)
{
xrt_core::message::send(severity_level::warning, "XRT", msg);
}

void
info(const std::string& msg)
{
xrt_core::message::send(severity_level::info, "XRT", msg);
}

// Parse the control_instrumentation subtree: copy known string keys into
// the returned struct and warn about any unknown keys.
control_instrumentation_t
parse_control_instrumentation(const pt::ptree& ci_tree)
{
static const std::set<std::string> known_keys{
"aie_tile", "mem_tile", "interface_tile"
};

control_instrumentation_t ci;

for (const auto& kv : ci_tree) {
const auto& key = kv.first;
const auto value = kv.second.get_value<std::string>("");

if (key == "aie_tile") {
ci.aie_tile = value;
if (!value.empty())
info("profiling_runtime_config.control_instrumentation.aie_tile='" + value + "'");
}
else if (key == "mem_tile") {
ci.mem_tile = value;
if (!value.empty())
info("profiling_runtime_config.control_instrumentation.mem_tile='" + value + "'");
}
else if (key == "interface_tile") {
ci.interface_tile = value;
if (!value.empty())
info("profiling_runtime_config.control_instrumentation.interface_tile='" + value + "'");
}
else {
std::stringstream msg;
msg << "Unknown key 'profiling_runtime_config.control_instrumentation."
<< key << "' ignored. Supported keys:";
const char* sep = " ";
for (const auto& k : known_keys) {
msg << sep << k;
sep = ", ";
}
warn(msg.str());
}
}

return ci;
}

// Parse the root blob exactly once.
const parsed_blob_t&
get_parsed()
{
static const parsed_blob_t cached = [] {
parsed_blob_t out;

const std::string raw = xrt_core::config::get_profiling_runtime_config();
if (raw.empty())
return out;

try {
pt::ptree root;
std::istringstream is(raw);
pt::read_json(is, root);

out.is_set = true;

if (const auto ci_opt = root.get_child_optional("control_instrumentation")) {
out.ci = parse_control_instrumentation(*ci_opt);
out.has_ci = out.ci.aie_tile.has_value()
|| out.ci.mem_tile.has_value()
|| out.ci.interface_tile.has_value();
}
}
catch (const std::exception& ex) {
warn(std::string("Failed to parse Debug.profiling_runtime_config "
"as JSON; ignoring runtime config. Details: ")
+ ex.what());
return parsed_blob_t{};
}

return out;
}();

return cached;
}

} // anonymous namespace

bool
is_set()
{
return get_parsed().is_set;
}

bool
has_control_instrumentation()
{
return get_parsed().has_ci;
}

const control_instrumentation_t&
control_instrumentation()
{
return get_parsed().ci;
}

} // namespace xdp::profiling_runtime_config
50 changes: 50 additions & 0 deletions profile/plugin/vp_base/profiling_runtime_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2026 Advanced Micro Devices, Inc. All rights reserved

#ifndef PROFILING_RUNTIME_CONFIG_DOT_H
#define PROFILING_RUNTIME_CONFIG_DOT_H

#include <optional>
#include <string>

#include "xdp/config.h"

// Parser for the XRT INI option Debug.profiling_runtime_config which holds
// an inline JSON blob describing XDP runtime configuration. Only the
// control_instrumentation section is consumed by this change; other top-level
// keys (event_trace, etc.) are accepted but ignored and may be wired up in a
// follow-up.
//
// The parser lives on the XDP side (xdp_core) so it can evolve without
// churning the stable xrt_coreutil interface. Plugin enablement and xdp_mode
// selection are not derived from this blob: FlexmlRT (or the user) is
// expected to set Debug.aie_dtrace / Debug.aie_trace and Debug.xdp_mode in
// xrt.ini directly. The blob's role is to override the per-metric settings
// that the corresponding plugin would otherwise read from
// AIE_dtrace_settings.* / AIE_trace_settings.* in xrt.ini.
//
// Example blob:
// {"control_instrumentation":{"aie_tile":"func_stalls","mem_tile":"","interface_tile":"ddr_bandwidth"},"event_trace":{}}

namespace xdp::profiling_runtime_config {

struct control_instrumentation_t {
std::optional<std::string> aie_tile; // maps to "core" module internally
std::optional<std::string> mem_tile; // maps to "mem_tile" module internally
std::optional<std::string> interface_tile; // maps to "shim" module internally
};

// True when the xrt.ini value is non-empty and parsed successfully.
XDP_CORE_EXPORT bool is_set();

// True when is_set() and the blob contained a control_instrumentation object
// with at least one recognized key (aie_tile / mem_tile / interface_tile).
XDP_CORE_EXPORT bool has_control_instrumentation();

// Returns the cached control_instrumentation view. Safe to call even when
// has_control_instrumentation() is false (all members will be empty).
XDP_CORE_EXPORT const control_instrumentation_t& control_instrumentation();

} // namespace xdp::profiling_runtime_config

#endif
Loading