18#include "mlir/Support/FileUtilities.h"
19#include "mlir/Support/LLVM.h"
20#include "llvm/ADT/DenseMapInfoVariant.h"
21#include "llvm/ADT/ScopeExit.h"
22#include "llvm/Support/Format.h"
23#include "llvm/Support/JSON.h"
24#include "llvm/Support/ToolOutputFile.h"
25#include "llvm/Support/raw_ostream.h"
28#define DEBUG_TYPE "synth-longest-path-analysis"
34#define GEN_PASS_DEF_PRINTLONGESTPATHANALYSIS
35#include "circt/Dialect/Synth/Transforms/SynthPasses.h.inc"
44struct PrintLongestPathAnalysisPass
45 :
public impl::PrintLongestPathAnalysisBase<PrintLongestPathAnalysisPass> {
46 void runOnOperation()
override;
47 using PrintLongestPathAnalysisBase::PrintLongestPathAnalysisBase;
51 llvm::json::OStream *jsonOS);
55 void printTimingLevelStatistics(SmallVectorImpl<DataflowPath> &allTimingPaths,
56 llvm::raw_ostream *os,
57 llvm::json::OStream *jsonOS);
60 void printTopKPathDetails(SmallVectorImpl<DataflowPath> &allTimingPaths,
62 llvm::json::OStream *jsonOS);
65 void printPathHistory(
const OpenPath &timingPath, llvm::raw_ostream &os);
71LogicalResult PrintLongestPathAnalysisPass::printAnalysisResult(
73 hw::HWModuleOp top, llvm::raw_ostream *os, llvm::json::OStream *jsonOS) {
74 auto moduleName = top.getModuleNameAttr();
79 if (failed(analysis.getAllPaths(moduleName, collection.paths,
true)))
84 for (
auto &result : collection.paths) {
85 auto fanOutLoc = result.getFanOutLoc();
86 auto diag = mlir::emitRemark(fanOutLoc);
88 llvm::raw_svector_ostream os(buf);
94 size_t oldPathCount = collection.paths.size();
95 collection.sortAndDropNonCriticalPathsPerFanOut();
96 auto &longestPathForEachFanOut = collection.paths;
100 *os <<
"# Longest Path Analysis result for " << top.getModuleNameAttr()
102 <<
"Found " << oldPathCount <<
" paths\n"
103 <<
"Found " << longestPathForEachFanOut.size()
104 <<
" unique fanout points\n"
105 <<
"Maximum path delay: "
106 << (longestPathForEachFanOut.empty()
108 : longestPathForEachFanOut.front().getDelay())
111 *os <<
"## Showing Levels\n";
116 jsonOS->objectBegin();
117 jsonOS->attribute(
"module_name", top.getModuleNameAttr().getValue());
120 auto deferClose = llvm::make_scope_exit([&]() {
126 printTimingLevelStatistics(longestPathForEachFanOut, os, jsonOS);
129 if (showTopKPercent.getValue() > 0)
130 printTopKPathDetails(longestPathForEachFanOut, top, os, jsonOS);
140void PrintLongestPathAnalysisPass::printTimingLevelStatistics(
141 SmallVectorImpl<DataflowPath> &allTimingPaths, llvm::raw_ostream *os,
142 llvm::json::OStream *jsonOS) {
144 int64_t totalTimingPoints = allTimingPaths.size();
145 int64_t cumulativeCount = 0;
148 jsonOS->attributeBegin(
"timing_levels");
149 jsonOS->arrayBegin();
151 auto closeJson = llvm::make_scope_exit([&]() {
154 jsonOS->attributeEnd();
159 if (allTimingPaths.empty())
161 for (int64_t index = allTimingPaths.size() - 1; index >= 0;) {
162 int64_t oldIndex = index;
163 auto currentDelay = allTimingPaths[index--].getDelay();
166 while (index >= 0 && allTimingPaths[index].getDelay() == currentDelay)
169 int64_t pathsWithSameDelay = oldIndex - index;
171 cumulativeCount += pathsWithSameDelay;
174 double cumulativePercentage =
175 (double)cumulativeCount / totalTimingPoints * 100.0;
180 *os << llvm::format(
"Level = %-10d. Count = %-10d. %-10.2f%%\n",
181 currentDelay, pathsWithSameDelay,
182 cumulativePercentage);
184 jsonOS->objectBegin();
185 jsonOS->attribute(
"level", currentDelay);
186 jsonOS->attribute(
"count", pathsWithSameDelay);
187 jsonOS->attribute(
"percentage", cumulativePercentage);
196void PrintLongestPathAnalysisPass::printTopKPathDetails(
197 SmallVectorImpl<DataflowPath> &allTimingPaths,
hw::HWModuleOp top,
198 llvm::raw_ostream *os, llvm::json::OStream *jsonOS) {
200 auto topKCount =
static_cast<uint64_t
>(allTimingPaths.size()) *
201 std::clamp(showTopKPercent.getValue(), 0, 100) / 100;
204 *os <<
"## Top " << topKCount <<
" (out of " << allTimingPaths.size()
205 <<
") fan-out points\n\n";
208 jsonOS->attributeBegin(
"top_paths");
209 jsonOS->arrayBegin();
211 auto closeJson = llvm::make_scope_exit([&]() {
214 jsonOS->attributeEnd();
220 for (
size_t i = 0; i < std::min<size_t>(topKCount, allTimingPaths.size());
222 auto &path = allTimingPaths[i];
224 jsonOS->value(
toJSON(path));
229 *os <<
"==============================================\n"
230 <<
"#" << i + 1 <<
": Distance=" << path.getDelay() <<
"\n";
234 path.printFanOut(*os);
239 path.getFanIn().print(*os);
243 printPathHistory(path.getPath(), *os);
252void PrintLongestPathAnalysisPass::printPathHistory(
const OpenPath &timingPath,
253 llvm::raw_ostream &os) {
254 int64_t remainingDelay = timingPath.getDelay();
256 if (!timingPath.getHistory().isEmpty()) {
257 os <<
"== History Start (closer to fanout) ==\n";
260 for (
auto &debugPoint : timingPath.getHistory()) {
262 int64_t stepDelay = remainingDelay - debugPoint.delay;
263 remainingDelay = debugPoint.delay;
266 os <<
"<--- (logic delay " << stepDelay <<
") ---\n";
267 debugPoint.print(os);
271 os <<
"== History End (closer to fanin) ==\n";
275void PrintLongestPathAnalysisPass::runOnOperation() {
276 auto am = getAnalysisManager();
279 LongestPathAnalysisOptions(
280 showTopKPercent.getValue() > 0,
286 getAnalysis<circt::igraph::InstanceGraph>());
287 auto outputFileVal = outputFile.getValue();
290 auto file = mlir::openOutputFile(outputFile.getValue(), &error);
292 llvm::errs() <<
error;
293 return signalPassFailure();
296 auto &os = file->os();
297 std::unique_ptr<llvm::json::OStream> jsonOS;
298 if (emitJSON.getValue()) {
299 jsonOS = std::make_unique<llvm::json::OStream>(os);
300 jsonOS->arrayBegin();
303 auto closeJson = llvm::make_scope_exit([&]() {
308 for (
auto top : analysis.getTopModules())
309 if (failed(printAnalysisResult(analysis, pathCache, top,
310 jsonOS ? nullptr : &os, jsonOS.
get())))
311 return signalPassFailure();
313 return markAllAnalysesPreserved();
static llvm::json::Value toJSON(const circt::igraph::InstancePath &path)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
void error(Twine message)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
A data structure that caches and provides paths to module instances in the IR.