From 0aa3840a724fb84c557ca2de309201d2c2a8d038 Mon Sep 17 00:00:00 2001 From: ilgeco Date: Mon, 3 Aug 2026 12:05:03 +0200 Subject: [PATCH] Conv lowering report --- src/PIM/Compiler/PimCompilerOptions.cpp | 5 + src/PIM/Compiler/PimCompilerOptions.hpp | 1 + .../ONNXToSpatial/Patterns/Math/Conv.cpp | 202 +++++++++++++++++- 3 files changed, 204 insertions(+), 4 deletions(-) diff --git a/src/PIM/Compiler/PimCompilerOptions.cpp b/src/PIM/Compiler/PimCompilerOptions.cpp index cd22550..dfa5e6c 100644 --- a/src/PIM/Compiler/PimCompilerOptions.cpp +++ b/src/PIM/Compiler/PimCompilerOptions.cpp @@ -87,6 +87,11 @@ llvm::cl::opt pimConvStreamChunkPositions( llvm::cl::init(1024), llvm::cl::cat(OnnxMlirOptions)); +llvm::cl::opt pimReportConvLowering("pim-report-conv-lowering", + llvm::cl::desc("Emit a bounded Conv lowering report"), + llvm::cl::init(true), + llvm::cl::cat(OnnxMlirOptions)); + llvm::cl::opt pimEmitJson("pim-emit-json", llvm::cl::desc("Also emit per-core JSON instruction files alongside binary .pim files"), llvm::cl::init(false), diff --git a/src/PIM/Compiler/PimCompilerOptions.hpp b/src/PIM/Compiler/PimCompilerOptions.hpp index 84cf80f..00c2472 100644 --- a/src/PIM/Compiler/PimCompilerOptions.hpp +++ b/src/PIM/Compiler/PimCompilerOptions.hpp @@ -57,6 +57,7 @@ extern llvm::cl::opt pimExportSpatialDataflow; extern llvm::cl::opt pimOnlyCodegen; extern llvm::cl::opt useExperimentalConvImpl; extern llvm::cl::opt pimEmitJson; +extern llvm::cl::opt pimReportConvLowering; extern llvm::cl::opt pimDetectCommunicationDeadlock; extern llvm::cl::opt pimMaterializeScalarFanoutGlobalOrder; extern llvm::cl::opt pimTraceCommunicationMaterialization; diff --git a/src/PIM/Conversion/ONNXToSpatial/Patterns/Math/Conv.cpp b/src/PIM/Conversion/ONNXToSpatial/Patterns/Math/Conv.cpp index 292ecdf..78ec80d 100644 --- a/src/PIM/Conversion/ONNXToSpatial/Patterns/Math/Conv.cpp +++ b/src/PIM/Conversion/ONNXToSpatial/Patterns/Math/Conv.cpp @@ -5,15 +5,22 @@ #include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/BuiltinTypes.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/raw_ostream.h" #include +#include #include +#include #include "src/Accelerators/PIM/Common/IR/AffineUtils.hpp" #include "src/Accelerators/PIM/Common/IR/LoopUtils.hpp" #include "src/Accelerators/PIM/Common/IR/TensorSliceUtils.hpp" #include "src/Accelerators/PIM/Common/Support/Diagnostics.hpp" +#include "src/Accelerators/PIM/Common/Support/ReportUtils.hpp" +#include "src/Accelerators/PIM/Compiler/PimCompilerOptions.hpp" #include "src/Accelerators/PIM/Conversion/ONNXToSpatial/Common/BiasAddUtils.hpp" #include "src/Accelerators/PIM/Conversion/ONNXToSpatial/Common/Common.hpp" #include "src/Accelerators/PIM/Conversion/ONNXToSpatial/Common/MatrixProductLowering.hpp" @@ -62,6 +69,181 @@ static StringRef stringifyConvLoweringStrategy(spatial::ConvLoweringStrategy str llvm_unreachable("unknown conv lowering strategy"); } +enum class ConvLoweringReportPhase { Planning, Realization }; + +struct ConvLoweringReportEntry { + size_t convId; + std::string phase; + std::string location; + std::string strategy; + std::string implementation; +}; + +struct ConvLoweringReportState { + std::mutex mutex; + llvm::SmallPtrSet planned; + llvm::SmallPtrSet realized; + llvm::DenseMap convIds; + llvm::SmallVector entries; + size_t nextConvId = 1; +}; + +static StringRef stringifyConvLoweringReportPhase(ConvLoweringReportPhase phase) { + return phase == ConvLoweringReportPhase::Planning ? "planning" : "realization"; +} + +static std::string convReportLocation(Operation* op) { + std::string location; + llvm::raw_string_ostream stream(location); + op->getLoc().print(stream); + if (location.size() > 120) + location.replace(117, std::string::npos, "..."); + return location; +} + +static StringRef convLoweringImplementation(spatial::ConvLoweringStrategy strategy) { + switch (strategy) { + case spatial::ConvLoweringStrategy::Depthwise: + return "DW"; + case spatial::ConvLoweringStrategy::Legacy: + case spatial::ConvLoweringStrategy::PackedIm2Col: + return "PIC"; + case spatial::ConvLoweringStrategy::StreamedPatch: + case spatial::ConvLoweringStrategy::OutputChannelTiled: + case spatial::ConvLoweringStrategy::Tiled2D: + return "STR"; + case spatial::ConvLoweringStrategy::InputKTiled: + return "IKT"; + case spatial::ConvLoweringStrategy::StreamedPacked: + return "STP"; + case spatial::ConvLoweringStrategy::Auto: + return "AUTO"; + } + llvm_unreachable("unknown conv lowering implementation"); +} + +static StringRef convRowStripInputImplementation(const ConvLoweringState& state, + spatial::ConvLoweringStrategy strategy) { + if (strategy == spatial::ConvLoweringStrategy::Depthwise) + return "RSDW"; + if (state.xHeight == 1 && state.xWidth == 1 && state.wHeight == 1 && state.wWidth == 1) + return "RSP"; + return "RSM"; +} + +static constexpr size_t kConvReportIdWidth = 4; +static constexpr size_t kConvReportLocationWidth = 24; +static constexpr size_t kConvReportStrategyWidth = 20; +static constexpr size_t kConvReportCodeWidth = 8; + +static std::string convReportCell(StringRef value, size_t width) { + std::string cell = value.str(); + if (cell.size() > width) { + cell = width <= 3 ? std::string(width, '.') : cell.substr(0, width - 3) + "..."; + } + cell.append(width - cell.size(), ' '); + return cell; +} + +static void writeConvReportTableHeader(std::fstream& reportFile, StringRef fourthColumn) { + reportFile << "+------+--------------------------+----------------------+----------+\n"; + reportFile << "| " << convReportCell("Conv", kConvReportIdWidth) << " | " + << convReportCell("Location", kConvReportLocationWidth) << " | " + << convReportCell("Strategy", kConvReportStrategyWidth) << " | " + << convReportCell(fourthColumn, kConvReportCodeWidth) << " |\n"; + reportFile << "+------+--------------------------+----------------------+----------+\n"; +} + +static void writeConvReportRow(std::fstream& reportFile, + const ConvLoweringReportEntry& entry) { + reportFile << "| " << convReportCell(std::to_string(entry.convId), kConvReportIdWidth) << " | " + << convReportCell(entry.location, kConvReportLocationWidth) << " | " + << convReportCell(entry.strategy, kConvReportStrategyWidth) << " | " + << convReportCell(entry.implementation, kConvReportCodeWidth) << " |\n"; +} + +static void writeConvReportLegend(std::fstream& reportFile) { + reportFile << "Legend: Conv is shared by both sections; codes expand to:\n"; + reportFile << " SEL selectConvLoweringPlan\n"; + reportFile << " DW depthwise::rewriteConv\n"; + reportFile << " PIC standard::rewritePackedIm2ColConv\n"; + reportFile << " STR standard::rewriteStreamedConv(pack=1)\n"; + reportFile << " IKT standard::rewriteInputKTiledConv\n"; + reportFile << " STP standard::rewriteStreamedConv(pack=geo.pack)\n"; + reportFile << " AUTO unresolved strategy\n"; + reportFile << " RSD createRowStripConvOutputFromDenseInput -> createRowStripConvOutput\n"; + reportFile << " RSDW createConvOutputFromRowStripInput -> createDepthwiseOutputFromRowStripFragments\n"; + reportFile << " RSP createConvOutputFromRowStripInput -> createPointwiseOutputFromRowStripFragments\n"; + reportFile << " RSM createConvOutputFromRowStripInput -> createConvOutputFromPixelMajorRowStripFragments\n\n"; +} + +static bool writeConvLoweringReport(const ConvLoweringReportEntry& entry, + ConvLoweringReportState& state) { + state.entries.push_back(entry); + std::fstream reportFile = openReportFile("conv_lowering_report"); + if (!reportFile.is_open()) { + state.entries.pop_back(); + return false; + } + + reportFile << "# PIM Conv Lowering Report (bounded to 512 rows)\n\n"; + reportFile << "## Plan selection\n"; + writeConvReportTableHeader(reportFile, "Selector"); + bool realizationSectionStarted = false; + for (const ConvLoweringReportEntry& reportEntry : state.entries) { + if (reportEntry.phase == "realization" && !realizationSectionStarted) { + reportFile << "\n## Realization\n"; + writeConvReportTableHeader(reportFile, "Code"); + realizationSectionStarted = true; + } + writeConvReportRow(reportFile, reportEntry); + } + reportFile << "\n"; + writeConvReportLegend(reportFile); + if (!reportFile.good()) { + state.entries.pop_back(); + return false; + } + return true; +} + +static void recordConvLoweringReport(Operation* op, + ConvLoweringReportPhase phase, + spatial::ConvLoweringStrategy strategy, + StringRef implementation) { + if (!pimReportConvLowering) + return; + + static ConvLoweringReportState state; + std::lock_guard lock(state.mutex); + if (state.entries.size() >= 512) + return; + if (phase == ConvLoweringReportPhase::Planning) { + if (state.planned.contains(op)) + return; + } + else { + if (state.realized.contains(op)) + return; + } + size_t convId = state.convIds.lookup(op); + if (!convId) { + convId = state.nextConvId++; + state.convIds[op] = convId; + } + ConvLoweringReportEntry entry {convId, + stringifyConvLoweringReportPhase(phase).str(), + convReportLocation(op), + stringifyConvLoweringStrategy(strategy).str(), + implementation.str()}; + if (!writeConvLoweringReport(entry, state)) + return; + if (phase == ConvLoweringReportPhase::Planning) + state.planned.insert(op); + else + state.realized.insert(op); +} + static Value expandBiasIfNeeded(Value bias, PatternRewriter& rewriter, Location loc) { auto biasType = cast(bias.getType()); if (biasType.getRank() != 1) @@ -3143,7 +3325,7 @@ resolveRequestedConvLoweringStrategy(Operation* op, const spatial::SpatialTarget } static FailureOr selectConvLoweringPlan( - Operation* op, const ConvLoweringState& state) { + Operation* op, const ConvLoweringState& state, bool reportPlanning) { FailureOr requested = resolveRequestedConvLoweringStrategy(op, state.targetInfo()); if (failed(requested)) @@ -3155,6 +3337,8 @@ static FailureOr selectConvLoweringPlan( && !depthwise::canUseStructuredRewrite(state)) { continue; } + if (reportPlanning) + recordConvLoweringReport(op, ConvLoweringReportPhase::Planning, candidate.strategy, "SEL"); return candidate; } op->emitOpError("has no applicable Conv lowering candidate for the injected Spatial target"); @@ -3168,6 +3352,8 @@ static FailureOr selectConvLoweringPlan( << "` is not applicable to this Conv problem"; return failure(); } + if (reportPlanning) + recordConvLoweringReport(op, ConvLoweringReportPhase::Planning, candidate->strategy, "SEL"); return *candidate; } @@ -3383,7 +3569,7 @@ LogicalResult canLowerConvPlanToRowStrip(spatial::SpatConv2DPlanOp planOp, if (!rowStripOutputChannelTileFitsOneCore(geometry)) return failure(); FailureOr plan = - selectConvLoweringPlan(planOp.getOperation(), *state); + selectConvLoweringPlan(planOp.getOperation(), *state, /*reportPlanning=*/true); if (failed(plan)) return failure(); @@ -3410,7 +3596,7 @@ LogicalResult canConsumeAndProduceRowStrip(spatial::SpatConv2DPlanOp planOp, return failure(); FailureOr plan = - selectConvLoweringPlan(planOp.getOperation(), *state); + selectConvLoweringPlan(planOp.getOperation(), *state, /*reportPlanning=*/true); if (failed(plan)) return failure(); if (plan->strategy == spatial::ConvLoweringStrategy::Depthwise) @@ -3430,25 +3616,33 @@ lowerSelectedConv2DPlan(spatial::SpatConv2DPlanOp planOp, return failure(); FailureOr plan = - selectConvLoweringPlan(planOp.getOperation(), *state); + selectConvLoweringPlan(planOp.getOperation(), *state, /*reportPlanning=*/false); if (failed(plan)) return failure(); + auto reportRealization = [&](StringRef implementation) { + recordConvLoweringReport( + planOp.getOperation(), ConvLoweringReportPhase::Realization, plan->strategy, implementation); + }; + if (emitRowStripLayout) { if (rowStripInput) { if (failed(canConsumeAndProduceRowStrip(planOp, target))) return planOp.emitOpError("selected row-strip input/output layout is not supported for this Conv plan"), failure(); + reportRealization(convRowStripInputImplementation(*state, plan->strategy)); return createConvOutputFromRowStripInput( *state, *rowStripInput, plan->strategy, rewriter, planOp.getLoc()); } if (failed(canLowerConvPlanToRowStrip(planOp, target))) return planOp.emitOpError("selected row-strip layout is not supported for this Conv plan"), failure(); + reportRealization("RSD"); FailureOr rowStripStorage = createRowStripConvOutputFromDenseInput(*state, rewriter, planOp.getLoc()); if (failed(rowStripStorage)) return planOp.emitOpError("failed to build row-strip fragment storage for the selected Conv plan"), failure(); return *rowStripStorage; } + reportRealization(convLoweringImplementation(plan->strategy)); if (plan->strategy == spatial::ConvLoweringStrategy::Depthwise) return lowerDenseSelectedConvPlan(planOp.getOperation(), *state, plan->strategy, rewriter, planOp.getLoc()); if (state->group != 1)