diff --git a/profile/plugin/aie_dtrace/aie_dtrace_metadata.cpp b/profile/plugin/aie_dtrace/aie_dtrace_metadata.cpp index 90ad7a3b..d6e0872e 100644 --- a/profile/plugin/aie_dtrace/aie_dtrace_metadata.cpp +++ b/profile/plugin/aie_dtrace/aie_dtrace_metadata.cpp @@ -15,6 +15,7 @@ #include "core/common/message.h" #include "xdp/profile/database/database.h" #include "xdp/profile/database/static_info/aie_util.h" +#include "xdp/profile/plugin/aie_dtrace/util/aie_dtrace_util.h" #include "xdp/profile/plugin/vp_base/profiling_runtime_config.h" namespace xdp { @@ -35,6 +36,21 @@ namespace xdp { return metrics; } + static constexpr const char* INPUT_PORTS_METRIC_SET = "input_ports"; + + bool settingsRequestL2L2Transfer(const std::vector& metricsSettings) + { + for (const auto& setting : metricsSettings) { + std::vector parts; + boost::split(parts, setting, boost::is_any_of(":")); + for (const auto& part : parts) { + if (part == INPUT_PORTS_METRIC_SET) + return true; + } + } + return false; + } + AieDtraceMetadata::AieDtraceMetadata(uint64_t deviceID, void* handle) : deviceID(deviceID) , handle(handle) @@ -53,14 +69,6 @@ namespace xdp { const bool usingBlob = profiling_runtime_config::has_control_instrumentation(); const auto& ci = profiling_runtime_config::control_instrumentation(); - if (usingBlob) { - 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."); - } - } - // Core (aie) tile metrics (e.g. compute_io_bound). Only used to enable the // metric; the tiles themselves are fixed to the first column. std::vector aieMetricsSettings; @@ -96,6 +104,86 @@ namespace xdp { getConfigMetricsForInterfaceTiles(SHIM_MODULE_IDX, metricsSettings); + // Memory tile / L2-L2: blob and xrt.ini are separate config sources. If either + // mem_tile or memory_tile_input_ports is present and non-empty in control_instrumentation, + // the whole mem-tile L2-L2 config must come from the blob (both fields). Otherwise + // both tile_based_memory_tile_metrics and memory_tile_input_ports must be in xrt.ini. + const std::string memTileSettings = + xrt_core::config::get_aie_dtrace_settings_tile_based_memory_tile_metrics(); + const bool iniL2L2Enabled = !memTileSettings.empty() + && settingsRequestL2L2Transfer(getSettingsVector(memTileSettings)); + const std::string iniPorts = + xrt_core::config::get_aie_dtrace_settings_memory_tile_input_ports(); + const bool iniPortsSet = !iniPorts.empty(); + const bool blobPortsSet = usingBlob && ci.memory_tile_input_ports.has_value() + && !ci.memory_tile_input_ports->empty(); + const bool memTileFieldFromBlob = usingBlob && ci.mem_tile.has_value() + && !ci.mem_tile->empty(); + const bool memTileUsesBlob = usingBlob && (memTileFieldFromBlob || blobPortsSet); + + bool l2L2FromBlob = false; + if (memTileUsesBlob) { + if (memTileFieldFromBlob && *ci.mem_tile == INPUT_PORTS_METRIC_SET) { + l2L2TransferEnabled = true; + l2L2FromBlob = true; + xrt_core::message::send(severity_level::info, "XRT", + "AIE dtrace: enabling L2-L2 via mem_tile metric '" + *ci.mem_tile + + "' from Debug.profiling_runtime_config."); + } else if (memTileFieldFromBlob) { + 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."); + } + } + else { + l2L2TransferEnabled = iniL2L2Enabled; + } + + if (blobPortsSet && !l2L2FromBlob) { + xrt_core::message::send(severity_level::error, "XRT", + "AIE dtrace: profiling_runtime_config.control_instrumentation.memory_tile_input_ports " + "is set but mem_tile is not 'input_ports'. Set " + "\"mem_tile\": \"input_ports\" under control_instrumentation to enable L2-L2."); + } + + if (iniPortsSet && !iniL2L2Enabled && !memTileUsesBlob) { + xrt_core::message::send(severity_level::error, "XRT", + "AIE dtrace: AIE_dtrace_settings.memory_tile_input_ports is set but " + "tile_based_memory_tile_metrics does not include 'input_ports'. Add " + "tile_based_memory_tile_metrics=all:input_ports (or equivalent) to enable L2-L2."); + } + + if (l2L2TransferEnabled) { + const std::string portsStr = profiling_runtime_config::resolveMemoryTileInputPorts(); + const auto designPoints = aie::dtrace::parseL2L2DesignPoints(portsStr); + if (designPoints.empty()) { + if (portsStr.empty()) { + if (l2L2FromBlob) { + xrt_core::message::send(severity_level::error, "XRT", + "AIE dtrace: profiling_runtime_config.control_instrumentation.mem_tile is " + "'input_ports' but memory_tile_input_ports is missing or empty. Add design points " + "as a {column,row:port} list under control_instrumentation " + "(e.g. \"memory_tile_input_ports\": \"{1,1:2},{5,1:1},{5,1:2}\"). " + "L2-L2 counters will not be appended to the CT."); + } else { + xrt_core::message::send(severity_level::error, "XRT", + "AIE dtrace: AIE_dtrace_settings.tile_based_memory_tile_metrics includes " + "'input_ports' but memory_tile_input_ports is missing or empty. Add design points " + "as a {column,row:port} list in xrt.ini " + "(e.g. memory_tile_input_ports={1,1:2},{5,1:1},{5,1:2}). " + "L2-L2 counters will not be appended to the CT."); + } + } else { + xrt_core::message::send(severity_level::warning, "XRT", + "AIE dtrace: L2-L2 is enabled but memory_tile_input_ports is invalid " + "(expected {column,row:port} entries; column is partition-relative, " + "0 = partition start). " + "L2-L2 counters will not be appended to the CT."); + } + l2L2TransferEnabled = false; + } + } + xrt_core::message::send(severity_level::info, "XRT", "Finished parsing AIE dtrace metadata."); } @@ -105,6 +193,8 @@ namespace xdp { const std::set validSettings { "tile_based_interface_tile_metrics", "tile_based_aie_metrics", + "tile_based_memory_tile_metrics", + "memory_tile_input_ports", "configure_aie_hardware", "config_one_partition", }; diff --git a/profile/plugin/aie_dtrace/aie_dtrace_metadata.h b/profile/plugin/aie_dtrace/aie_dtrace_metadata.h index a0661177..db1b8d65 100644 --- a/profile/plugin/aie_dtrace/aie_dtrace_metadata.h +++ b/profile/plugin/aie_dtrace/aie_dtrace_metadata.h @@ -31,6 +31,7 @@ class AieDtraceMetadata { double clockFreqMhz = 0.0; void* handle = nullptr; bool configOnePartition = false; + bool l2L2TransferEnabled = false; std::vector> configMetrics; std::map configChannel0; @@ -63,6 +64,8 @@ class AieDtraceMetadata { bool isConfigOnePartition() const { return configOnePartition; } + bool isL2L2Enabled() const { return l2L2TransferEnabled; } + bool aieMetadataEmpty() { return metadataReader == nullptr; } std::vector getSettingsVector(std::string settingsString); diff --git a/profile/plugin/aie_dtrace/util/aie_dtrace_util.cpp b/profile/plugin/aie_dtrace/util/aie_dtrace_util.cpp index 20cf5aac..4aee0fe7 100644 --- a/profile/plugin/aie_dtrace/util/aie_dtrace_util.cpp +++ b/profile/plugin/aie_dtrace/util/aie_dtrace_util.cpp @@ -5,6 +5,8 @@ #include "xdp/profile/plugin/aie_dtrace/util/aie_dtrace_util.h" +#include +#include #include "core/common/config_reader.h" #include "core/common/message.h" @@ -16,6 +18,30 @@ namespace xdp::aie::dtrace { using severity_level = xrt_core::message::severity_level; static constexpr unsigned int DEFAULT_COALESCE_RESULT_MEMORY_MB = 256; + + void addPortCounterPair(std::vector& points, + uint8_t column, + uint8_t portIndex, + uint8_t runningCounter, + uint8_t stalledCounter) + { + L2L2CounterPoint running; + running.column = column; + running.row = MEM_TILE_ROW_START; + running.portIndex = portIndex; + running.counterNumber = runningCounter; + running.eventType = "running"; + points.push_back(running); + + L2L2CounterPoint stalled; + stalled.column = column; + stalled.row = MEM_TILE_ROW_START; + stalled.portIndex = portIndex; + stalled.counterNumber = stalledCounter; + stalled.eventType = "stalled"; + points.push_back(stalled); + } + } // anonymous namespace void @@ -88,4 +114,65 @@ namespace xdp::aie::dtrace { }; } + std::vector parseL2L2DesignPoints(const std::string& spec) + { + std::vector points; + if (spec.empty()) + return points; + + // Format: {column,row:port} — column is partition-relative (0 = partition + // start_col); row is accepted for readability only (ignored). + static const std::regex pointRegex(R"(\{\s*(\d+)\s*,\s*(\d+)\s*:\s*(\d+)\s*\})"); + const auto begin = std::sregex_iterator(spec.begin(), spec.end(), pointRegex); + const auto end = std::sregex_iterator(); + for (auto it = begin; it != end; ++it) { + try { + const unsigned long column = std::stoul((*it)[1].str()); + const unsigned long dstPort = std::stoul((*it)[3].str()); + if (column > 255 || (dstPort != 1 && dstPort != 2)) + continue; + + L2L2InstrumentPoint point; + point.column = static_cast(column); + point.dstPort = static_cast(dstPort); + points.push_back(point); + } + catch (const std::exception&) { + continue; + } + } + return points; + } + + std::vector getL2L2CounterPoints( + uint32_t numCols, + const std::vector& instrumentPoints) + { + if (numCols == 0 || instrumentPoints.empty()) + return {}; + + // Design-point columns are partition-relative (0 .. numCols-1). Counters and + // CT addresses use the same relative column as the rest of the CT writer. + std::vector points; + points.reserve(instrumentPoints.size() * 2); + + // Assign counters 0-1 for the first dst path on a tile, 2-3 for the second. + std::map nextCounterByColumn; + for (const auto& instrumentPoint : instrumentPoints) { + const uint32_t column = instrumentPoint.column; + if (column >= numCols) + continue; + + uint8_t& nextCounter = nextCounterByColumn[instrumentPoint.column]; + if (nextCounter >= L2L2_MAX_DST_PATHS_PER_COLUMN * 2) + continue; + + addPortCounterPair(points, instrumentPoint.column, instrumentPoint.dstPort, + nextCounter, static_cast(nextCounter + 1)); + nextCounter = static_cast(nextCounter + 2); + } + + return points; + } + } // namespace xdp::aie::dtrace diff --git a/profile/plugin/aie_dtrace/util/aie_dtrace_util.h b/profile/plugin/aie_dtrace/util/aie_dtrace_util.h index e9e95c4d..1a9bcb1c 100644 --- a/profile/plugin/aie_dtrace/util/aie_dtrace_util.h +++ b/profile/plugin/aie_dtrace/util/aie_dtrace_util.h @@ -4,6 +4,7 @@ #ifndef AIE_DTRACE_UTIL_DOT_H #define AIE_DTRACE_UTIL_DOT_H +#include #include #include #include @@ -17,6 +18,39 @@ namespace xdp::aie::dtrace { // Shim bandwidth metric sets used for Debug.aie_dtrace (not part of standard aie_profile ini). std::map> getBandwidthInterfaceTileEventSets(int hwGen); + // ===========================L2L2 transfer metrics ========================================== + + // Inter-stamp memtile halo dst paths; design points come from xrt.ini. + // Max dst halo paths per memtile column (4 perf counters, running+stalled per path). + static constexpr uint8_t L2L2_MAX_DST_PATHS_PER_COLUMN = 2; + // Memtile row 1 (absolute array row 1; row 0 = shim/interface tile). + static constexpr uint8_t MEM_TILE_ROW_START = 1; + + struct L2L2InstrumentPoint { + uint8_t column = 0; + uint8_t dstPort = 1; + }; + + // One perf counter at a memtile dst halo path (running or stalled). + struct L2L2CounterPoint { + uint8_t column = 0; + uint8_t row = 0; + uint8_t portIndex = 1; // halo dst port (1 = from left neighbor, 2 = from right) + uint8_t counterNumber = 0; // memtile perf counter 0-3 on this tile + std::string eventType; // "running" or "stalled" + }; + + // Parses memory_tile_input_ports, e.g. "{1,1:2},{5,1:1},{5,1:2}". + // Column is partition-relative (0 = partition start_col); row is ignored. + std::vector parseL2L2DesignPoints(const std::string& spec); + + // Builds running+stalled counter pairs from design points within the partition. + // Columns in instrumentPoints are partition-relative (0 .. numCols-1). + std::vector getL2L2CounterPoints( + uint32_t numCols, + const std::vector& instrumentPoints); + + // ======================================================================================== // Apply JSON + coalesced dtrace_dump defaults when those keys are absent. // Values already present in xrt.ini or the environment are left unchanged. // Must run before XRT creates the first dtrace module (config keys lock on first read). diff --git a/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.cpp b/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.cpp index e2404650..63d965c2 100644 --- a/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.cpp +++ b/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.cpp @@ -5,11 +5,13 @@ #include "xdp/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.h" #include "xdp/profile/plugin/aie_dtrace/aie_dtrace_metadata.h" +#include "xdp/profile/plugin/aie_dtrace/util/aie_dtrace_util.h" #include "xdp/profile/database/database.h" #include "xdp/profile/database/static_info/aie_constructs.h" #include "xdp/profile/database/static_info/aie_util.h" #include "core/common/message.h" +#include "xdp/profile/plugin/vp_base/profiling_runtime_config.h" #include #include @@ -1059,9 +1061,15 @@ bool AieDtraceCTWriter::writeCounterCTFile( return false; } + const bool hasL2L2Counters = std::any_of(allCounters.begin(), allCounters.end(), + [](const CTCounterInfo& ctr) { return ctr.metricSet == "input_ports"; }); + ctFile << "# Auto-generated CT file for AIE counter monitoring\n"; ctFile << "# Generated by XRT AIE Dtrace Plugin\n"; - ctFile << "# Hardware configuration is embedded in the begin block (write_reg)\n\n"; + ctFile << "# Hardware configuration is embedded in the begin block (write_reg)\n"; + if (hasL2L2Counters) + ctFile << "# Memtile L2-L2 inter-stamp halo counters when tile_based_memory_tile_metrics includes input_ports\n"; + ctFile << "\n"; ctFile << "begin\n"; ctFile << "{\n"; @@ -1132,7 +1140,6 @@ bool AieDtraceCTWriter::writeCounterCTFile( else ctFile << "null"; - // Add event type for peak bandwidth metrics if (!ctr.eventType.empty()) { ctFile << ", \"event\": "; if (ctr.eventType == "running") @@ -1382,6 +1389,88 @@ void AieDtraceCTWriter::appendComputeIoBoundConfig( lockStarvationMemoryWrites.begin(), lockStarvationMemoryWrites.end()); } +//=============================================== L2-L2 transfers ================================================ + +void AieDtraceCTWriter::appendL2L2Config( + void* hwctx, + std::vector& counters, + std::vector& beginWrites) +{ + if (!metadata || !metadata->isL2L2Enabled()) + return; + + if (!hwctx) { + xrt_core::message::send(severity_level::debug, "XRT", + "AIE dtrace: No hwctx provided for L2-L2 configuration"); + return; + } + + boost::property_tree::ptree aiePartitionPt; + try { + aiePartitionPt = xdp::aie::getAIEPartitionInfo(hwctx); + } + catch (const std::exception& e) { + xrt_core::message::send(severity_level::warning, "XRT", + std::string("AIE dtrace: Error getting partition info for L2-L2: ") + e.what()); + return; + } + if (aiePartitionPt.empty()) + return; + + const uint32_t numCols = + static_cast(aiePartitionPt.back().second.get("num_cols", 0)); + if (numCols == 0) + return; + const auto instrumentPoints = aie::dtrace::parseL2L2DesignPoints( + profiling_runtime_config::resolveMemoryTileInputPorts()); + if (instrumentPoints.empty()) + return; + + auto counterPoints = aie::dtrace::getL2L2CounterPoints(numCols, instrumentPoints); + if (counterPoints.size() != instrumentPoints.size() * 2) { + std::stringstream l2Msg; + l2Msg << "AIE dtrace: L2-L2 design points are invalid for this partition (start_col=" + << static_cast(partitionStartCol) << ", num_cols=" << numCols + << "). Check memory_tile_input_ports {column,row:dstPort} entries: column is " + << "partition-relative (0 .. num_cols-1; 0 = start_col), max " + << static_cast(aie::dtrace::L2L2_MAX_DST_PATHS_PER_COLUMN) + << "). Skipping L2-L2 CT append."; + xrt_core::message::send(severity_level::warning, "XRT", l2Msg.str()); + return; + } + + std::map> pointsByColumn; + for (const auto& point : counterPoints) + pointsByColumn[point.column].push_back(point); + + for (const auto& entry : pointsByColumn) { + auto pcWrites = generateMemtilePerfCounterConfig(entry.first, entry.second); + beginWrites.insert(beginWrites.end(), pcWrites.begin(), pcWrites.end()); + } + + for (const auto& point : counterPoints) { + CTCounterInfo info; + info.column = point.column; + info.row = point.row; + info.counterNumber = point.counterNumber; + info.channel = point.portIndex; + info.module = "memory_tile"; + info.address = calculateCounterAddress(point.column, point.row, point.counterNumber, + "memory_tile"); + info.metricSet = "input_ports"; + info.portDirection = "input"; + info.eventType = point.eventType; + counters.push_back(info); + } + + std::stringstream l2Msg; + l2Msg << "AIE dtrace: Appending " << counterPoints.size() + << " inter-stamp memtile L2-L2 counters to CT (start_col=" + << static_cast(partitionStartCol) << ", num_cols=" << numCols << ")"; + xrt_core::message::send(severity_level::info, "XRT", l2Msg.str()); +} +//============================================================================================================ + bool AieDtraceCTWriter::generateCT( const std::string& outputPath, void* hwctx, @@ -1409,8 +1498,9 @@ bool AieDtraceCTWriter::generateCT( // Both metric families can be emitted into the same CT file. Bandwidth counters live // on shim tiles (row 0); the core-tile metric sets live on the core and memory modules - // of tiles in column 0. filterCountersByColumn keys by column, so both land in the - // matching UC group and read distinct addresses. + // of tiles in column 0. Memtile L2-L2 counters are appended when enabled. + // filterCountersByColumn keys by column, so all land in the matching UC group and read + // distinct addresses. if (includeBandwidth) appendBandwidthConfig(hwctx, bandwidthMetricSet, bandwidthChannel, allCounters, beginBlockWrites); @@ -1421,6 +1511,8 @@ bool AieDtraceCTWriter::generateCT( "AIE dtrace: Unsupported core (aie) tile metric set '" + coreMetricSet + "'; no core tile counters configured."); + appendL2L2Config(hwctx, allCounters, beginBlockWrites); + if (allCounters.empty()) { xrt_core::message::send(severity_level::warning, "XRT", "AIE dtrace: No counters configured; CT file will not be generated."); @@ -1618,6 +1710,72 @@ std::vector AieDtraceCTWriter::generateComputeMemoryConfig( return writes; } +// ===========================L2L2 transfer metrics ========================================== +std::vector AieDtraceCTWriter::generateMemtilePerfCounterConfig( + uint8_t column, + const std::vector& counterPoints) +{ + std::vector writes; + if (counterPoints.empty()) + return writes; + + const uint8_t row = counterPoints.front().row; + uint64_t tileAddress = (static_cast(column) << columnShift) | + (static_cast(row) << rowShift); + + uint8_t counterEvents[4] = {0, 0, 0, 0}; + bool counterUsed[4] = {false, false, false, false}; + for (const auto& point : counterPoints) { + if (point.counterNumber > 3) + continue; + if (point.eventType == "stalled") + counterEvents[point.counterNumber] = + static_cast(PORT_STALLED_0_MEM_TILE_EVENT + (point.portIndex * 4)); + else + counterEvents[point.counterNumber] = + static_cast(PORT_RUNNING_0_MEM_TILE_EVENT + (point.portIndex * 4)); + counterUsed[point.counterNumber] = true; + } + + for (uint8_t ctr = 0; ctr < 4; ++ctr) { + if (!counterUsed[ctr]) + continue; + + CTRegisterWrite resetWrite; + resetWrite.address = tileAddress + MEM_TILE_BASE_OFFSET + (ctr * 4); + resetWrite.value = 0; + resetWrite.comment = "Reset memtile PerfCounter" + std::to_string(ctr) + + " @ col " + std::to_string(column); + writes.push_back(resetWrite); + } + + if (counterUsed[0] || counterUsed[1]) { + CTRegisterWrite ctrlWrite; + ctrlWrite.address = tileAddress + MEM_TILE_PERF_CTRL0_OFFSET; + ctrlWrite.value = (static_cast(counterEvents[0]) << 0) + | (static_cast(counterEvents[0]) << 8) + | (static_cast(counterEvents[1]) << 16) + | (static_cast(counterEvents[1]) << 24); + ctrlWrite.comment = "Memtile PerfCtrl0 @ col " + std::to_string(column) + + " (PORT_RUNNING/STALLED on dst halo ports)"; + writes.push_back(ctrlWrite); + } + + if (counterUsed[2] || counterUsed[3]) { + CTRegisterWrite ctrlWrite; + ctrlWrite.address = tileAddress + MEM_TILE_PERF_CTRL1_OFFSET; + ctrlWrite.value = (static_cast(counterEvents[2]) << 0) + | (static_cast(counterEvents[2]) << 8) + | (static_cast(counterEvents[3]) << 16) + | (static_cast(counterEvents[3]) << 24); + ctrlWrite.comment = "Memtile PerfCtrl1 @ col " + std::to_string(column) + + " (PORT_RUNNING/STALLED on dst halo ports)"; + writes.push_back(ctrlWrite); + } + + return writes; +} + std::vector AieDtraceCTWriter::generateLockStarvationCoreConfig( uint8_t column, uint8_t row) { diff --git a/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.h b/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.h index 4b6f065b..f6591049 100644 --- a/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.h +++ b/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.h @@ -13,6 +13,7 @@ #include #include "aiebu/aiebu_assembler.h" +#include "xdp/profile/plugin/aie_dtrace/util/aie_dtrace_util.h" namespace xdp { @@ -359,6 +360,16 @@ class AieDtraceCTWriter { void appendComputeIoBoundConfig(std::vector& counters, std::vector& beginWrites); + /** + * @brief Append memtile L2-L2 counters and begin-block writes from design points + * @param hwctx Hardware context handle for partition column bounds + * @param counters [in,out] Accumulated counter list + * @param beginWrites [in,out] Accumulated begin-block register writes + */ + void appendL2L2Config(void* hwctx, + std::vector& counters, + std::vector& beginWrites); + /** * @brief Generate the core module config for the compute_io_bound lock correlation tile * @@ -453,6 +464,10 @@ class AieDtraceCTWriter { const std::vector& beginBlockWrites, const std::string& outputPath); + std::vector generateMemtilePerfCounterConfig( + uint8_t column, + const std::vector& counterPoints); + private: VPDatabase* db; std::shared_ptr metadata; @@ -472,8 +487,13 @@ class AieDtraceCTWriter { // Stream switch and performance counter configuration offsets static constexpr uint64_t STREAM_SWITCH_EVENT_PORT_SEL_OFFSET = 0x0003FF00; + static constexpr uint64_t MEM_TILE_PERF_CTRL0_OFFSET = 0x00091000; + static constexpr uint64_t MEM_TILE_PERF_CTRL1_OFFSET = 0x00091004; static constexpr uint64_t PERF_CTRL_OFFSET = 0x00031000; + static constexpr uint8_t PORT_RUNNING_0_MEM_TILE_EVENT = 80; // PORT_RUNNING_N = 80 + 4*N + static constexpr uint8_t PORT_STALLED_0_MEM_TILE_EVENT = 81; // PORT_STALLED_N = 81 + 4*N + // Core (aie) module offsets for the compute_io_bound metric (aie2ps). // Performance_Control0 (0x00037500) is deliberately never written: it holds counter // 0's start/stop events, and the driver's ECC scrubbing owns core counter 0 diff --git a/profile/plugin/aie_dtrace/ve2/aie_dtrace_ve2.cpp b/profile/plugin/aie_dtrace/ve2/aie_dtrace_ve2.cpp index ca6748bc..1b4212c2 100644 --- a/profile/plugin/aie_dtrace/ve2/aie_dtrace_ve2.cpp +++ b/profile/plugin/aie_dtrace/ve2/aie_dtrace_ve2.cpp @@ -142,7 +142,7 @@ namespace xdp { + std::to_string(bandwidthChannel) + ") from configuration"); } - if (!includeBandwidth && coreMetricSet.empty()) { + if (!includeBandwidth && coreMetricSet.empty() && !metadata->isL2L2Enabled()) { xrt_core::message::send(severity_level::info, "XRT", "AIE dtrace: No metrics configured; skipping CT generation."); return; @@ -159,10 +159,14 @@ namespace xdp { genMsg << "AIE dtrace: CT generated for kernel '" << kernel_name << "' ("; if (includeBandwidth) genMsg << "interface_tile=" << bandwidthMetricSet; - if (includeBandwidth && !coreMetricSet.empty()) + if (includeBandwidth && (!coreMetricSet.empty() || metadata->isL2L2Enabled())) genMsg << ", "; if (!coreMetricSet.empty()) genMsg << "aie_tile=" << coreMetricSet; + if (!coreMetricSet.empty() && metadata->isL2L2Enabled()) + genMsg << ", "; + if (metadata->isL2L2Enabled()) + genMsg << "memtile=input_ports"; genMsg << ")"; xrt_core::message::send(severity_level::debug, "XRT", genMsg.str()); diff --git a/profile/plugin/vp_base/profiling_runtime_config.cpp b/profile/plugin/vp_base/profiling_runtime_config.cpp index 5be86045..b1b7a217 100644 --- a/profile/plugin/vp_base/profiling_runtime_config.cpp +++ b/profile/plugin/vp_base/profiling_runtime_config.cpp @@ -77,7 +77,7 @@ namespace xdp::profiling_runtime_config { parse_control_instrumentation(const pt::ptree& ci_tree) { static const std::set known_keys{ - "aie_tile", "mem_tile", "interface_tile" + "aie_tile", "mem_tile", "interface_tile", "memory_tile_input_ports" }; control_instrumentation_t ci; @@ -101,6 +101,12 @@ namespace xdp::profiling_runtime_config { if (!value.empty()) info("profiling_runtime_config.control_instrumentation.interface_tile='" + value + "'"); } + else if (key == "memory_tile_input_ports") { + ci.memory_tile_input_ports = value; + if (!value.empty()) + info("profiling_runtime_config.control_instrumentation.memory_tile_input_ports='" + + value + "'"); + } else { std::stringstream msg; msg << "Unknown key 'profiling_runtime_config.control_instrumentation." @@ -198,7 +204,8 @@ namespace xdp::profiling_runtime_config { 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(); + || out.ci.interface_tile.has_value() + || out.ci.memory_tile_input_ports.has_value(); } if (const auto et_opt = root.get_child_optional("event_trace")) { @@ -252,6 +259,31 @@ namespace xdp::profiling_runtime_config { return get_parsed().ci; } + std::string + resolveMemoryTileInputPorts() + { + static constexpr const char* INPUT_PORTS_METRIC_SET = "input_ports"; + + if (has_control_instrumentation()) { + const auto& ci = control_instrumentation(); + const bool memTileFieldFromBlob = ci.mem_tile.has_value() && !ci.mem_tile->empty(); + const bool blobPortsSet = ci.memory_tile_input_ports.has_value() + && !ci.memory_tile_input_ports->empty(); + const bool memTileUsesBlob = memTileFieldFromBlob || blobPortsSet; + + if (memTileFieldFromBlob && *ci.mem_tile == INPUT_PORTS_METRIC_SET) { + if (blobPortsSet) + return *ci.memory_tile_input_ports; + return {}; + } + + // Partial blob mem-tile config: do not fall back to xrt.ini ports. + if (memTileUsesBlob) + return {}; + } + return xrt_core::config::get_aie_dtrace_settings_memory_tile_input_ports(); + } + bool has_event_trace() { diff --git a/profile/plugin/vp_base/profiling_runtime_config.h b/profile/plugin/vp_base/profiling_runtime_config.h index f3685c06..7271b000 100644 --- a/profile/plugin/vp_base/profiling_runtime_config.h +++ b/profile/plugin/vp_base/profiling_runtime_config.h @@ -26,7 +26,8 @@ // load-time gate. // // Example blob: -// {"control_instrumentation":{"aie_tile":"func_stalls","mem_tile":"","interface_tile":"ddr_bandwidth"},"event_trace":{"tile_based_aie_tile_metrics":"all:functions"}} +// {"control_instrumentation":{"aie_tile":"func_stalls","mem_tile":"input_ports","interface_tile":"ddr_bandwidth", +// "memory_tile_input_ports":"{1,1:2},{5,1:1}"},"event_trace":{"tile_based_aie_tile_metrics":"all:functions"}} namespace xdp::profiling_runtime_config { @@ -34,6 +35,7 @@ namespace xdp::profiling_runtime_config { std::optional aie_tile; // maps to "core" module internally std::optional mem_tile; // maps to "mem_tile" module internally std::optional interface_tile; // maps to "shim" module internally + std::optional memory_tile_input_ports; // L2-L2 {column,row:port} list }; // Mirrors the AIE_trace_settings.* xrt.ini keys 1:1. When event_trace is @@ -106,13 +108,19 @@ namespace xdp::profiling_runtime_config { 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). + // with at least one recognized key (aie_tile / mem_tile / interface_tile / + // memory_tile_input_ports). 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(); + // When control_instrumentation carries mem_tile or memory_tile_input_ports, + // ports come only from the blob (requires mem_tile "input_ports"). Otherwise + // AIE_dtrace_settings.memory_tile_input_ports from xrt.ini is used. + XDP_CORE_EXPORT std::string resolveMemoryTileInputPorts(); + // True when is_set() and the blob contained an "event_trace" object (even // if empty). Note this only reflects presence in the blob - it is NOT an // AIE trace enablement signal by itself; see aie_trace_enabled() in