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.sortInDescendingOrder();
98 collection.dropNonCriticalPaths(
true);
99 auto &longestPathForEachEndPoint = collection.paths;
103 *os <<
"# Longest Path Analysis result for " << top.getModuleNameAttr()
105 <<
"Found " << oldPathCount <<
" paths\n"
106 <<
"Found " << longestPathForEachEndPoint.size()
107 <<
" unique end points \n"
108 <<
"Maximum path delay: "
109 << (longestPathForEachEndPoint.empty()
111 : longestPathForEachEndPoint.front().getDelay())
114 *os <<
"## Showing Levels\n";
119 jsonOS->objectBegin();
120 jsonOS->attribute(
"module_name", top.getModuleNameAttr().getValue());
123 auto deferClose = llvm::make_scope_exit([&]() {
129 printTimingLevelStatistics(longestPathForEachEndPoint, os, jsonOS);
132 if (showTopKPercent.getValue() > 0)
133 printTopKPathDetails(longestPathForEachEndPoint, top, os, jsonOS);
143void PrintLongestPathAnalysisPass::printTimingLevelStatistics(
144 SmallVectorImpl<DataflowPath> &allTimingPaths, llvm::raw_ostream *os,
145 llvm::json::OStream *jsonOS) {
147 int64_t totalTimingPoints = allTimingPaths.size();
148 int64_t cumulativeCount = 0;
151 jsonOS->attributeBegin(
"timing_levels");
152 jsonOS->arrayBegin();
154 auto closeJson = llvm::make_scope_exit([&]() {
157 jsonOS->attributeEnd();
162 if (allTimingPaths.empty())
164 for (int64_t index = allTimingPaths.size() - 1; index >= 0;) {
165 int64_t oldIndex = index;
166 auto currentDelay = allTimingPaths[index--].getDelay();
169 while (index >= 0 && allTimingPaths[index].getDelay() == currentDelay)
172 int64_t pathsWithSameDelay = oldIndex - index;
174 cumulativeCount += pathsWithSameDelay;
177 double cumulativePercentage =
178 (double)cumulativeCount / totalTimingPoints * 100.0;
183 *os << llvm::format(
"Level = %-10d. Count = %-10d. %-10.2f%%\n",
184 currentDelay, pathsWithSameDelay,
185 cumulativePercentage);
187 jsonOS->objectBegin();
188 jsonOS->attribute(
"level", currentDelay);
189 jsonOS->attribute(
"count", pathsWithSameDelay);
190 jsonOS->attribute(
"percentage", cumulativePercentage);
199void PrintLongestPathAnalysisPass::printTopKPathDetails(
200 SmallVectorImpl<DataflowPath> &allTimingPaths,
hw::HWModuleOp top,
201 llvm::raw_ostream *os, llvm::json::OStream *jsonOS) {
203 auto topKCount =
static_cast<uint64_t
>(allTimingPaths.size()) *
204 std::clamp(showTopKPercent.getValue(), 0, 100) / 100;
207 *os <<
"## Top " << topKCount <<
" (out of " << allTimingPaths.size()
208 <<
") end points\n\n";
211 jsonOS->attributeBegin(
"top_paths");
212 jsonOS->arrayBegin();
214 auto closeJson = llvm::make_scope_exit([&]() {
217 jsonOS->attributeEnd();
223 for (
size_t i = 0; i < std::min<size_t>(topKCount, allTimingPaths.size());
225 auto &path = allTimingPaths[i];
227 jsonOS->value(
toJSON(path));
232 *os <<
"==============================================\n"
233 <<
"#" << i + 1 <<
": Distance=" << path.getDelay() <<
"\n";
237 path.printEndPoint(*os);
242 path.getStartPoint().print(*os);
246 printPathHistory(path.getPath(), *os);
255void PrintLongestPathAnalysisPass::printPathHistory(
const OpenPath &timingPath,
256 llvm::raw_ostream &os) {
257 int64_t remainingDelay = timingPath.getDelay();
259 if (!timingPath.getHistory().isEmpty()) {
260 os <<
"== History Start (closer to end point) ==\n";
263 for (
auto &debugPoint : timingPath.getHistory()) {
265 int64_t stepDelay = remainingDelay - debugPoint.delay;
266 remainingDelay = debugPoint.delay;
269 os <<
"<--- (logic delay " << stepDelay <<
") ---\n";
270 debugPoint.print(os);
274 os <<
"== History End (closer to start point) ==\n";
278void PrintLongestPathAnalysisPass::runOnOperation() {
279 auto am = getAnalysisManager();
282 LongestPathAnalysisOptions(
283 showTopKPercent.getValue() > 0,
286 !test, StringAttr::get(&getContext(), topModuleName.getValue())));
289 getAnalysis<circt::igraph::InstanceGraph>());
290 auto outputFileVal = outputFile.getValue();
293 auto file = mlir::openOutputFile(outputFile.getValue(), &error);
295 llvm::errs() <<
error;
296 return signalPassFailure();
299 auto &os = file->os();
300 std::unique_ptr<llvm::json::OStream> jsonOS;
301 if (emitJSON.getValue()) {
302 jsonOS = std::make_unique<llvm::json::OStream>(os);
303 jsonOS->arrayBegin();
306 auto closeJson = llvm::make_scope_exit([&]() {
311 for (
auto top : analysis.getTopModules())
312 if (failed(printAnalysisResult(analysis, pathCache, top,
313 jsonOS ? nullptr : &os, jsonOS.
get())))
314 return signalPassFailure();
316 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.