xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===--------------------- BottleneckAnalysis.h -----------------*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric /// \file
9*0b57cec5SDimitry Andric ///
10*0b57cec5SDimitry Andric /// This file implements the bottleneck analysis view.
11*0b57cec5SDimitry Andric ///
12*0b57cec5SDimitry Andric /// This view internally observes backend pressure increase events in order to
13*0b57cec5SDimitry Andric /// identify problematic data dependencies and processor resource interferences.
14*0b57cec5SDimitry Andric ///
15*0b57cec5SDimitry Andric /// Example of bottleneck analysis report for a dot-product on X86 btver2:
16*0b57cec5SDimitry Andric ///
17*0b57cec5SDimitry Andric /// Cycles with backend pressure increase [ 40.76% ]
18*0b57cec5SDimitry Andric /// Throughput Bottlenecks:
19*0b57cec5SDimitry Andric ///   Resource Pressure       [ 39.34% ]
20*0b57cec5SDimitry Andric ///   - JFPA  [ 39.34% ]
21*0b57cec5SDimitry Andric ///   - JFPU0  [ 39.34% ]
22*0b57cec5SDimitry Andric ///   Data Dependencies:      [ 1.42% ]
23*0b57cec5SDimitry Andric ///   - Register Dependencies [ 1.42% ]
24*0b57cec5SDimitry Andric ///   - Memory Dependencies   [ 0.00% ]
25*0b57cec5SDimitry Andric ///
26*0b57cec5SDimitry Andric /// According to the example, backend pressure increased during the 40.76% of
27*0b57cec5SDimitry Andric /// the simulated cycles.  In particular, the major cause of backend pressure
28*0b57cec5SDimitry Andric /// increases was the contention on floating point adder JFPA accessible from
29*0b57cec5SDimitry Andric /// pipeline resource JFPU0.
30*0b57cec5SDimitry Andric ///
31*0b57cec5SDimitry Andric /// At the end of each cycle, if pressure on the simulated out-of-order buffers
32*0b57cec5SDimitry Andric /// has increased, a backend pressure event is reported.
33*0b57cec5SDimitry Andric /// In particular, this occurs when there is a delta between the number of uOps
34*0b57cec5SDimitry Andric /// dispatched and the number of uOps issued to the underlying pipelines.
35*0b57cec5SDimitry Andric ///
36*0b57cec5SDimitry Andric /// The bottleneck analysis view is also responsible for identifying and printing
37*0b57cec5SDimitry Andric /// the most "critical" sequence of dependent instructions according to the
38*0b57cec5SDimitry Andric /// simulated run.
39*0b57cec5SDimitry Andric ///
40*0b57cec5SDimitry Andric /// Below is the critical sequence computed for the dot-product example on
41*0b57cec5SDimitry Andric /// btver2:
42*0b57cec5SDimitry Andric ///
43*0b57cec5SDimitry Andric ///              Instruction                     Dependency Information
44*0b57cec5SDimitry Andric /// +----< 2.    vhaddps %xmm3, %xmm3, %xmm4
45*0b57cec5SDimitry Andric /// |
46*0b57cec5SDimitry Andric /// |    < loop carried >
47*0b57cec5SDimitry Andric /// |
48*0b57cec5SDimitry Andric /// |      0.    vmulps	 %xmm0, %xmm0, %xmm2
49*0b57cec5SDimitry Andric /// +----> 1.    vhaddps %xmm2, %xmm2, %xmm3     ## RESOURCE interference:  JFPA [ probability: 73% ]
50*0b57cec5SDimitry Andric /// +----> 2.    vhaddps %xmm3, %xmm3, %xmm4     ## REGISTER dependency:  %xmm3
51*0b57cec5SDimitry Andric /// |
52*0b57cec5SDimitry Andric /// |    < loop carried >
53*0b57cec5SDimitry Andric /// |
54*0b57cec5SDimitry Andric /// +----> 1.    vhaddps %xmm2, %xmm2, %xmm3     ## RESOURCE interference:  JFPA [ probability: 73% ]
55*0b57cec5SDimitry Andric ///
56*0b57cec5SDimitry Andric ///
57*0b57cec5SDimitry Andric /// The algorithm that computes the critical sequence is very similar to a
58*0b57cec5SDimitry Andric /// critical path analysis.
59*0b57cec5SDimitry Andric ///
60*0b57cec5SDimitry Andric /// A dependency graph is used internally to track dependencies between nodes.
61*0b57cec5SDimitry Andric /// Nodes of the graph represent instructions from the input assembly sequence,
62*0b57cec5SDimitry Andric /// and edges of the graph represent data dependencies or processor resource
63*0b57cec5SDimitry Andric /// interferences.
64*0b57cec5SDimitry Andric ///
65*0b57cec5SDimitry Andric /// Edges are dynamically 'discovered' by observing instruction state transitions
66*0b57cec5SDimitry Andric /// and backend pressure increase events. Edges are internally ranked based on
67*0b57cec5SDimitry Andric /// their "criticality". A dependency is considered to be critical if it takes a
68*0b57cec5SDimitry Andric /// long time to execute, and if it contributes to backend pressure increases.
69*0b57cec5SDimitry Andric /// Criticality is internally measured in terms of cycles; it is computed for
70*0b57cec5SDimitry Andric /// every edge in the graph as a function of the edge latency and the number of
71*0b57cec5SDimitry Andric /// backend pressure increase cycles contributed by that edge.
72*0b57cec5SDimitry Andric ///
73*0b57cec5SDimitry Andric /// At the end of simulation, costs are propagated to nodes through the edges of
74*0b57cec5SDimitry Andric /// the graph, and the most expensive path connecting the root-set (a
75*0b57cec5SDimitry Andric /// set of nodes with no predecessors) to a leaf node is reported as critical
76*0b57cec5SDimitry Andric /// sequence.
77*0b57cec5SDimitry Andric //
78*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
79*0b57cec5SDimitry Andric 
80*0b57cec5SDimitry Andric #ifndef LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
81*0b57cec5SDimitry Andric #define LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
82*0b57cec5SDimitry Andric 
83*0b57cec5SDimitry Andric #include "Views/View.h"
84*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
85*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
86*0b57cec5SDimitry Andric #include "llvm/MC/MCInstPrinter.h"
87*0b57cec5SDimitry Andric #include "llvm/MC/MCSchedule.h"
88*0b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
89*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
90*0b57cec5SDimitry Andric 
91*0b57cec5SDimitry Andric namespace llvm {
92*0b57cec5SDimitry Andric namespace mca {
93*0b57cec5SDimitry Andric 
94*0b57cec5SDimitry Andric class PressureTracker {
95*0b57cec5SDimitry Andric   const MCSchedModel &SM;
96*0b57cec5SDimitry Andric 
97*0b57cec5SDimitry Andric   // Resource pressure distribution. There is an element for every processor
98*0b57cec5SDimitry Andric   // resource declared by the scheduling model. Quantities are number of cycles.
99*0b57cec5SDimitry Andric   SmallVector<unsigned, 4> ResourcePressureDistribution;
100*0b57cec5SDimitry Andric 
101*0b57cec5SDimitry Andric   // Each processor resource is associated with a so-called processor resource
102*0b57cec5SDimitry Andric   // mask. This vector allows to correlate processor resource IDs with processor
103*0b57cec5SDimitry Andric   // resource masks. There is exactly one element per each processor resource
104*0b57cec5SDimitry Andric   // declared by the scheduling model.
105*0b57cec5SDimitry Andric   SmallVector<uint64_t, 4> ProcResID2Mask;
106*0b57cec5SDimitry Andric 
107*0b57cec5SDimitry Andric   // Maps processor resource state indices (returned by calls to
108*0b57cec5SDimitry Andric   // `getResourceStateIndex(Mask)` to processor resource identifiers.
109*0b57cec5SDimitry Andric   SmallVector<unsigned, 4> ResIdx2ProcResID;
110*0b57cec5SDimitry Andric 
111*0b57cec5SDimitry Andric   // Maps Processor Resource identifiers to ResourceUsers indices.
112*0b57cec5SDimitry Andric   SmallVector<unsigned, 4> ProcResID2ResourceUsersIndex;
113*0b57cec5SDimitry Andric 
114*0b57cec5SDimitry Andric   // Identifies the last user of a processor resource unit.
115*0b57cec5SDimitry Andric   // This vector is updated on every instruction issued event.
116*0b57cec5SDimitry Andric   // There is one entry for every processor resource unit declared by the
117*0b57cec5SDimitry Andric   // processor model. An all_ones value is treated like an invalid instruction
118*0b57cec5SDimitry Andric   // identifier.
119*0b57cec5SDimitry Andric   using User = std::pair<unsigned, unsigned>;
120*0b57cec5SDimitry Andric   SmallVector<User, 4> ResourceUsers;
121*0b57cec5SDimitry Andric 
122*0b57cec5SDimitry Andric   struct InstructionPressureInfo {
123*0b57cec5SDimitry Andric     unsigned RegisterPressureCycles;
124*0b57cec5SDimitry Andric     unsigned MemoryPressureCycles;
125*0b57cec5SDimitry Andric     unsigned ResourcePressureCycles;
126*0b57cec5SDimitry Andric   };
127*0b57cec5SDimitry Andric   DenseMap<unsigned, InstructionPressureInfo> IPI;
128*0b57cec5SDimitry Andric 
129*0b57cec5SDimitry Andric   void updateResourcePressureDistribution(uint64_t CumulativeMask);
130*0b57cec5SDimitry Andric 
131*0b57cec5SDimitry Andric   User getResourceUser(unsigned ProcResID, unsigned UnitID) const {
132*0b57cec5SDimitry Andric     unsigned Index = ProcResID2ResourceUsersIndex[ProcResID];
133*0b57cec5SDimitry Andric     return ResourceUsers[Index + UnitID];
134*0b57cec5SDimitry Andric   }
135*0b57cec5SDimitry Andric 
136*0b57cec5SDimitry Andric public:
137*0b57cec5SDimitry Andric   PressureTracker(const MCSchedModel &Model);
138*0b57cec5SDimitry Andric 
139*0b57cec5SDimitry Andric   ArrayRef<unsigned> getResourcePressureDistribution() const {
140*0b57cec5SDimitry Andric     return ResourcePressureDistribution;
141*0b57cec5SDimitry Andric   }
142*0b57cec5SDimitry Andric 
143*0b57cec5SDimitry Andric   void getResourceUsers(uint64_t ResourceMask,
144*0b57cec5SDimitry Andric                         SmallVectorImpl<User> &Users) const;
145*0b57cec5SDimitry Andric 
146*0b57cec5SDimitry Andric   unsigned getRegisterPressureCycles(unsigned IID) const {
147*0b57cec5SDimitry Andric     assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
148*0b57cec5SDimitry Andric     const InstructionPressureInfo &Info = IPI.find(IID)->second;
149*0b57cec5SDimitry Andric     return Info.RegisterPressureCycles;
150*0b57cec5SDimitry Andric   }
151*0b57cec5SDimitry Andric 
152*0b57cec5SDimitry Andric   unsigned getMemoryPressureCycles(unsigned IID) const {
153*0b57cec5SDimitry Andric     assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
154*0b57cec5SDimitry Andric     const InstructionPressureInfo &Info = IPI.find(IID)->second;
155*0b57cec5SDimitry Andric     return Info.MemoryPressureCycles;
156*0b57cec5SDimitry Andric   }
157*0b57cec5SDimitry Andric 
158*0b57cec5SDimitry Andric   unsigned getResourcePressureCycles(unsigned IID) const {
159*0b57cec5SDimitry Andric     assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
160*0b57cec5SDimitry Andric     const InstructionPressureInfo &Info = IPI.find(IID)->second;
161*0b57cec5SDimitry Andric     return Info.ResourcePressureCycles;
162*0b57cec5SDimitry Andric   }
163*0b57cec5SDimitry Andric 
164*0b57cec5SDimitry Andric   const char *resolveResourceName(uint64_t ResourceMask) const {
165*0b57cec5SDimitry Andric     unsigned Index = getResourceStateIndex(ResourceMask);
166*0b57cec5SDimitry Andric     unsigned ProcResID = ResIdx2ProcResID[Index];
167*0b57cec5SDimitry Andric     const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID);
168*0b57cec5SDimitry Andric     return PRDesc.Name;
169*0b57cec5SDimitry Andric   }
170*0b57cec5SDimitry Andric 
171*0b57cec5SDimitry Andric   void onInstructionDispatched(unsigned IID);
172*0b57cec5SDimitry Andric   void onInstructionExecuted(unsigned IID);
173*0b57cec5SDimitry Andric 
174*0b57cec5SDimitry Andric   void handlePressureEvent(const HWPressureEvent &Event);
175*0b57cec5SDimitry Andric   void handleInstructionIssuedEvent(const HWInstructionIssuedEvent &Event);
176*0b57cec5SDimitry Andric };
177*0b57cec5SDimitry Andric 
178*0b57cec5SDimitry Andric // A dependency edge.
179*0b57cec5SDimitry Andric struct DependencyEdge {
180*0b57cec5SDimitry Andric   enum DependencyType { DT_INVALID, DT_REGISTER, DT_MEMORY, DT_RESOURCE };
181*0b57cec5SDimitry Andric 
182*0b57cec5SDimitry Andric   // Dependency edge descriptor.
183*0b57cec5SDimitry Andric   //
184*0b57cec5SDimitry Andric   // It specifies the dependency type, as well as the edge cost in cycles.
185*0b57cec5SDimitry Andric   struct Dependency {
186*0b57cec5SDimitry Andric     DependencyType Type;
187*0b57cec5SDimitry Andric     uint64_t ResourceOrRegID;
188*0b57cec5SDimitry Andric     uint64_t Cost;
189*0b57cec5SDimitry Andric   };
190*0b57cec5SDimitry Andric   Dependency Dep;
191*0b57cec5SDimitry Andric 
192*0b57cec5SDimitry Andric   unsigned FromIID;
193*0b57cec5SDimitry Andric   unsigned ToIID;
194*0b57cec5SDimitry Andric 
195*0b57cec5SDimitry Andric   // Used by the bottleneck analysis to compute the interference
196*0b57cec5SDimitry Andric   // probability for processor resources.
197*0b57cec5SDimitry Andric   unsigned Frequency;
198*0b57cec5SDimitry Andric };
199*0b57cec5SDimitry Andric 
200*0b57cec5SDimitry Andric // A dependency graph used by the bottleneck analysis to describe data
201*0b57cec5SDimitry Andric // dependencies and processor resource interferences between instructions.
202*0b57cec5SDimitry Andric //
203*0b57cec5SDimitry Andric // There is a node (an instance of struct DGNode) for every instruction in the
204*0b57cec5SDimitry Andric // input assembly sequence. Edges of the graph represent dependencies between
205*0b57cec5SDimitry Andric // instructions.
206*0b57cec5SDimitry Andric //
207*0b57cec5SDimitry Andric // Each edge of the graph is associated with a cost value which is used
208*0b57cec5SDimitry Andric // internally to rank dependency based on their impact on the runtime
209*0b57cec5SDimitry Andric // performance (see field DependencyEdge::Dependency::Cost). In general, the
210*0b57cec5SDimitry Andric // higher the cost of an edge, the higher the impact on performance.
211*0b57cec5SDimitry Andric //
212*0b57cec5SDimitry Andric // The cost of a dependency is a function of both the latency and the number of
213*0b57cec5SDimitry Andric // cycles where the dependency has been seen as critical (i.e. contributing to
214*0b57cec5SDimitry Andric // back-pressure increases).
215*0b57cec5SDimitry Andric //
216*0b57cec5SDimitry Andric // Loop carried dependencies are carefully expanded by the bottleneck analysis
217*0b57cec5SDimitry Andric // to guarantee that the graph stays acyclic. To this end, extra nodes are
218*0b57cec5SDimitry Andric // pre-allocated at construction time to describe instructions from "past and
219*0b57cec5SDimitry Andric // future" iterations. The graph is kept acyclic mainly because it simplifies the
220*0b57cec5SDimitry Andric // complexity of the algorithm that computes the critical sequence.
221*0b57cec5SDimitry Andric class DependencyGraph {
222*0b57cec5SDimitry Andric   struct DGNode {
223*0b57cec5SDimitry Andric     unsigned NumPredecessors;
224*0b57cec5SDimitry Andric     unsigned NumVisitedPredecessors;
225*0b57cec5SDimitry Andric     uint64_t Cost;
226*0b57cec5SDimitry Andric     unsigned Depth;
227*0b57cec5SDimitry Andric 
228*0b57cec5SDimitry Andric     DependencyEdge CriticalPredecessor;
229*0b57cec5SDimitry Andric     SmallVector<DependencyEdge, 8> OutgoingEdges;
230*0b57cec5SDimitry Andric   };
231*0b57cec5SDimitry Andric   SmallVector<DGNode, 16> Nodes;
232*0b57cec5SDimitry Andric 
233*0b57cec5SDimitry Andric   DependencyGraph(const DependencyGraph &) = delete;
234*0b57cec5SDimitry Andric   DependencyGraph &operator=(const DependencyGraph &) = delete;
235*0b57cec5SDimitry Andric 
236*0b57cec5SDimitry Andric   void addDependency(unsigned From, unsigned To,
237*0b57cec5SDimitry Andric                      DependencyEdge::Dependency &&DE);
238*0b57cec5SDimitry Andric 
239*0b57cec5SDimitry Andric   void initializeRootSet(SmallVectorImpl<unsigned> &RootSet) const;
240*0b57cec5SDimitry Andric   void propagateThroughEdges(SmallVectorImpl<unsigned> &RootSet);
241*0b57cec5SDimitry Andric 
242*0b57cec5SDimitry Andric #ifndef NDEBUG
243*0b57cec5SDimitry Andric   void dumpDependencyEdge(raw_ostream &OS, const DependencyEdge &DE,
244*0b57cec5SDimitry Andric                           MCInstPrinter &MCIP) const;
245*0b57cec5SDimitry Andric #endif
246*0b57cec5SDimitry Andric 
247*0b57cec5SDimitry Andric public:
248*0b57cec5SDimitry Andric   DependencyGraph(unsigned Size) : Nodes(Size) {}
249*0b57cec5SDimitry Andric 
250*0b57cec5SDimitry Andric   void addRegisterDep(unsigned From, unsigned To, unsigned RegID,
251*0b57cec5SDimitry Andric                       unsigned Cost) {
252*0b57cec5SDimitry Andric     addDependency(From, To, {DependencyEdge::DT_REGISTER, RegID, Cost});
253*0b57cec5SDimitry Andric   }
254*0b57cec5SDimitry Andric 
255*0b57cec5SDimitry Andric   void addMemoryDep(unsigned From, unsigned To, unsigned Cost) {
256*0b57cec5SDimitry Andric     addDependency(From, To, {DependencyEdge::DT_MEMORY, /* unused */ 0, Cost});
257*0b57cec5SDimitry Andric   }
258*0b57cec5SDimitry Andric 
259*0b57cec5SDimitry Andric   void addResourceDep(unsigned From, unsigned To, uint64_t Mask,
260*0b57cec5SDimitry Andric                       unsigned Cost) {
261*0b57cec5SDimitry Andric     addDependency(From, To, {DependencyEdge::DT_RESOURCE, Mask, Cost});
262*0b57cec5SDimitry Andric   }
263*0b57cec5SDimitry Andric 
264*0b57cec5SDimitry Andric   // Called by the bottleneck analysis at the end of simulation to propagate
265*0b57cec5SDimitry Andric   // costs through the edges of the graph, and compute a critical path.
266*0b57cec5SDimitry Andric   void finalizeGraph() {
267*0b57cec5SDimitry Andric     SmallVector<unsigned, 16> RootSet;
268*0b57cec5SDimitry Andric     initializeRootSet(RootSet);
269*0b57cec5SDimitry Andric     propagateThroughEdges(RootSet);
270*0b57cec5SDimitry Andric   }
271*0b57cec5SDimitry Andric 
272*0b57cec5SDimitry Andric   // Returns a sequence of edges representing the critical sequence based on the
273*0b57cec5SDimitry Andric   // simulated run. It assumes that the graph has already been finalized (i.e.
274*0b57cec5SDimitry Andric   // method `finalizeGraph()` has already been called on this graph).
275*0b57cec5SDimitry Andric   void getCriticalSequence(SmallVectorImpl<const DependencyEdge *> &Seq) const;
276*0b57cec5SDimitry Andric 
277*0b57cec5SDimitry Andric #ifndef NDEBUG
278*0b57cec5SDimitry Andric   void dump(raw_ostream &OS, MCInstPrinter &MCIP) const;
279*0b57cec5SDimitry Andric #endif
280*0b57cec5SDimitry Andric };
281*0b57cec5SDimitry Andric 
282*0b57cec5SDimitry Andric /// A view that collects and prints a few performance numbers.
283*0b57cec5SDimitry Andric class BottleneckAnalysis : public View {
284*0b57cec5SDimitry Andric   const MCSubtargetInfo &STI;
285*0b57cec5SDimitry Andric   MCInstPrinter &MCIP;
286*0b57cec5SDimitry Andric   PressureTracker Tracker;
287*0b57cec5SDimitry Andric   DependencyGraph DG;
288*0b57cec5SDimitry Andric 
289*0b57cec5SDimitry Andric   ArrayRef<MCInst> Source;
290*0b57cec5SDimitry Andric   unsigned Iterations;
291*0b57cec5SDimitry Andric   unsigned TotalCycles;
292*0b57cec5SDimitry Andric 
293*0b57cec5SDimitry Andric   bool PressureIncreasedBecauseOfResources;
294*0b57cec5SDimitry Andric   bool PressureIncreasedBecauseOfRegisterDependencies;
295*0b57cec5SDimitry Andric   bool PressureIncreasedBecauseOfMemoryDependencies;
296*0b57cec5SDimitry Andric   // True if throughput was affected by dispatch stalls.
297*0b57cec5SDimitry Andric   bool SeenStallCycles;
298*0b57cec5SDimitry Andric 
299*0b57cec5SDimitry Andric   struct BackPressureInfo {
300*0b57cec5SDimitry Andric     // Cycles where backpressure increased.
301*0b57cec5SDimitry Andric     unsigned PressureIncreaseCycles;
302*0b57cec5SDimitry Andric     // Cycles where backpressure increased because of pipeline pressure.
303*0b57cec5SDimitry Andric     unsigned ResourcePressureCycles;
304*0b57cec5SDimitry Andric     // Cycles where backpressure increased because of data dependencies.
305*0b57cec5SDimitry Andric     unsigned DataDependencyCycles;
306*0b57cec5SDimitry Andric     // Cycles where backpressure increased because of register dependencies.
307*0b57cec5SDimitry Andric     unsigned RegisterDependencyCycles;
308*0b57cec5SDimitry Andric     // Cycles where backpressure increased because of memory dependencies.
309*0b57cec5SDimitry Andric     unsigned MemoryDependencyCycles;
310*0b57cec5SDimitry Andric   };
311*0b57cec5SDimitry Andric   BackPressureInfo BPI;
312*0b57cec5SDimitry Andric 
313*0b57cec5SDimitry Andric   // Used to populate the dependency graph DG.
314*0b57cec5SDimitry Andric   void addRegisterDep(unsigned From, unsigned To, unsigned RegID, unsigned Cy);
315*0b57cec5SDimitry Andric   void addMemoryDep(unsigned From, unsigned To, unsigned Cy);
316*0b57cec5SDimitry Andric   void addResourceDep(unsigned From, unsigned To, uint64_t Mask, unsigned Cy);
317*0b57cec5SDimitry Andric 
318*0b57cec5SDimitry Andric   // Prints a bottleneck message to OS.
319*0b57cec5SDimitry Andric   void printBottleneckHints(raw_ostream &OS) const;
320*0b57cec5SDimitry Andric   void printCriticalSequence(raw_ostream &OS) const;
321*0b57cec5SDimitry Andric 
322*0b57cec5SDimitry Andric public:
323*0b57cec5SDimitry Andric   BottleneckAnalysis(const MCSubtargetInfo &STI, MCInstPrinter &MCIP,
324*0b57cec5SDimitry Andric                      ArrayRef<MCInst> Sequence, unsigned Iterations);
325*0b57cec5SDimitry Andric 
326*0b57cec5SDimitry Andric   void onCycleEnd() override;
327*0b57cec5SDimitry Andric   void onEvent(const HWStallEvent &Event) override { SeenStallCycles = true; }
328*0b57cec5SDimitry Andric   void onEvent(const HWPressureEvent &Event) override;
329*0b57cec5SDimitry Andric   void onEvent(const HWInstructionEvent &Event) override;
330*0b57cec5SDimitry Andric 
331*0b57cec5SDimitry Andric   void printView(raw_ostream &OS) const override;
332*0b57cec5SDimitry Andric 
333*0b57cec5SDimitry Andric #ifndef NDEBUG
334*0b57cec5SDimitry Andric   void dump(raw_ostream &OS, MCInstPrinter &MCIP) const { DG.dump(OS, MCIP); }
335*0b57cec5SDimitry Andric #endif
336*0b57cec5SDimitry Andric };
337*0b57cec5SDimitry Andric 
338*0b57cec5SDimitry Andric } // namespace mca
339*0b57cec5SDimitry Andric } // namespace llvm
340*0b57cec5SDimitry Andric 
341*0b57cec5SDimitry Andric #endif
342