20#include "mlir/Support/FileUtilities.h"
21#include "mlir/Support/LLVM.h"
22#include "llvm/ADT/DenseMapInfoVariant.h"
23#include "llvm/ADT/ScopeExit.h"
24#include "llvm/Support/Format.h"
25#include "llvm/Support/JSON.h"
26#include "llvm/Support/ToolOutputFile.h"
27#include "llvm/Support/raw_ostream.h"
30#define DEBUG_TYPE "synth-longest-path-analysis"
36#define GEN_PASS_DEF_PRINTLONGESTPATHANALYSIS
37#include "circt/Dialect/Synth/Transforms/SynthPasses.h.inc"
46struct PrintLongestPathAnalysisPass
47 :
public impl::PrintLongestPathAnalysisBase<PrintLongestPathAnalysisPass> {
48 void runOnOperation()
override;
49 using PrintLongestPathAnalysisBase::PrintLongestPathAnalysisBase;
53 llvm::json::OStream *jsonOS);
57 void printTimingLevelStatistics(SmallVectorImpl<DataflowPath> &allTimingPaths,
58 llvm::raw_ostream *os,
59 llvm::json::OStream *jsonOS);
62 void printTopKPathDetails(SmallVectorImpl<DataflowPath> &allTimingPaths,
64 llvm::json::OStream *jsonOS);
67 void printPathHistory(
const OpenPath &timingPath, llvm::raw_ostream &os);
73LogicalResult PrintLongestPathAnalysisPass::printAnalysisResult(
75 hw::HWModuleOp top, llvm::raw_ostream *os, llvm::json::OStream *jsonOS) {
76 auto moduleName = top.getModuleNameAttr();
81 if (failed(analysis.getAllPaths(moduleName, collection.paths,
true)))
86 for (
auto &result : collection.paths) {
87 auto endPointLoc = result.getEndPointLoc();
88 auto diag = mlir::emitRemark(endPointLoc);
90 llvm::raw_svector_ostream os(buf);
96 size_t oldPathCount = collection.paths.size();
97 collection.sortAndDropNonCriticalPathsPerEndPoint();
98 auto &longestPathForEachEndPoint = collection.paths;
102 *os <<
"# Longest Path Analysis result for " << top.getModuleNameAttr()
104 <<
"Found " << oldPathCount <<
" paths\n"
105 <<
"Found " << longestPathForEachEndPoint.size()
106 <<
" unique end points \n"
107 <<
"Maximum path delay: "
108 << (longestPathForEachEndPoint.empty()
110 : longestPathForEachEndPoint.front().getDelay())
113 *os <<
"## Showing Levels\n";
118 jsonOS->objectBegin();
119 jsonOS->attribute(
"module_name", top.getModuleNameAttr().getValue());
122 auto deferClose = llvm::make_scope_exit([&]() {
128 printTimingLevelStatistics(longestPathForEachEndPoint, os, jsonOS);
131 if (showTopKPercent.getValue() > 0)
132 printTopKPathDetails(longestPathForEachEndPoint, top, os, jsonOS);
142void PrintLongestPathAnalysisPass::printTimingLevelStatistics(
143 SmallVectorImpl<DataflowPath> &allTimingPaths, llvm::raw_ostream *os,
144 llvm::json::OStream *jsonOS) {
146 int64_t totalTimingPoints = allTimingPaths.size();
147 int64_t cumulativeCount = 0;
150 jsonOS->attributeBegin(
"timing_levels");
151 jsonOS->arrayBegin();
153 auto closeJson = llvm::make_scope_exit([&]() {
156 jsonOS->attributeEnd();
161 if (allTimingPaths.empty())
163 for (int64_t index = allTimingPaths.size() - 1; index >= 0;) {
164 int64_t oldIndex = index;
165 auto currentDelay = allTimingPaths[index--].getDelay();
168 while (index >= 0 && allTimingPaths[index].getDelay() == currentDelay)
171 int64_t pathsWithSameDelay = oldIndex - index;
173 cumulativeCount += pathsWithSameDelay;
176 double cumulativePercentage =
177 (double)cumulativeCount / totalTimingPoints * 100.0;
182 *os << llvm::format(
"Level = %-10d. Count = %-10d. %-10.2f%%\n",
183 currentDelay, pathsWithSameDelay,
184 cumulativePercentage);
186 jsonOS->objectBegin();
187 jsonOS->attribute(
"level", currentDelay);
188 jsonOS->attribute(
"count", pathsWithSameDelay);
189 jsonOS->attribute(
"percentage", cumulativePercentage);
198void PrintLongestPathAnalysisPass::printTopKPathDetails(
199 SmallVectorImpl<DataflowPath> &allTimingPaths,
hw::HWModuleOp top,
200 llvm::raw_ostream *os, llvm::json::OStream *jsonOS) {
202 auto topKCount =
static_cast<uint64_t
>(allTimingPaths.size()) *
203 std::clamp(showTopKPercent.getValue(), 0, 100) / 100;
206 *os <<
"## Top " << topKCount <<
" (out of " << allTimingPaths.size()
207 <<
") end points\n\n";
210 jsonOS->attributeBegin(
"top_paths");
211 jsonOS->arrayBegin();
213 auto closeJson = llvm::make_scope_exit([&]() {
216 jsonOS->attributeEnd();
222 for (
size_t i = 0; i < std::min<size_t>(topKCount, allTimingPaths.size());
224 auto &path = allTimingPaths[i];
226 jsonOS->value(
toJSON(path));
231 *os <<
"==============================================\n"
232 <<
"#" << i + 1 <<
": Distance=" << path.getDelay() <<
"\n";
236 path.printEndPoint(*os);
241 path.getStartPoint().print(*os);
245 printPathHistory(path.getPath(), *os);
254void PrintLongestPathAnalysisPass::printPathHistory(
const OpenPath &timingPath,
255 llvm::raw_ostream &os) {
256 int64_t remainingDelay = timingPath.getDelay();
258 if (!timingPath.getHistory().isEmpty()) {
259 os <<
"== History Start (closer to end point) ==\n";
262 for (
auto &debugPoint : timingPath.getHistory()) {
264 int64_t stepDelay = remainingDelay - debugPoint.delay;
265 remainingDelay = debugPoint.delay;
268 os <<
"<--- (logic delay " << stepDelay <<
") ---\n";
269 debugPoint.print(os);
273 os <<
"== History End (closer to start point) ==\n";
277void PrintLongestPathAnalysisPass::runOnOperation() {
278 auto am = getAnalysisManager();
281 LongestPathAnalysisOptions(
282 showTopKPercent.getValue() > 0,
285 !test, StringAttr::get(&getContext(), topModuleName.getValue())));
288 getAnalysis<circt::igraph::InstanceGraph>());
289 auto outputFileVal = outputFile.getValue();
292 auto file = mlir::openOutputFile(outputFile.getValue(), &error);
294 llvm::errs() <<
error;
295 return signalPassFailure();
298 auto &os = file->os();
299 std::unique_ptr<llvm::json::OStream> jsonOS;
300 if (emitJSON.getValue()) {
301 jsonOS = std::make_unique<llvm::json::OStream>(os);
302 jsonOS->arrayBegin();
305 auto closeJson = llvm::make_scope_exit([&]() {
310 for (
auto top : analysis.getTopModules())
311 if (failed(printAnalysisResult(analysis, pathCache, top,
312 jsonOS ? nullptr : &os, jsonOS.
get())))
313 return signalPassFailure();
315 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.