Conv lowering report
Validate Operations / validate-operations (push) Waiting to run

This commit is contained in:
ilgeco
2026-08-03 12:05:03 +02:00
parent 942a9faa4f
commit 0aa3840a72
3 changed files with 204 additions and 4 deletions
+5
View File
@@ -87,6 +87,11 @@ llvm::cl::opt<uint64_t> pimConvStreamChunkPositions(
llvm::cl::init(1024),
llvm::cl::cat(OnnxMlirOptions));
llvm::cl::opt<bool> 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<bool> pimEmitJson("pim-emit-json",
llvm::cl::desc("Also emit per-core JSON instruction files alongside binary .pim files"),
llvm::cl::init(false),
+1
View File
@@ -57,6 +57,7 @@ extern llvm::cl::opt<PimSpatialDataflowExportType> pimExportSpatialDataflow;
extern llvm::cl::opt<bool> pimOnlyCodegen;
extern llvm::cl::opt<bool> useExperimentalConvImpl;
extern llvm::cl::opt<bool> pimEmitJson;
extern llvm::cl::opt<bool> pimReportConvLowering;
extern llvm::cl::opt<bool> pimDetectCommunicationDeadlock;
extern llvm::cl::opt<bool> pimMaterializeScalarFanoutGlobalOrder;
extern llvm::cl::opt<bool> pimTraceCommunicationMaterialization;
@@ -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 <algorithm>
#include <mutex>
#include <optional>
#include <string>
#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<Operation*, 32> planned;
llvm::SmallPtrSet<Operation*, 32> realized;
llvm::DenseMap<Operation*, size_t> convIds;
llvm::SmallVector<ConvLoweringReportEntry, 256> 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<std::mutex> 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<RankedTensorType>(bias.getType());
if (biasType.getRank() != 1)
@@ -3143,7 +3325,7 @@ resolveRequestedConvLoweringStrategy(Operation* op, const spatial::SpatialTarget
}
static FailureOr<ConvPlan> selectConvLoweringPlan(
Operation* op, const ConvLoweringState& state) {
Operation* op, const ConvLoweringState& state, bool reportPlanning) {
FailureOr<spatial::ConvLoweringStrategy> requested =
resolveRequestedConvLoweringStrategy(op, state.targetInfo());
if (failed(requested))
@@ -3155,6 +3337,8 @@ static FailureOr<ConvPlan> 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<ConvPlan> 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<ConvPlan> 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<ConvPlan> 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<ConvPlan> 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<Value> 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)