This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user