1 //===--------------------- ResourcePressureView.cpp -------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// This file implements methods in the ResourcePressureView interface.
12 //===----------------------------------------------------------------------===//
14 #include "Views/ResourcePressureView.h"
15 #include "llvm/Support/FormattedStream.h"
16 #include "llvm/Support/raw_ostream.h"
21 ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo
&sti
,
22 MCInstPrinter
&Printer
,
24 : InstructionView(sti
, Printer
, S
), LastInstructionIdx(0) {
25 // Populate the map of resource descriptors.
26 unsigned R2VIndex
= 0;
27 const MCSchedModel
&SM
= getSubTargetInfo().getSchedModel();
28 for (unsigned I
= 0, E
= SM
.getNumProcResourceKinds(); I
< E
; ++I
) {
29 const MCProcResourceDesc
&ProcResource
= *SM
.getProcResource(I
);
30 unsigned NumUnits
= ProcResource
.NumUnits
;
31 // Skip groups and invalid resources with zero units.
32 if (ProcResource
.SubUnitsIdxBegin
|| !NumUnits
)
35 Resource2VecIndex
.insert(std::pair
<unsigned, unsigned>(I
, R2VIndex
));
36 R2VIndex
+= ProcResource
.NumUnits
;
39 NumResourceUnits
= R2VIndex
;
40 ResourceUsage
.resize(NumResourceUnits
* (getSource().size() + 1));
41 std::fill(ResourceUsage
.begin(), ResourceUsage
.end(), 0.0);
44 void ResourcePressureView::onEvent(const HWInstructionEvent
&Event
) {
45 if (Event
.Type
== HWInstructionEvent::Dispatched
) {
46 LastInstructionIdx
= Event
.IR
.getSourceIndex();
50 // We're only interested in Issue events.
51 if (Event
.Type
!= HWInstructionEvent::Issued
)
54 const auto &IssueEvent
= static_cast<const HWInstructionIssuedEvent
&>(Event
);
55 ArrayRef
<llvm::MCInst
> Source
= getSource();
56 const unsigned SourceIdx
= Event
.IR
.getSourceIndex() % Source
.size();
57 for (const std::pair
<ResourceRef
, ReleaseAtCycles
> &Use
:
58 IssueEvent
.UsedResources
) {
59 const ResourceRef
&RR
= Use
.first
;
60 assert(Resource2VecIndex
.contains(RR
.first
));
61 unsigned R2VIndex
= Resource2VecIndex
[RR
.first
];
62 R2VIndex
+= llvm::countr_zero(RR
.second
);
63 ResourceUsage
[R2VIndex
+ NumResourceUnits
* SourceIdx
] += Use
.second
;
64 ResourceUsage
[R2VIndex
+ NumResourceUnits
* Source
.size()] += Use
.second
;
68 static void printColumnNames(formatted_raw_ostream
&OS
,
69 const MCSchedModel
&SM
) {
70 unsigned Column
= OS
.getColumn();
71 for (unsigned I
= 1, ResourceIndex
= 0, E
= SM
.getNumProcResourceKinds();
73 const MCProcResourceDesc
&ProcResource
= *SM
.getProcResource(I
);
74 unsigned NumUnits
= ProcResource
.NumUnits
;
75 // Skip groups and invalid resources with zero units.
76 if (ProcResource
.SubUnitsIdxBegin
|| !NumUnits
)
79 for (unsigned J
= 0; J
< NumUnits
; ++J
) {
81 OS
<< "[" << ResourceIndex
;
85 OS
.PadToColumn(Column
);
92 static void printResourcePressure(formatted_raw_ostream
&OS
, double Pressure
,
94 if (!Pressure
|| Pressure
< 0.005) {
97 // Round to the value to the nearest hundredth and then print it.
98 OS
<< format("%.2f", floor((Pressure
* 100) + 0.5) / 100);
103 void ResourcePressureView::printResourcePressurePerIter(raw_ostream
&OS
) const {
105 raw_string_ostream
TempStream(Buffer
);
106 formatted_raw_ostream
FOS(TempStream
);
108 FOS
<< "\n\nResources:\n";
109 const MCSchedModel
&SM
= getSubTargetInfo().getSchedModel();
110 for (unsigned I
= 1, ResourceIndex
= 0, E
= SM
.getNumProcResourceKinds();
112 const MCProcResourceDesc
&ProcResource
= *SM
.getProcResource(I
);
113 unsigned NumUnits
= ProcResource
.NumUnits
;
114 // Skip groups and invalid resources with zero units.
115 if (ProcResource
.SubUnitsIdxBegin
|| !NumUnits
)
118 for (unsigned J
= 0; J
< NumUnits
; ++J
) {
119 FOS
<< '[' << ResourceIndex
;
124 FOS
<< "- " << ProcResource
.Name
<< '\n';
130 FOS
<< "\n\nResource pressure per iteration:\n";
132 printColumnNames(FOS
, SM
);
136 ArrayRef
<llvm::MCInst
> Source
= getSource();
137 const unsigned Executions
= LastInstructionIdx
/ Source
.size() + 1;
138 for (unsigned I
= 0, E
= NumResourceUnits
; I
< E
; ++I
) {
139 double Usage
= ResourceUsage
[I
+ Source
.size() * E
];
140 printResourcePressure(FOS
, Usage
/ Executions
, (I
+ 1) * 7);
147 void ResourcePressureView::printResourcePressurePerInst(raw_ostream
&OS
) const {
149 raw_string_ostream
TempStream(Buffer
);
150 formatted_raw_ostream
FOS(TempStream
);
152 FOS
<< "\n\nResource pressure by instruction:\n";
153 printColumnNames(FOS
, getSubTargetInfo().getSchedModel());
154 FOS
<< "Instructions:\n";
156 unsigned InstrIndex
= 0;
157 ArrayRef
<llvm::MCInst
> Source
= getSource();
158 const unsigned Executions
= LastInstructionIdx
/ Source
.size() + 1;
159 for (const MCInst
&MCI
: Source
) {
160 unsigned BaseEltIdx
= InstrIndex
* NumResourceUnits
;
161 for (unsigned J
= 0; J
< NumResourceUnits
; ++J
) {
162 double Usage
= ResourceUsage
[J
+ BaseEltIdx
];
163 printResourcePressure(FOS
, Usage
/ Executions
, (J
+ 1) * 7);
166 FOS
<< printInstructionString(MCI
) << '\n';
175 json::Value
ResourcePressureView::toJSON() const {
176 // We're dumping the instructions and the ResourceUsage array.
177 json::Array ResourcePressureInfo
;
179 // The ResourceUsage matrix is sparse, so we only consider
181 ArrayRef
<llvm::MCInst
> Source
= getSource();
182 const unsigned Executions
= LastInstructionIdx
/ Source
.size() + 1;
183 for (const auto &R
: enumerate(ResourceUsage
)) {
184 const ReleaseAtCycles
&RU
= R
.value();
185 if (RU
.getNumerator() == 0)
187 unsigned InstructionIndex
= R
.index() / NumResourceUnits
;
188 unsigned ResourceIndex
= R
.index() % NumResourceUnits
;
189 double Usage
= RU
/ Executions
;
190 ResourcePressureInfo
.push_back(
191 json::Object({{"InstructionIndex", InstructionIndex
},
192 {"ResourceIndex", ResourceIndex
},
193 {"ResourceUsage", Usage
}}));
196 json::Object
JO({{"ResourcePressureInfo", std::move(ResourcePressureInfo
)}});