diff --git a/profile/plugin/aie_dtrace/aie_dtrace_metadata.cpp b/profile/plugin/aie_dtrace/aie_dtrace_metadata.cpp index 0013e511..d9c5b843 100644 --- a/profile/plugin/aie_dtrace/aie_dtrace_metadata.cpp +++ b/profile/plugin/aie_dtrace/aie_dtrace_metadata.cpp @@ -29,6 +29,12 @@ namespace xdp { return metrics; } + static const std::set& coreMetricSets() + { + static const std::set metrics = {"compute_io_bound", "off"}; + return metrics; + } + AieDtraceMetadata::AieDtraceMetadata(uint64_t deviceID, void* handle) : deviceID(deviceID) , handle(handle) @@ -48,11 +54,6 @@ namespace xdp { const auto& ci = profiling_runtime_config::control_instrumentation(); if (usingBlob) { - 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 @@ -60,6 +61,23 @@ namespace xdp { } } + // Core (aie) tile metrics (e.g. compute_io_bound). Only used to enable the + // metric; the tile itself is fixed to the first column / first core row. + std::vector aieMetricsSettings; + if (usingBlob && ci.aie_tile.has_value() && !ci.aie_tile->empty()) { + xrt_core::message::send(severity_level::info, "XRT", + "AIE dtrace: using aie_tile metric '" + *ci.aie_tile + + "' from Debug.profiling_runtime_config."); + aieMetricsSettings = getSettingsVector("all:" + *ci.aie_tile); + } + else { + const std::string tileBasedAie = + xrt_core::config::get_aie_dtrace_settings_tile_based_aie_metrics(); + if (!tileBasedAie.empty()) + aieMetricsSettings = getSettingsVector(tileBasedAie); + } + getConfigMetricsForAIETiles(CORE_MODULE_IDX, aieMetricsSettings); + std::vector metricsSettings; if (usingBlob && ci.interface_tile.has_value() && !ci.interface_tile->empty()) { xrt_core::message::send(severity_level::info, "XRT", @@ -86,6 +104,7 @@ namespace xdp { using boost::property_tree::ptree; const std::set validSettings { "tile_based_interface_tile_metrics", + "tile_based_aie_metrics", "configure_aie_hardware", "config_one_partition", }; @@ -122,6 +141,55 @@ namespace xdp { return bandwidthMetricSets().count(metricSet) > 0; } + bool AieDtraceMetadata::isCoreMetricSet(const std::string& metricSet) const + { + return coreMetricSets().count(metricSet) > 0; + } + + void AieDtraceMetadata::getConfigMetricsForAIETiles(int moduleIdx, + const std::vector& metricsSettings) + { + if (metricsSettings.empty()) + return; + + // These settings only enable/disable the metric. The tile itself is fixed + // to the first column / first core row; only a single core tile is ever + // configured for compute_io_bound. + std::string metricSet; + for (const auto& setting : metricsSettings) { + std::vector parts; + boost::split(parts, setting, boost::is_any_of(":")); + // Accept "all:", ":", or bare "". + const std::string& candidate = parts.back(); + if (isCoreMetricSet(candidate)) { + metricSet = candidate; + break; + } + } + + if (metricSet.empty()) { + xrt_core::message::send(severity_level::warning, "XRT", + "AIE dtrace: no valid core (aie) tile metric set found in " + "tile_based_aie_metrics. Supported: compute_io_bound, off."); + return; + } + + if (metricSet == "off") + return; + + tile_type tile; + tile.col = COMPUTE_IO_CORE_COL; + tile.row = COMPUTE_IO_CORE_ROW; + tile.active_core = true; + configMetrics[moduleIdx][tile] = metricSet; + + xrt_core::message::send(severity_level::info, "XRT", + "AIE dtrace: configured core tile (col " + + std::to_string(static_cast(COMPUTE_IO_CORE_COL)) + ", row " + + std::to_string(static_cast(COMPUTE_IO_CORE_ROW)) + + ") with metric set '" + metricSet + "'."); + } + void AieDtraceMetadata::getConfigMetricsForInterfaceTiles(int moduleIdx, const std::vector& metricsSettings) { diff --git a/profile/plugin/aie_dtrace/aie_dtrace_metadata.h b/profile/plugin/aie_dtrace/aie_dtrace_metadata.h index f75f99c6..5b3b7469 100644 --- a/profile/plugin/aie_dtrace/aie_dtrace_metadata.h +++ b/profile/plugin/aie_dtrace/aie_dtrace_metadata.h @@ -18,8 +18,15 @@ namespace xdp { class AieDtraceMetadata { private: static constexpr int SHIM_MODULE_IDX = static_cast(module_type::shim); + static constexpr int CORE_MODULE_IDX = static_cast(module_type::core); static constexpr int NUM_MODULES = static_cast(module_type::num_types); + // compute_io_bound configures a single core tile: the first column / first + // core row. Used as the config-map key here; the CT writer derives the + // actual absolute row from driver_config.aie_tile_row_start. + static constexpr uint8_t COMPUTE_IO_CORE_COL = 0; + static constexpr uint8_t COMPUTE_IO_CORE_ROW = 3; + uint64_t deviceID = 0; double clockFreqMhz = 0.0; void* handle = nullptr; @@ -34,7 +41,10 @@ class AieDtraceMetadata { void checkDtraceSettings(); void getConfigMetricsForInterfaceTiles(int moduleIdx, const std::vector& metricsSettings); + void getConfigMetricsForAIETiles(int moduleIdx, + const std::vector& metricsSettings); bool isBandwidthMetricSet(const std::string& metricSet) const; + bool isCoreMetricSet(const std::string& metricSet) const; public: AieDtraceMetadata(uint64_t deviceID, void* handle); @@ -43,8 +53,12 @@ class AieDtraceMetadata { void* getHandle() { return handle; } bool isConfigured() const { - return SHIM_MODULE_IDX < static_cast(configMetrics.size()) + const int numModules = static_cast(configMetrics.size()); + const bool shimConfigured = SHIM_MODULE_IDX < numModules && !configMetrics[SHIM_MODULE_IDX].empty(); + const bool coreConfigured = CORE_MODULE_IDX < numModules + && !configMetrics[CORE_MODULE_IDX].empty(); + return shimConfigured || coreConfigured; } bool isConfigOnePartition() const { return configOnePartition; } 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 a5f313fa..160a19f5 100644 --- a/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.cpp +++ b/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.cpp @@ -101,11 +101,13 @@ AieDtraceCTWriter::AieDtraceCTWriter(VPDatabase* database, , deviceId(deviceId) , columnShift(0) , rowShift(0) + , coreRowStart(0) , partitionStartCol(startCol) { auto config = metadata->getAIEConfigMetadata(); columnShift = config.column_shift; rowShift = config.row_shift; + coreRowStart = config.aie_tile_row_start; } bool AieDtraceCTWriter::generate() @@ -1039,7 +1041,7 @@ std::vector AieDtraceCTWriter::generateBandwidthCounters( return counters; } -bool AieDtraceCTWriter::writeBandwidthCTFile( +bool AieDtraceCTWriter::writeCounterCTFile( const std::vector& asmFileInfoList, const std::vector& allCounters, const std::vector& beginBlockWrites, @@ -1054,10 +1056,9 @@ bool AieDtraceCTWriter::writeBandwidthCTFile( return false; } - ctFile << "# Auto-generated CT file for AIE bandwidth monitoring\n"; - ctFile << "# Generated by XRT AIE Dtrace Plugin (simplified bandwidth mode)\n"; - ctFile << "# Fixed 4 counters per shim tile: S2MM ch0,ch1 + MM2S ch0,ch1\n"; - ctFile << "# Post-processing filters by metric: read_bandwidth, write_bandwidth, ddr_bandwidth\n\n"; + 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 << "begin\n"; ctFile << "{\n"; @@ -1172,33 +1173,16 @@ bool AieDtraceCTWriter::writeBandwidthCTFile( ctFile.close(); std::stringstream msg; - msg << "Generated bandwidth CT file: " << outputPath + msg << "Generated CT file: " << outputPath << " (" << allCounters.size() << " counters)"; xrt_core::message::send(severity_level::info, "XRT", msg.str()); return true; } -bool AieDtraceCTWriter::generateBandwidthCT( - const std::string& outputPath, - void* hwctx, - const std::vector& opLocations, - const std::string& metricSet, - uint8_t channel) +std::vector AieDtraceCTWriter::buildAsmFileInfoList( + const std::vector& opLocations) { - if (opLocations.empty()) { - xrt_core::message::send(severity_level::debug, "XRT", - "AIE dtrace: No op_locations provided for bandwidth CT generation"); - return false; - } - - auto shimColumns = getShimTileColumns(hwctx); - if (shimColumns.empty()) { - xrt_core::message::send(severity_level::warning, "XRT", - "AIE dtrace: No shim columns found in partition. Cannot generate bandwidth CT."); - return false; - } - std::vector asmFileInfoList; std::regex filenamePattern(R"(aie_runtime_control(\d+)?\.asm)"); @@ -1237,18 +1221,120 @@ bool AieDtraceCTWriter::generateBandwidthCT( } } + if (!asmFileInfoList.empty()) + applyUcSpansFromOpLoc(asmFileInfoList); + + return asmFileInfoList; +} + +bool AieDtraceCTWriter::appendBandwidthConfig( + void* hwctx, const std::string& metricSet, uint8_t channel, + std::vector& counters, std::vector& beginWrites) +{ + auto shimColumns = getShimTileColumns(hwctx); + if (shimColumns.empty()) { + xrt_core::message::send(severity_level::warning, "XRT", + "AIE dtrace: No shim columns found in partition. Skipping bandwidth counters."); + return false; + } + + auto bwCounters = generateBandwidthCounters(shimColumns, metricSet, channel); + if (bwCounters.empty()) { + xrt_core::message::send(severity_level::warning, "XRT", + "AIE dtrace: No bandwidth counters generated"); + return false; + } + counters.insert(counters.end(), bwCounters.begin(), bwCounters.end()); + + for (uint8_t column : shimColumns) { + // For detailed sets, counter 0 monitors PORT_RUNNING on the channel's + // stream-switch port, so the SS event port selection must be programmed. + auto streamSwitchWrites = generateStreamSwitchPortConfig(column, metricSet, channel); + beginWrites.insert(beginWrites.end(), streamSwitchWrites.begin(), streamSwitchWrites.end()); + + auto perfCounterWrites = generatePerfCounterConfig(column, metricSet, channel); + beginWrites.insert(beginWrites.end(), perfCounterWrites.begin(), perfCounterWrites.end()); + } + + return true; +} + +void AieDtraceCTWriter::appendComputeIoBoundConfig( + const ComputeIoCoreConfig& cfg, + std::vector& counters, std::vector& beginWrites) +{ + // Single core tile: two counters (kernelWrapper and total) using performance + // counters 2 and 3. The listing/metadata use relative core rows, so the first + // core row's absolute row for register addressing is aie_tile_row_start. + const uint8_t row = coreRowStart; + + CTCounterInfo compute; + compute.column = COMPUTE_IO_CORE_COL; + compute.row = row; + compute.counterNumber = 2; + compute.channel = 0; + compute.module = "aie"; + compute.address = calculateCounterAddress(COMPUTE_IO_CORE_COL, row, 2, "aie"); + compute.metricSet = "compute_io_bound"; + compute.portDirection = ""; + compute.eventType = "compute"; + counters.push_back(compute); + + CTCounterInfo ioCompute; + ioCompute.column = COMPUTE_IO_CORE_COL; + ioCompute.row = row; + ioCompute.counterNumber = 3; + ioCompute.channel = 0; + ioCompute.module = "aie"; + ioCompute.address = calculateCounterAddress(COMPUTE_IO_CORE_COL, row, 3, "aie"); + ioCompute.metricSet = "compute_io_bound"; + ioCompute.portDirection = ""; + ioCompute.eventType = "io_compute"; + counters.push_back(ioCompute); + + auto pcWrites = generatePcStartStopCoreConfig(COMPUTE_IO_CORE_COL, cfg); + beginWrites.insert(beginWrites.end(), pcWrites.begin(), pcWrites.end()); +} + +bool AieDtraceCTWriter::generateCT( + const std::string& outputPath, + void* hwctx, + const std::vector& opLocations, + bool includeBandwidth, + const std::string& bandwidthMetricSet, + uint8_t bandwidthChannel, + bool includeComputeIoBound, + const ComputeIoCoreConfig& computeIoCfg) +{ + if (opLocations.empty()) { + xrt_core::message::send(severity_level::debug, "XRT", + "AIE dtrace: No op_locations provided for CT generation"); + return false; + } + + auto asmFileInfoList = buildAsmFileInfoList(opLocations); if (asmFileInfoList.empty()) { xrt_core::message::send(severity_level::debug, "XRT", - "AIE dtrace: No ASM files found in op_locations for bandwidth CT generation"); + "AIE dtrace: No ASM files found in op_locations for CT generation"); return false; } - applyUcSpansFromOpLoc(asmFileInfoList); + std::vector allCounters; + std::vector beginBlockWrites; + + // Both metric families can be emitted into the same CT file. Bandwidth + // counters live on shim tiles (row 0); the compute_io_bound counters live on + // the single core tile (col 0, first core row). filterCountersByColumn keys by column, + // so both simply land in the matching UC group and read distinct addresses. + if (includeBandwidth) + appendBandwidthConfig(hwctx, bandwidthMetricSet, bandwidthChannel, allCounters, beginBlockWrites); + + if (includeComputeIoBound) + appendComputeIoBoundConfig(computeIoCfg, allCounters, beginBlockWrites); - auto allCounters = generateBandwidthCounters(shimColumns, metricSet, channel); if (allCounters.empty()) { xrt_core::message::send(severity_level::warning, "XRT", - "AIE dtrace: No bandwidth counters generated"); + "AIE dtrace: No counters configured; CT file will not be generated."); return false; } @@ -1258,18 +1344,72 @@ bool AieDtraceCTWriter::generateBandwidthCT( asmFileInfo.counters = filterCountersByColumn(allCounters, asmFileInfo.colStart, asmFileInfo.colEnd); } - std::vector beginBlockWrites; - for (uint8_t column : shimColumns) { - // For detailed sets, counter 0 monitors PORT_RUNNING on the channel's - // stream-switch port, so the SS event port selection must be programmed. - auto ssWrites = generateStreamSwitchPortConfig(column, metricSet, channel); - beginBlockWrites.insert(beginBlockWrites.end(), ssWrites.begin(), ssWrites.end()); + return writeCounterCTFile(asmFileInfoList, allCounters, beginBlockWrites, outputPath); +} - auto pcWrites = generatePerfCounterConfig(column, metricSet, channel); - beginBlockWrites.insert(beginBlockWrites.end(), pcWrites.begin(), pcWrites.end()); +bool AieDtraceCTWriter::generateBandwidthCT( + const std::string& outputPath, + void* hwctx, + const std::vector& opLocations, + const std::string& metricSet, + uint8_t channel) +{ + return generateCT(outputPath, hwctx, opLocations, + /*includeBandwidth=*/true, metricSet, channel, + /*includeComputeIoBound=*/false, ComputeIoCoreConfig{}); +} + +std::vector AieDtraceCTWriter::generatePcStartStopCoreConfig( + uint8_t column, const ComputeIoCoreConfig& cfg) +{ + std::vector writes; + + const uint8_t row = coreRowStart; + uint64_t tileAddress = (static_cast(column) << columnShift) | + (static_cast(row) << rowShift); + + auto addWrite = [&](uint64_t offset, uint32_t value, const std::string& comment) { + CTRegisterWrite w; + w.address = tileAddress + offset; + w.value = value; + w.comment = comment; + writes.push_back(w); + }; + + std::string loc = "core (" + std::to_string(column) + "," + std::to_string(row) + ")"; + + // PC_Event0/1 bracket the kernelWrapper dispatch window (counter 2); + // PC_Event2/3 give the total range [0, PROG_MEM_END] (counter 3). + // PC_Event0..3: Valid bit + 14-bit PC address. + addWrite(CM_PC_EVENT0 + 0, PC_EVENT_VALID | (cfg.startPc & PC_ADDRESS_MASK), + "PC_Event0 @ " + loc + " (kernelWrapper start_pc = indirect kernel dispatch)"); + addWrite(CM_PC_EVENT0 + 4, PC_EVENT_VALID | (cfg.stopPc & PC_ADDRESS_MASK), + "PC_Event1 @ " + loc + " (kernelWrapper stop_pc)"); + addWrite(CM_PC_EVENT0 + 8, PC_EVENT_VALID | 0, + "PC_Event2 @ " + loc + " (total range start)"); + addWrite(CM_PC_EVENT0 + 12, PC_EVENT_VALID | (PROG_MEM_END & PC_ADDRESS_MASK), + "PC_Event3 @ " + loc + " (total range end)"); + + // Reset performance counters 2 and 3. + addWrite(CM_PERF_COUNTER0 + 8, 0, "Reset PerfCounter2 @ " + loc); + addWrite(CM_PERF_COUNTER0 + 12, 0, "Reset PerfCounter3 @ " + loc); + + // Performance_Ctrl1: [6:0]=Cnt2_Start, [14:8]=Cnt2_Stop, [22:16]=Cnt3_Start, [30:24]=Cnt3_Stop + // Counter 2 = kernelWrapper, counter 3 = total. Counter 2 uses distinct Start(PC_0)/ + // Stop(PC_1) breakpoint events, i.e. a temporal window rather than a PC range, so the + // called kernel is counted even though it executes outside [start_pc, stop_pc]. + { + uint32_t regValue = 0; + regValue |= (static_cast(PC_0_EVENT) & 0x7F) << 0; + regValue |= (static_cast(PC_1_EVENT) & 0x7F) << 8; + regValue |= (static_cast(PC_RANGE_2_3_EVENT) & 0x7F) << 16; + regValue |= (static_cast(PC_RANGE_2_3_EVENT) & 0x7F) << 24; + addWrite(CM_PERF_CTRL1, regValue, + "PerfCtrl1 @ " + loc + + " (ctr2 start=PC_0 stop=PC_1 kernelWrapper, ctr3=PC_Range_2-3 total)"); } - return writeBandwidthCTFile(asmFileInfoList, allCounters, beginBlockWrites, outputPath); + return writes; } } // namespace xdp 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 d353b165..d31414e3 100644 --- a/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.h +++ b/profile/plugin/aie_dtrace/ve2/aie_dtrace_ct_writer.h @@ -92,6 +92,19 @@ struct BandwidthCounterConfig { std::string eventType; // "running" or "stalled" }; +/** + * @brief Resolved kernelWrapper PCs for the single core-tile compute_io_bound counter. + * + * Used identically for static and reloadable designs: the compute counter is driven + * by PC breakpoint events - Start=PC_0 at startPc (the indirect kernel dispatch), + * Stop=PC_1 at stopPc (the 10th listed instruction from it) - so it accumulates the + * whole dispatch window including the called kernel. + */ +struct ComputeIoCoreConfig { + uint32_t startPc = 0; // indirect kernel dispatch ("jl pN") + uint32_t stopPc = 0; // 10th listed instruction from the dispatch +}; + /** * @class AieDtraceCTWriter * @brief Generates CT (CERT Tracing) files for VE2 AIE profiling @@ -166,6 +179,33 @@ class AieDtraceCTWriter { const std::string& metricSet = "ddr_bandwidth", uint8_t channel = 0); + /** + * @brief Generate a self-contained CT file combining bandwidth and/or + * compute_io_bound metrics into a single begin block + counter reads. + * + * Either family can be enabled independently; when both are enabled the shim + * bandwidth counters and the core compute_io_bound counters are emitted into + * the same CT file. + * + * @param outputPath Full path for the generated CT file + * @param hwctx Hardware context handle for partition info access + * @param opLocations Vector of op_loc from aiebu_assembler::get_op_locations + * @param includeBandwidth Emit interface-tile bandwidth counters + * @param bandwidthMetricSet Bandwidth metric set (used when includeBandwidth) + * @param bandwidthChannel DMA channel for detailed_ddr_*_bandwidth sets + * @param includeComputeIoBound Emit the single core-tile compute_io_bound counters + * @param computeIoCfg Resolved compute_io_bound core configuration (used when includeComputeIoBound) + * @return true if CT file was generated successfully, false otherwise + */ + bool generateCT(const std::string& outputPath, + void* hwctx, + const std::vector& opLocations, + bool includeBandwidth, + const std::string& bandwidthMetricSet, + uint8_t bandwidthChannel, + bool includeComputeIoBound, + const ComputeIoCoreConfig& computeIoCfg); + private: /** * @brief Read ASM file information from CSV file @@ -290,17 +330,61 @@ class AieDtraceCTWriter { const std::string& metricSet = "ddr_bandwidth", uint8_t channel = 0); /** - * @brief Write the bandwidth CT file content with register configuration + * @brief Build the ASM file/timestamp info list from op_locations + * @param opLocations Vector of op_loc from aiebu_assembler::get_op_locations + * @return Vector of ASMFileInfo (UC spans applied); empty if none found + */ + std::vector buildAsmFileInfoList( + const std::vector& opLocations); + + /** + * @brief Append interface-tile bandwidth counters and begin-block writes + * @param hwctx Hardware context handle for shim column discovery + * @param metricSet Bandwidth metric set + * @param channel DMA channel for detailed_ddr_*_bandwidth sets + * @param counters [in,out] Accumulated counter list + * @param beginWrites [in,out] Accumulated begin-block register writes + * @return true if bandwidth config was appended + */ + bool appendBandwidthConfig(void* hwctx, const std::string& metricSet, uint8_t channel, + std::vector& counters, std::vector& beginWrites); + + /** + * @brief Append the single core-tile compute_io_bound counters and begin-block writes + * @param cfg Resolved compute_io_bound core configuration + * @param counters [in,out] Accumulated counter list + * @param beginWrites [in,out] Accumulated begin-block register writes + */ + void appendComputeIoBoundConfig(const ComputeIoCoreConfig& cfg, + std::vector& counters, std::vector& beginWrites); + + /** + * @brief Generate PC-event + performance counter config for a single core tile + * + * Programs PC_Event0-3 (with the Valid bit), resets performance counters 2/3, and + * configures Performance_Ctrl1 so counter 2 measures kernelWrapper (Start=PC_0 at + * startPc, Stop=PC_1 at stopPc) and counter 3 measures total (PC_Range_2-3 over + * [0, PROG_MEM_END]). + * + * @param column Partition-relative core tile column + * @param cfg Resolved kernelWrapper start/stop PCs + * @return Vector of register writes for the begin block + */ + std::vector generatePcStartStopCoreConfig(uint8_t column, + const ComputeIoCoreConfig& cfg); + + /** + * @brief Write a self-contained counter CT file with begin-block register writes * @param asmFileInfoList Vector of ASMFileInfo with timestamps * @param allCounters Vector of all CTCounterInfo for metadata * @param beginBlockWrites Vector of register writes for begin block * @param outputPath Full path for the output CT file * @return true if file was written successfully */ - bool writeBandwidthCTFile(const std::vector& asmFileInfoList, - const std::vector& allCounters, - const std::vector& beginBlockWrites, - const std::string& outputPath); + bool writeCounterCTFile(const std::vector& asmFileInfoList, + const std::vector& allCounters, + const std::vector& beginBlockWrites, + const std::string& outputPath); private: VPDatabase* db; @@ -310,6 +394,7 @@ class AieDtraceCTWriter { // AIE configuration values uint8_t columnShift; uint8_t rowShift; + uint8_t coreRowStart; // Absolute row of the first AIE core row (aie_tile_row_start) uint8_t partitionStartCol; // Absolute start column of the hw_context partition // Base offsets by module type @@ -322,6 +407,21 @@ class AieDtraceCTWriter { static constexpr uint64_t STREAM_SWITCH_EVENT_PORT_SEL_OFFSET = 0x0003FF00; static constexpr uint64_t PERF_CTRL_OFFSET = 0x00031000; + // Core (aie) module offsets for the compute_io_bound metric (aie2ps) + static constexpr uint64_t CM_PERF_CTRL1 = 0x00037504; // Counters 2,3 start/stop events + static constexpr uint64_t CM_PERF_COUNTER0 = 0x00037520; // Counter 0 (Counter N at +4*N) + static constexpr uint64_t CM_PC_EVENT0 = 0x00038020; // PC_Event0 (1..3 at +4 each) + static constexpr uint32_t PC_EVENT_VALID = 0x80000000; // PC_Event Valid bit (bit 31) + static constexpr uint32_t PC_ADDRESS_MASK = 0x00003FFF; // PC_Address field (bits 13:0) + static constexpr uint32_t PROG_MEM_END = 0x00003FFF; // End of 16KB program memory + static constexpr uint8_t PC_0_EVENT = 16; // XAIE2PS_EVENTS_CORE_PC_0 (breakpoint @ PC_Event0) + static constexpr uint8_t PC_1_EVENT = 17; // XAIE2PS_EVENTS_CORE_PC_1 (breakpoint @ PC_Event1) + static constexpr uint8_t PC_RANGE_2_3_EVENT = 21; // XAIE2PS_EVENTS_CORE_PC_RANGE_2_3 + + // compute_io_bound configures a single core tile: the first column / first core + // row. The absolute row comes from coreRowStart (driver_config.aie_tile_row_start). + static constexpr uint8_t COMPUTE_IO_CORE_COL = 0; + // Bandwidth monitoring constants static constexpr uint8_t NUM_BANDWIDTH_COUNTERS = 4; static constexpr uint8_t SHIM_ROW = 0; diff --git a/profile/plugin/aie_dtrace/ve2/aie_dtrace_ve2.cpp b/profile/plugin/aie_dtrace/ve2/aie_dtrace_ve2.cpp index cfab9211..0a36254e 100644 --- a/profile/plugin/aie_dtrace/ve2/aie_dtrace_ve2.cpp +++ b/profile/plugin/aie_dtrace/ve2/aie_dtrace_ve2.cpp @@ -15,14 +15,99 @@ #include "xdp/profile/database/static_info/aie_util.h" +#include #include #include +#include #include +#include namespace xdp { using severity_level = xrt_core::message::severity_level; static constexpr int SHIM_MODULE_IDX = static_cast(module_type::shim); + static constexpr int CORE_MODULE_IDX = static_cast(module_type::core); + + // Listing base name of the compute_io_bound core tile: first column, first core + // row. Listings/elfs_metadata use RELATIVE core rows, hence "_0". + static constexpr const char* COMPUTE_IO_TILE_BASE = "0_0"; + + // PC metadata produced on the host by "vaiprofile --gen-pc-metadata" and read from + // the run directory. Holds the compute_io_bound start/stop PCs so this plugin does + // not have to parse aiecompiler listings at run time. + static constexpr const char* PC_METADATA_FILENAME = "aie_pc_metadata.json"; + + // Read compute_io_bound start/stop PCs for 'tileBase' from the PC metadata JSON in + // the run directory. std::nullopt when the file is missing or lacks the tile entry. + static std::optional> + readComputeStartStopPc(const std::string& tileBase) + { + const std::string path = + (std::filesystem::current_path() / PC_METADATA_FILENAME).string(); + + std::error_code ec; + if (!std::filesystem::is_regular_file(path, ec)) { + xrt_core::message::send(severity_level::warning, "XRT", + "AIE dtrace: '" + std::string(PC_METADATA_FILENAME) + "' not found in the run " + "directory; generate it with 'vaiprofile --gen-pc-metadata ' and copy it " + "here. Skipping compute_io_bound."); + return std::nullopt; + } + + try { + boost::property_tree::ptree pt; + boost::property_tree::read_json(path, pt); + + auto tile = pt.get_child_optional("compute_io_bound." + tileBase); + if (!tile) { + xrt_core::message::send(severity_level::warning, "XRT", + "AIE dtrace: no 'compute_io_bound." + tileBase + "' entry in " + path + + "; skipping compute_io_bound."); + return std::nullopt; + } + + // The PCs are "0x"-prefixed hex strings, JSON having no hex number literal. + auto parsePc = [](const boost::optional& text) -> std::optional { + if (!text) + return std::nullopt; + try { + size_t end = 0; + const unsigned long value = std::stoul(*text, &end, 16); + if (end != text->size()) // trailing junk + return std::nullopt; + return static_cast(value); + } + catch (const std::exception&) { + return std::nullopt; + } + }; + + auto startPc = parsePc(tile->get_optional("start_pc")); + auto stopPc = parsePc(tile->get_optional("stop_pc")); + if (!startPc || !stopPc) { + xrt_core::message::send(severity_level::warning, "XRT", + "AIE dtrace: 'compute_io_bound." + tileBase + "' in " + path + + " has missing or malformed start_pc/stop_pc (expected hex strings such as " + "\"0x337e\"); skipping compute_io_bound."); + return std::nullopt; + } + + std::stringstream msg; + msg << "AIE dtrace: compute_io_bound PCs from " << path << " (design '" + << pt.get("design", "unknown") << "', " + << pt.get("design_type", "unknown") << "): start_pc=0x" + << std::hex << *startPc << " stop_pc=0x" << *stopPc << std::dec; + xrt_core::message::send(severity_level::info, "XRT", msg.str()); + + return std::make_pair(*startPc, *stopPc); + } + catch (const std::exception& e) { + xrt_core::message::send(severity_level::warning, "XRT", + "AIE dtrace: could not parse " + path + " (" + e.what() + + "); skipping compute_io_bound."); + return std::nullopt; + } + } AieDtrace_VE2Impl::AieDtrace_VE2Impl(VPDatabase* database, std::shared_ptr metadata, @@ -108,10 +193,41 @@ namespace xdp { AieDtraceCTWriter ctWriter(db, metadata, deviceID, partitionStartCol); + // Determine which metric families are configured for this run. Both the + // interface-tile bandwidth metrics and the core-tile compute_io_bound metric + // can be emitted into the same per-run CT file. + bool includeComputeIoBound = false; + for (const auto& tc : metadata->getConfigMetricsVec(CORE_MODULE_IDX)) { + if (tc.second == "compute_io_bound") { + includeComputeIoBound = true; + break; + } + } + + // Compute start/stop PCs come from the host-generated PC metadata JSON; resolve + // once per process since they are fixed for the loaded design. + ComputeIoCoreConfig computeIoCfg; + if (includeComputeIoBound) { + if (!m_computeIoPcsResolved) { + m_computeIoPcs = readComputeStartStopPc(COMPUTE_IO_TILE_BASE); + m_computeIoPcsResolved = true; + } + if (!m_computeIoPcs) { + includeComputeIoBound = false; + } + else { + computeIoCfg.startPc = m_computeIoPcs->first; + computeIoCfg.stopPc = m_computeIoPcs->second; + } + } + + // Interface-tile bandwidth metrics are configured by default unless the user + // turned interface tiles off (which leaves the shim config map empty). + auto shimConfigMetrics = metadata->getConfigMetricsVec(SHIM_MODULE_IDX); + bool includeBandwidth = !shimConfigMetrics.empty(); std::string bandwidthMetricSet = "peak_read_bandwidth"; uint8_t bandwidthChannel = 0; - auto shimConfigMetrics = metadata->getConfigMetricsVec(SHIM_MODULE_IDX); - if (!shimConfigMetrics.empty()) { + if (includeBandwidth) { bandwidthMetricSet = shimConfigMetrics.front().second; // The detailed_ddr_*_bandwidth metric sets carry a DMA channel in their // ":" suffix (stored in configChannel0). Match by column/row. @@ -124,19 +240,32 @@ namespace xdp { } } xrt_core::message::send(severity_level::info, "XRT", - "AIE dtrace: Using metric set '" + bandwidthMetricSet + "' (channel " + "AIE dtrace: Using interface tile metric set '" + bandwidthMetricSet + "' (channel " + std::to_string(bandwidthChannel) + ") from configuration"); - } else { + } + + if (!includeBandwidth && !includeComputeIoBound) { xrt_core::message::send(severity_level::info, "XRT", - "AIE dtrace: No interface tile metrics configured, using default 'peak_read_bandwidth'"); + "AIE dtrace: No metrics configured; skipping CT generation."); + return; } - if (!ctWriter.generateBandwidthCT(outputPath, hwctx, it->second, bandwidthMetricSet, bandwidthChannel)) + if (!ctWriter.generateCT(outputPath, hwctx, it->second, + includeBandwidth, bandwidthMetricSet, bandwidthChannel, + includeComputeIoBound, computeIoCfg)) return; - xrt_core::message::send(severity_level::debug, "XRT", - "AIE dtrace: Bandwidth CT generated for kernel '" + kernel_name - + "' with metric set '" + bandwidthMetricSet + "'"); + std::stringstream genMsg; + genMsg << "AIE dtrace: CT generated for kernel '" << kernel_name << "' ("; + if (includeBandwidth) + genMsg << "interface_tile=" << bandwidthMetricSet; + if (includeBandwidth && includeComputeIoBound) + genMsg << ", "; + if (includeComputeIoBound) + genMsg << "aie_tile=compute_io_bound start_pc=0x" << std::hex << computeIoCfg.startPc + << " stop_pc=0x" << computeIoCfg.stopPc << std::dec; + genMsg << ")"; + xrt_core::message::send(severity_level::debug, "XRT", genMsg.str()); auto* run_impl = static_cast(run_impl_ptr); try { diff --git a/profile/plugin/aie_dtrace/ve2/aie_dtrace_ve2.h b/profile/plugin/aie_dtrace/ve2/aie_dtrace_ve2.h index 3fa6926a..7434b84a 100644 --- a/profile/plugin/aie_dtrace/ve2/aie_dtrace_ve2.h +++ b/profile/plugin/aie_dtrace/ve2/aie_dtrace_ve2.h @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include #include "aiebu/aiebu_assembler.h" @@ -37,6 +39,10 @@ namespace xdp { void computeOpLocations(void* elf_handle, const std::string& kernel_name); std::map> m_op_locations_cache; + + // compute_io_bound start/stop PCs read once from the PC metadata JSON. + std::optional> m_computeIoPcs; + bool m_computeIoPcsResolved = false; }; }