xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-mca/Views/BottleneckAnalysis.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===--------------------- BottleneckAnalysis.h -----------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// This file implements the bottleneck analysis view.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric /// This view internally observes backend pressure increase events in order to
130b57cec5SDimitry Andric /// identify problematic data dependencies and processor resource interferences.
140b57cec5SDimitry Andric ///
150b57cec5SDimitry Andric /// Example of bottleneck analysis report for a dot-product on X86 btver2:
160b57cec5SDimitry Andric ///
170b57cec5SDimitry Andric /// Cycles with backend pressure increase [ 40.76% ]
180b57cec5SDimitry Andric /// Throughput Bottlenecks:
190b57cec5SDimitry Andric ///   Resource Pressure       [ 39.34% ]
200b57cec5SDimitry Andric ///   - JFPA  [ 39.34% ]
210b57cec5SDimitry Andric ///   - JFPU0  [ 39.34% ]
220b57cec5SDimitry Andric ///   Data Dependencies:      [ 1.42% ]
230b57cec5SDimitry Andric ///   - Register Dependencies [ 1.42% ]
240b57cec5SDimitry Andric ///   - Memory Dependencies   [ 0.00% ]
250b57cec5SDimitry Andric ///
260b57cec5SDimitry Andric /// According to the example, backend pressure increased during the 40.76% of
270b57cec5SDimitry Andric /// the simulated cycles.  In particular, the major cause of backend pressure
280b57cec5SDimitry Andric /// increases was the contention on floating point adder JFPA accessible from
290b57cec5SDimitry Andric /// pipeline resource JFPU0.
300b57cec5SDimitry Andric ///
310b57cec5SDimitry Andric /// At the end of each cycle, if pressure on the simulated out-of-order buffers
320b57cec5SDimitry Andric /// has increased, a backend pressure event is reported.
330b57cec5SDimitry Andric /// In particular, this occurs when there is a delta between the number of uOps
340b57cec5SDimitry Andric /// dispatched and the number of uOps issued to the underlying pipelines.
350b57cec5SDimitry Andric ///
36fe6060f1SDimitry Andric /// The bottleneck analysis view is also responsible for identifying and
37fe6060f1SDimitry Andric /// printing the most "critical" sequence of dependent instructions according to
38fe6060f1SDimitry Andric /// the simulated run.
390b57cec5SDimitry Andric ///
400b57cec5SDimitry Andric /// Below is the critical sequence computed for the dot-product example on
410b57cec5SDimitry Andric /// btver2:
420b57cec5SDimitry Andric ///
430b57cec5SDimitry Andric ///              Instruction                     Dependency Information
440b57cec5SDimitry Andric /// +----< 2.    vhaddps %xmm3, %xmm3, %xmm4
450b57cec5SDimitry Andric /// |
460b57cec5SDimitry Andric /// |    < loop carried >
470b57cec5SDimitry Andric /// |
480b57cec5SDimitry Andric /// |      0.    vmulps	 %xmm0, %xmm0, %xmm2
490b57cec5SDimitry Andric /// +----> 1.    vhaddps %xmm2, %xmm2, %xmm3     ## RESOURCE interference:  JFPA [ probability: 73% ]
500b57cec5SDimitry Andric /// +----> 2.    vhaddps %xmm3, %xmm3, %xmm4     ## REGISTER dependency:  %xmm3
510b57cec5SDimitry Andric /// |
520b57cec5SDimitry Andric /// |    < loop carried >
530b57cec5SDimitry Andric /// |
540b57cec5SDimitry Andric /// +----> 1.    vhaddps %xmm2, %xmm2, %xmm3     ## RESOURCE interference:  JFPA [ probability: 73% ]
550b57cec5SDimitry Andric ///
560b57cec5SDimitry Andric ///
570b57cec5SDimitry Andric /// The algorithm that computes the critical sequence is very similar to a
580b57cec5SDimitry Andric /// critical path analysis.
590b57cec5SDimitry Andric ///
600b57cec5SDimitry Andric /// A dependency graph is used internally to track dependencies between nodes.
610b57cec5SDimitry Andric /// Nodes of the graph represent instructions from the input assembly sequence,
620b57cec5SDimitry Andric /// and edges of the graph represent data dependencies or processor resource
630b57cec5SDimitry Andric /// interferences.
640b57cec5SDimitry Andric ///
65fe6060f1SDimitry Andric /// Edges are dynamically 'discovered' by observing instruction state
66fe6060f1SDimitry Andric /// transitions and backend pressure increase events. Edges are internally
67fe6060f1SDimitry Andric /// ranked based on their "criticality". A dependency is considered to be
68fe6060f1SDimitry Andric /// critical if it takes a long time to execute, and if it contributes to
69fe6060f1SDimitry Andric /// backend pressure increases. Criticality is internally measured in terms of
70fe6060f1SDimitry Andric /// cycles; it is computed for every edge in the graph as a function of the edge
71fe6060f1SDimitry Andric /// latency and the number of backend pressure increase cycles contributed by
72fe6060f1SDimitry Andric /// that edge.
730b57cec5SDimitry Andric ///
740b57cec5SDimitry Andric /// At the end of simulation, costs are propagated to nodes through the edges of
750b57cec5SDimitry Andric /// the graph, and the most expensive path connecting the root-set (a
760b57cec5SDimitry Andric /// set of nodes with no predecessors) to a leaf node is reported as critical
770b57cec5SDimitry Andric /// sequence.
780b57cec5SDimitry Andric //
790b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric #ifndef LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
820b57cec5SDimitry Andric #define LLVM_TOOLS_LLVM_MCA_BOTTLENECK_ANALYSIS_H
830b57cec5SDimitry Andric 
84e8d8bef9SDimitry Andric #include "Views/InstructionView.h"
850b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
860b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
870b57cec5SDimitry Andric #include "llvm/MC/MCInstPrinter.h"
880b57cec5SDimitry Andric #include "llvm/MC/MCSchedule.h"
890b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
90e8d8bef9SDimitry Andric #include "llvm/Support/FormattedStream.h"
910b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric namespace llvm {
940b57cec5SDimitry Andric namespace mca {
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric class PressureTracker {
970b57cec5SDimitry Andric   const MCSchedModel &SM;
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   // Resource pressure distribution. There is an element for every processor
1000b57cec5SDimitry Andric   // resource declared by the scheduling model. Quantities are number of cycles.
1010b57cec5SDimitry Andric   SmallVector<unsigned, 4> ResourcePressureDistribution;
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   // Each processor resource is associated with a so-called processor resource
1040b57cec5SDimitry Andric   // mask. This vector allows to correlate processor resource IDs with processor
1050b57cec5SDimitry Andric   // resource masks. There is exactly one element per each processor resource
1060b57cec5SDimitry Andric   // declared by the scheduling model.
1070b57cec5SDimitry Andric   SmallVector<uint64_t, 4> ProcResID2Mask;
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   // Maps processor resource state indices (returned by calls to
1100b57cec5SDimitry Andric   // `getResourceStateIndex(Mask)` to processor resource identifiers.
1110b57cec5SDimitry Andric   SmallVector<unsigned, 4> ResIdx2ProcResID;
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   // Maps Processor Resource identifiers to ResourceUsers indices.
1140b57cec5SDimitry Andric   SmallVector<unsigned, 4> ProcResID2ResourceUsersIndex;
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   // Identifies the last user of a processor resource unit.
1170b57cec5SDimitry Andric   // This vector is updated on every instruction issued event.
1180b57cec5SDimitry Andric   // There is one entry for every processor resource unit declared by the
1190b57cec5SDimitry Andric   // processor model. An all_ones value is treated like an invalid instruction
1200b57cec5SDimitry Andric   // identifier.
1210b57cec5SDimitry Andric   using User = std::pair<unsigned, unsigned>;
1220b57cec5SDimitry Andric   SmallVector<User, 4> ResourceUsers;
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   struct InstructionPressureInfo {
1250b57cec5SDimitry Andric     unsigned RegisterPressureCycles;
1260b57cec5SDimitry Andric     unsigned MemoryPressureCycles;
1270b57cec5SDimitry Andric     unsigned ResourcePressureCycles;
1280b57cec5SDimitry Andric   };
1290b57cec5SDimitry Andric   DenseMap<unsigned, InstructionPressureInfo> IPI;
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   void updateResourcePressureDistribution(uint64_t CumulativeMask);
1320b57cec5SDimitry Andric 
getResourceUser(unsigned ProcResID,unsigned UnitID)1330b57cec5SDimitry Andric   User getResourceUser(unsigned ProcResID, unsigned UnitID) const {
1340b57cec5SDimitry Andric     unsigned Index = ProcResID2ResourceUsersIndex[ProcResID];
1350b57cec5SDimitry Andric     return ResourceUsers[Index + UnitID];
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric public:
1390b57cec5SDimitry Andric   PressureTracker(const MCSchedModel &Model);
1400b57cec5SDimitry Andric 
getResourcePressureDistribution()1410b57cec5SDimitry Andric   ArrayRef<unsigned> getResourcePressureDistribution() const {
1420b57cec5SDimitry Andric     return ResourcePressureDistribution;
1430b57cec5SDimitry Andric   }
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   void getResourceUsers(uint64_t ResourceMask,
1460b57cec5SDimitry Andric                         SmallVectorImpl<User> &Users) const;
1470b57cec5SDimitry Andric 
getRegisterPressureCycles(unsigned IID)1480b57cec5SDimitry Andric   unsigned getRegisterPressureCycles(unsigned IID) const {
149*06c3fb27SDimitry Andric     assert(IPI.contains(IID) && "Instruction is not tracked!");
1500b57cec5SDimitry Andric     const InstructionPressureInfo &Info = IPI.find(IID)->second;
1510b57cec5SDimitry Andric     return Info.RegisterPressureCycles;
1520b57cec5SDimitry Andric   }
1530b57cec5SDimitry Andric 
getMemoryPressureCycles(unsigned IID)1540b57cec5SDimitry Andric   unsigned getMemoryPressureCycles(unsigned IID) const {
155*06c3fb27SDimitry Andric     assert(IPI.contains(IID) && "Instruction is not tracked!");
1560b57cec5SDimitry Andric     const InstructionPressureInfo &Info = IPI.find(IID)->second;
1570b57cec5SDimitry Andric     return Info.MemoryPressureCycles;
1580b57cec5SDimitry Andric   }
1590b57cec5SDimitry Andric 
getResourcePressureCycles(unsigned IID)1600b57cec5SDimitry Andric   unsigned getResourcePressureCycles(unsigned IID) const {
161*06c3fb27SDimitry Andric     assert(IPI.contains(IID) && "Instruction is not tracked!");
1620b57cec5SDimitry Andric     const InstructionPressureInfo &Info = IPI.find(IID)->second;
1630b57cec5SDimitry Andric     return Info.ResourcePressureCycles;
1640b57cec5SDimitry Andric   }
1650b57cec5SDimitry Andric 
resolveResourceName(uint64_t ResourceMask)1660b57cec5SDimitry Andric   const char *resolveResourceName(uint64_t ResourceMask) const {
1670b57cec5SDimitry Andric     unsigned Index = getResourceStateIndex(ResourceMask);
1680b57cec5SDimitry Andric     unsigned ProcResID = ResIdx2ProcResID[Index];
1690b57cec5SDimitry Andric     const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID);
1700b57cec5SDimitry Andric     return PRDesc.Name;
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   void onInstructionDispatched(unsigned IID);
1740b57cec5SDimitry Andric   void onInstructionExecuted(unsigned IID);
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric   void handlePressureEvent(const HWPressureEvent &Event);
1770b57cec5SDimitry Andric   void handleInstructionIssuedEvent(const HWInstructionIssuedEvent &Event);
1780b57cec5SDimitry Andric };
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric // A dependency edge.
1810b57cec5SDimitry Andric struct DependencyEdge {
1820b57cec5SDimitry Andric   enum DependencyType { DT_INVALID, DT_REGISTER, DT_MEMORY, DT_RESOURCE };
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric   // Dependency edge descriptor.
1850b57cec5SDimitry Andric   //
1860b57cec5SDimitry Andric   // It specifies the dependency type, as well as the edge cost in cycles.
1870b57cec5SDimitry Andric   struct Dependency {
1880b57cec5SDimitry Andric     DependencyType Type;
1890b57cec5SDimitry Andric     uint64_t ResourceOrRegID;
1900b57cec5SDimitry Andric     uint64_t Cost;
1910b57cec5SDimitry Andric   };
1920b57cec5SDimitry Andric   Dependency Dep;
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   unsigned FromIID;
1950b57cec5SDimitry Andric   unsigned ToIID;
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   // Used by the bottleneck analysis to compute the interference
1980b57cec5SDimitry Andric   // probability for processor resources.
1990b57cec5SDimitry Andric   unsigned Frequency;
2000b57cec5SDimitry Andric };
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric // A dependency graph used by the bottleneck analysis to describe data
2030b57cec5SDimitry Andric // dependencies and processor resource interferences between instructions.
2040b57cec5SDimitry Andric //
2050b57cec5SDimitry Andric // There is a node (an instance of struct DGNode) for every instruction in the
2060b57cec5SDimitry Andric // input assembly sequence. Edges of the graph represent dependencies between
2070b57cec5SDimitry Andric // instructions.
2080b57cec5SDimitry Andric //
2090b57cec5SDimitry Andric // Each edge of the graph is associated with a cost value which is used
2100b57cec5SDimitry Andric // internally to rank dependency based on their impact on the runtime
2110b57cec5SDimitry Andric // performance (see field DependencyEdge::Dependency::Cost). In general, the
2120b57cec5SDimitry Andric // higher the cost of an edge, the higher the impact on performance.
2130b57cec5SDimitry Andric //
2140b57cec5SDimitry Andric // The cost of a dependency is a function of both the latency and the number of
2150b57cec5SDimitry Andric // cycles where the dependency has been seen as critical (i.e. contributing to
2160b57cec5SDimitry Andric // back-pressure increases).
2170b57cec5SDimitry Andric //
2180b57cec5SDimitry Andric // Loop carried dependencies are carefully expanded by the bottleneck analysis
2190b57cec5SDimitry Andric // to guarantee that the graph stays acyclic. To this end, extra nodes are
2200b57cec5SDimitry Andric // pre-allocated at construction time to describe instructions from "past and
221fe6060f1SDimitry Andric // future" iterations. The graph is kept acyclic mainly because it simplifies
222fe6060f1SDimitry Andric // the complexity of the algorithm that computes the critical sequence.
2230b57cec5SDimitry Andric class DependencyGraph {
2240b57cec5SDimitry Andric   struct DGNode {
2250b57cec5SDimitry Andric     unsigned NumPredecessors;
2260b57cec5SDimitry Andric     unsigned NumVisitedPredecessors;
2270b57cec5SDimitry Andric     uint64_t Cost;
2280b57cec5SDimitry Andric     unsigned Depth;
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric     DependencyEdge CriticalPredecessor;
2310b57cec5SDimitry Andric     SmallVector<DependencyEdge, 8> OutgoingEdges;
2320b57cec5SDimitry Andric   };
2330b57cec5SDimitry Andric   SmallVector<DGNode, 16> Nodes;
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric   DependencyGraph(const DependencyGraph &) = delete;
2360b57cec5SDimitry Andric   DependencyGraph &operator=(const DependencyGraph &) = delete;
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   void addDependency(unsigned From, unsigned To,
2390b57cec5SDimitry Andric                      DependencyEdge::Dependency &&DE);
2400b57cec5SDimitry Andric 
2418bcb0991SDimitry Andric   void pruneEdges(unsigned Iterations);
2420b57cec5SDimitry Andric   void initializeRootSet(SmallVectorImpl<unsigned> &RootSet) const;
243fe6060f1SDimitry Andric   void propagateThroughEdges(SmallVectorImpl<unsigned> &RootSet,
244fe6060f1SDimitry Andric                              unsigned Iterations);
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric #ifndef NDEBUG
2470b57cec5SDimitry Andric   void dumpDependencyEdge(raw_ostream &OS, const DependencyEdge &DE,
2480b57cec5SDimitry Andric                           MCInstPrinter &MCIP) const;
2490b57cec5SDimitry Andric #endif
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric public:
DependencyGraph(unsigned Size)2520b57cec5SDimitry Andric   DependencyGraph(unsigned Size) : Nodes(Size) {}
2530b57cec5SDimitry Andric 
addRegisterDep(unsigned From,unsigned To,unsigned RegID,unsigned Cost)2540b57cec5SDimitry Andric   void addRegisterDep(unsigned From, unsigned To, unsigned RegID,
2550b57cec5SDimitry Andric                       unsigned Cost) {
2560b57cec5SDimitry Andric     addDependency(From, To, {DependencyEdge::DT_REGISTER, RegID, Cost});
2570b57cec5SDimitry Andric   }
2580b57cec5SDimitry Andric 
addMemoryDep(unsigned From,unsigned To,unsigned Cost)2590b57cec5SDimitry Andric   void addMemoryDep(unsigned From, unsigned To, unsigned Cost) {
2600b57cec5SDimitry Andric     addDependency(From, To, {DependencyEdge::DT_MEMORY, /* unused */ 0, Cost});
2610b57cec5SDimitry Andric   }
2620b57cec5SDimitry Andric 
addResourceDep(unsigned From,unsigned To,uint64_t Mask,unsigned Cost)2630b57cec5SDimitry Andric   void addResourceDep(unsigned From, unsigned To, uint64_t Mask,
2640b57cec5SDimitry Andric                       unsigned Cost) {
2650b57cec5SDimitry Andric     addDependency(From, To, {DependencyEdge::DT_RESOURCE, Mask, Cost});
2660b57cec5SDimitry Andric   }
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric   // Called by the bottleneck analysis at the end of simulation to propagate
2690b57cec5SDimitry Andric   // costs through the edges of the graph, and compute a critical path.
finalizeGraph(unsigned Iterations)2708bcb0991SDimitry Andric   void finalizeGraph(unsigned Iterations) {
2710b57cec5SDimitry Andric     SmallVector<unsigned, 16> RootSet;
2728bcb0991SDimitry Andric     pruneEdges(Iterations);
2730b57cec5SDimitry Andric     initializeRootSet(RootSet);
2748bcb0991SDimitry Andric     propagateThroughEdges(RootSet, Iterations);
2750b57cec5SDimitry Andric   }
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric   // Returns a sequence of edges representing the critical sequence based on the
2780b57cec5SDimitry Andric   // simulated run. It assumes that the graph has already been finalized (i.e.
2790b57cec5SDimitry Andric   // method `finalizeGraph()` has already been called on this graph).
2800b57cec5SDimitry Andric   void getCriticalSequence(SmallVectorImpl<const DependencyEdge *> &Seq) const;
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric #ifndef NDEBUG
2830b57cec5SDimitry Andric   void dump(raw_ostream &OS, MCInstPrinter &MCIP) const;
2840b57cec5SDimitry Andric #endif
2850b57cec5SDimitry Andric };
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric /// A view that collects and prints a few performance numbers.
288e8d8bef9SDimitry Andric class BottleneckAnalysis : public InstructionView {
2890b57cec5SDimitry Andric   PressureTracker Tracker;
2900b57cec5SDimitry Andric   DependencyGraph DG;
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric   unsigned Iterations;
2930b57cec5SDimitry Andric   unsigned TotalCycles;
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric   bool PressureIncreasedBecauseOfResources;
2960b57cec5SDimitry Andric   bool PressureIncreasedBecauseOfRegisterDependencies;
2970b57cec5SDimitry Andric   bool PressureIncreasedBecauseOfMemoryDependencies;
2980b57cec5SDimitry Andric   // True if throughput was affected by dispatch stalls.
2990b57cec5SDimitry Andric   bool SeenStallCycles;
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric   struct BackPressureInfo {
3020b57cec5SDimitry Andric     // Cycles where backpressure increased.
3030b57cec5SDimitry Andric     unsigned PressureIncreaseCycles;
3040b57cec5SDimitry Andric     // Cycles where backpressure increased because of pipeline pressure.
3050b57cec5SDimitry Andric     unsigned ResourcePressureCycles;
3060b57cec5SDimitry Andric     // Cycles where backpressure increased because of data dependencies.
3070b57cec5SDimitry Andric     unsigned DataDependencyCycles;
3080b57cec5SDimitry Andric     // Cycles where backpressure increased because of register dependencies.
3090b57cec5SDimitry Andric     unsigned RegisterDependencyCycles;
3100b57cec5SDimitry Andric     // Cycles where backpressure increased because of memory dependencies.
3110b57cec5SDimitry Andric     unsigned MemoryDependencyCycles;
3120b57cec5SDimitry Andric   };
3130b57cec5SDimitry Andric   BackPressureInfo BPI;
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric   // Used to populate the dependency graph DG.
3160b57cec5SDimitry Andric   void addRegisterDep(unsigned From, unsigned To, unsigned RegID, unsigned Cy);
3170b57cec5SDimitry Andric   void addMemoryDep(unsigned From, unsigned To, unsigned Cy);
3180b57cec5SDimitry Andric   void addResourceDep(unsigned From, unsigned To, uint64_t Mask, unsigned Cy);
3190b57cec5SDimitry Andric 
320e8d8bef9SDimitry Andric   void printInstruction(formatted_raw_ostream &FOS, const MCInst &MCI,
321e8d8bef9SDimitry Andric                         bool UseDifferentColor = false) const;
322e8d8bef9SDimitry Andric 
3230b57cec5SDimitry Andric   // Prints a bottleneck message to OS.
3240b57cec5SDimitry Andric   void printBottleneckHints(raw_ostream &OS) const;
3250b57cec5SDimitry Andric   void printCriticalSequence(raw_ostream &OS) const;
3260b57cec5SDimitry Andric 
3270b57cec5SDimitry Andric public:
3280b57cec5SDimitry Andric   BottleneckAnalysis(const MCSubtargetInfo &STI, MCInstPrinter &MCIP,
3290b57cec5SDimitry Andric                      ArrayRef<MCInst> Sequence, unsigned Iterations);
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric   void onCycleEnd() override;
onEvent(const HWStallEvent & Event)3320b57cec5SDimitry Andric   void onEvent(const HWStallEvent &Event) override { SeenStallCycles = true; }
3330b57cec5SDimitry Andric   void onEvent(const HWPressureEvent &Event) override;
3340b57cec5SDimitry Andric   void onEvent(const HWInstructionEvent &Event) override;
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric   void printView(raw_ostream &OS) const override;
getNameAsString()337e8d8bef9SDimitry Andric   StringRef getNameAsString() const override { return "BottleneckAnalysis"; }
isSerializable()338fe6060f1SDimitry Andric   bool isSerializable() const override { return false; }
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric #ifndef NDEBUG
dump(raw_ostream & OS,MCInstPrinter & MCIP)3410b57cec5SDimitry Andric   void dump(raw_ostream &OS, MCInstPrinter &MCIP) const { DG.dump(OS, MCIP); }
3420b57cec5SDimitry Andric #endif
3430b57cec5SDimitry Andric };
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric } // namespace mca
3460b57cec5SDimitry Andric } // namespace llvm
3470b57cec5SDimitry Andric 
3480b57cec5SDimitry Andric #endif
349