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