brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.8 KiB · e7d8083 Raw
691 lines · cpp
1//===--------------------- BottleneckAnalysis.cpp ---------------*- C++ -*-===//2//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-exception6//7//===----------------------------------------------------------------------===//8/// \file9///10/// This file implements the functionalities used by the BottleneckAnalysis11/// to report bottleneck info.12///13//===----------------------------------------------------------------------===//14 15#include "Views/BottleneckAnalysis.h"16#include "llvm/MC/MCInst.h"17#include "llvm/MCA/Support.h"18#include "llvm/Support/Format.h"19 20namespace llvm {21namespace mca {22 23#define DEBUG_TYPE "llvm-mca"24 25PressureTracker::PressureTracker(const MCSchedModel &Model)26    : SM(Model),27      ResourcePressureDistribution(Model.getNumProcResourceKinds(), 0),28      ProcResID2Mask(Model.getNumProcResourceKinds(), 0),29      ResIdx2ProcResID(Model.getNumProcResourceKinds(), 0),30      ProcResID2ResourceUsersIndex(Model.getNumProcResourceKinds(), 0) {31  computeProcResourceMasks(SM, ProcResID2Mask);32 33  // Ignore the invalid resource at index zero.34  unsigned NextResourceUsersIdx = 0;35  for (unsigned I = 1, E = Model.getNumProcResourceKinds(); I < E; ++I) {36    const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);37    ProcResID2ResourceUsersIndex[I] = NextResourceUsersIdx;38    NextResourceUsersIdx += ProcResource.NumUnits;39    uint64_t ResourceMask = ProcResID2Mask[I];40    ResIdx2ProcResID[getResourceStateIndex(ResourceMask)] = I;41  }42 43  ResourceUsers.resize(NextResourceUsersIdx);44  llvm::fill(ResourceUsers, std::make_pair<unsigned, unsigned>(~0U, 0U));45}46 47void PressureTracker::getResourceUsers(uint64_t ResourceMask,48                                       SmallVectorImpl<User> &Users) const {49  unsigned Index = getResourceStateIndex(ResourceMask);50  unsigned ProcResID = ResIdx2ProcResID[Index];51  const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID);52  for (unsigned I = 0, E = PRDesc.NumUnits; I < E; ++I) {53    const User U = getResourceUser(ProcResID, I);54    if (U.second && IPI.contains(U.first))55      Users.emplace_back(U);56  }57}58 59void PressureTracker::onInstructionDispatched(unsigned IID) {60  IPI.try_emplace(IID);61}62 63void PressureTracker::onInstructionExecuted(unsigned IID) { IPI.erase(IID); }64 65void PressureTracker::handleInstructionIssuedEvent(66    const HWInstructionIssuedEvent &Event) {67  unsigned IID = Event.IR.getSourceIndex();68  for (const ResourceUse &Use : Event.UsedResources) {69    const ResourceRef &RR = Use.first;70    unsigned Index = ProcResID2ResourceUsersIndex[RR.first];71    Index += llvm::countr_zero(RR.second);72    ResourceUsers[Index] = std::make_pair(IID, Use.second.getNumerator());73  }74}75 76void PressureTracker::updateResourcePressureDistribution(77    uint64_t CumulativeMask) {78  while (CumulativeMask) {79    uint64_t Current = CumulativeMask & (-CumulativeMask);80    unsigned ResIdx = getResourceStateIndex(Current);81    unsigned ProcResID = ResIdx2ProcResID[ResIdx];82    uint64_t Mask = ProcResID2Mask[ProcResID];83 84    if (Mask == Current) {85      ResourcePressureDistribution[ProcResID]++;86      CumulativeMask ^= Current;87      continue;88    }89 90    Mask ^= Current;91    while (Mask) {92      uint64_t SubUnit = Mask & (-Mask);93      ResIdx = getResourceStateIndex(SubUnit);94      ProcResID = ResIdx2ProcResID[ResIdx];95      ResourcePressureDistribution[ProcResID]++;96      Mask ^= SubUnit;97    }98 99    CumulativeMask ^= Current;100  }101}102 103void PressureTracker::handlePressureEvent(const HWPressureEvent &Event) {104  assert(Event.Reason != HWPressureEvent::INVALID &&105         "Unexpected invalid event!");106 107  switch (Event.Reason) {108  default:109    break;110 111  case HWPressureEvent::RESOURCES: {112    const uint64_t ResourceMask = Event.ResourceMask;113    updateResourcePressureDistribution(Event.ResourceMask);114 115    for (const InstRef &IR : Event.AffectedInstructions) {116      const Instruction &IS = *IR.getInstruction();117      unsigned BusyResources = IS.getCriticalResourceMask() & ResourceMask;118      if (!BusyResources)119        continue;120 121      unsigned IID = IR.getSourceIndex();122      IPI[IID].ResourcePressureCycles++;123    }124    break;125  }126 127  case HWPressureEvent::REGISTER_DEPS:128    for (const InstRef &IR : Event.AffectedInstructions) {129      unsigned IID = IR.getSourceIndex();130      IPI[IID].RegisterPressureCycles++;131    }132    break;133 134  case HWPressureEvent::MEMORY_DEPS:135    for (const InstRef &IR : Event.AffectedInstructions) {136      unsigned IID = IR.getSourceIndex();137      IPI[IID].MemoryPressureCycles++;138    }139  }140}141 142#ifndef NDEBUG143void DependencyGraph::dumpDependencyEdge(raw_ostream &OS,144                                         const DependencyEdge &DepEdge,145                                         MCInstPrinter &MCIP) const {146  unsigned FromIID = DepEdge.FromIID;147  unsigned ToIID = DepEdge.ToIID;148  assert(FromIID < ToIID && "Graph should be acyclic!");149 150  const DependencyEdge::Dependency &DE = DepEdge.Dep;151  assert(DE.Type != DependencyEdge::DT_INVALID && "Unexpected invalid edge!");152 153  OS << " FROM: " << FromIID << " TO: " << ToIID << "             ";154  if (DE.Type == DependencyEdge::DT_REGISTER) {155    OS << " - REGISTER: ";156    MCIP.printRegName(OS, DE.ResourceOrRegID);157  } else if (DE.Type == DependencyEdge::DT_MEMORY) {158    OS << " - MEMORY";159  } else {160    assert(DE.Type == DependencyEdge::DT_RESOURCE &&161           "Unsupported dependency type!");162    OS << " - RESOURCE MASK: " << DE.ResourceOrRegID;163  }164  OS << " - COST: " << DE.Cost << '\n';165}166#endif // NDEBUG167 168void DependencyGraph::pruneEdges(unsigned Iterations) {169  for (DGNode &N : Nodes) {170    unsigned NumPruned = 0;171    const unsigned Size = N.OutgoingEdges.size();172    // Use a cut-off threshold to prune edges with a low frequency.173    for (unsigned I = 0, E = Size; I < E; ++I) {174      DependencyEdge &Edge = N.OutgoingEdges[I];175      if (Edge.Frequency == Iterations)176        continue;177      double Factor = (double)Edge.Frequency / Iterations;178      if (0.10 < Factor)179        continue;180      Nodes[Edge.ToIID].NumPredecessors--;181      std::swap(Edge, N.OutgoingEdges[E - 1]);182      --E;183      ++NumPruned;184    }185 186    if (NumPruned)187      N.OutgoingEdges.resize(Size - NumPruned);188  }189}190 191void DependencyGraph::initializeRootSet(192    SmallVectorImpl<unsigned> &RootSet) const {193  for (unsigned I = 0, E = Nodes.size(); I < E; ++I) {194    const DGNode &N = Nodes[I];195    if (N.NumPredecessors == 0 && !N.OutgoingEdges.empty())196      RootSet.emplace_back(I);197  }198}199 200void DependencyGraph::propagateThroughEdges(SmallVectorImpl<unsigned> &RootSet,201                                            unsigned Iterations) {202  SmallVector<unsigned, 8> ToVisit;203 204  // A critical sequence is computed as the longest path from a node of the205  // RootSet to a leaf node (i.e. a node with no successors).  The RootSet is206  // composed of nodes with at least one successor, and no predecessors.207  //208  // Each node of the graph starts with an initial default cost of zero.  The209  // cost of a node is a measure of criticality: the higher the cost, the bigger210  // is the performance impact.211  // For register and memory dependencies, the cost is a function of the write212  // latency as well as the actual delay (in cycles) caused to users.213  // For processor resource dependencies, the cost is a function of the resource214  // pressure. Resource interferences with low frequency values are ignored.215  //216  // This algorithm is very similar to a (reverse) Dijkstra.  Every iteration of217  // the inner loop selects (i.e. visits) a node N from a set of `unvisited218  // nodes`, and then propagates the cost of N to all its neighbors.219  //220  // The `unvisited nodes` set initially contains all the nodes from the221  // RootSet.  A node N is added to the `unvisited nodes` if all its222  // predecessors have been visited already.223  //224  // For simplicity, every node tracks the number of unvisited incoming edges in225  // field `NumVisitedPredecessors`.  When the value of that field drops to226  // zero, then the corresponding node is added to a `ToVisit` set.227  //228  // At the end of every iteration of the outer loop, set `ToVisit` becomes our229  // new `unvisited nodes` set.230  //231  // The algorithm terminates when the set of unvisited nodes (i.e. our RootSet)232  // is empty. This algorithm works under the assumption that the graph is233  // acyclic.234  do {235    for (unsigned IID : RootSet) {236      const DGNode &N = Nodes[IID];237      for (const DependencyEdge &DepEdge : N.OutgoingEdges) {238        unsigned ToIID = DepEdge.ToIID;239        DGNode &To = Nodes[ToIID];240        uint64_t Cost = N.Cost + DepEdge.Dep.Cost;241        // Check if this is the most expensive incoming edge seen so far.  In242        // case, update the total cost of the destination node (ToIID), as well243        // its field `CriticalPredecessor`.244        if (Cost > To.Cost) {245          To.CriticalPredecessor = DepEdge;246          To.Cost = Cost;247          To.Depth = N.Depth + 1;248        }249        To.NumVisitedPredecessors++;250        if (To.NumVisitedPredecessors == To.NumPredecessors)251          ToVisit.emplace_back(ToIID);252      }253    }254 255    std::swap(RootSet, ToVisit);256    ToVisit.clear();257  } while (!RootSet.empty());258}259 260void DependencyGraph::getCriticalSequence(261    SmallVectorImpl<const DependencyEdge *> &Seq) const {262  // At this stage, nodes of the graph have been already visited, and costs have263  // been propagated through the edges (see method `propagateThroughEdges()`).264 265  // Identify the node N with the highest cost in the graph. By construction,266  // that node is the last instruction of our critical sequence.267  // Field N.Depth would tell us the total length of the sequence.268  //269  // To obtain the sequence of critical edges, we simply follow the chain of270  // critical predecessors starting from node N (field271  // DGNode::CriticalPredecessor).272  const auto It =273      llvm::max_element(Nodes, [](const DGNode &Lhs, const DGNode &Rhs) {274        return Lhs.Cost < Rhs.Cost;275      });276  unsigned IID = std::distance(Nodes.begin(), It);277  Seq.resize(Nodes[IID].Depth);278  for (const DependencyEdge *&DE : llvm::reverse(Seq)) {279    const DGNode &N = Nodes[IID];280    DE = &N.CriticalPredecessor;281    IID = N.CriticalPredecessor.FromIID;282  }283}284 285void BottleneckAnalysis::printInstruction(formatted_raw_ostream &FOS,286                                          const MCInst &MCI,287                                          bool UseDifferentColor) const {288  FOS.PadToColumn(14);289  if (UseDifferentColor)290    FOS.changeColor(raw_ostream::CYAN, true, false);291  FOS << printInstructionString(MCI);292  if (UseDifferentColor)293    FOS.resetColor();294}295 296void BottleneckAnalysis::printCriticalSequence(raw_ostream &OS) const {297  // Early exit if no bottlenecks were found during the simulation.298  if (!SeenStallCycles || !BPI.PressureIncreaseCycles)299    return;300 301  SmallVector<const DependencyEdge *, 16> Seq;302  DG.getCriticalSequence(Seq);303  if (Seq.empty())304    return;305 306  OS << "\nCritical sequence based on the simulation:\n\n";307 308  const DependencyEdge &FirstEdge = *Seq[0];309  ArrayRef<llvm::MCInst> Source = getSource();310  unsigned FromIID = FirstEdge.FromIID % Source.size();311  unsigned ToIID = FirstEdge.ToIID % Source.size();312  bool IsLoopCarried = FromIID >= ToIID;313 314  formatted_raw_ostream FOS(OS);315  FOS.PadToColumn(14);316  FOS << "Instruction";317  FOS.PadToColumn(58);318  FOS << "Dependency Information";319 320  bool HasColors = FOS.has_colors();321 322  unsigned CurrentIID = 0;323  if (IsLoopCarried) {324    FOS << "\n +----< " << FromIID << ".";325    printInstruction(FOS, Source[FromIID], HasColors);326    FOS << "\n |\n |    < loop carried > \n |";327  } else {328    while (CurrentIID < FromIID) {329      FOS << "\n        " << CurrentIID << ".";330      printInstruction(FOS, Source[CurrentIID]);331      CurrentIID++;332    }333 334    FOS << "\n +----< " << CurrentIID << ".";335    printInstruction(FOS, Source[CurrentIID], HasColors);336    CurrentIID++;337  }338 339  for (const DependencyEdge *&DE : Seq) {340    ToIID = DE->ToIID % Source.size();341    unsigned LastIID = CurrentIID > ToIID ? Source.size() : ToIID;342 343    while (CurrentIID < LastIID) {344      FOS << "\n |      " << CurrentIID << ".";345      printInstruction(FOS, Source[CurrentIID]);346      CurrentIID++;347    }348 349    if (CurrentIID == ToIID) {350      FOS << "\n +----> " << ToIID << ".";351      printInstruction(FOS, Source[CurrentIID], HasColors);352    } else {353      FOS << "\n |\n |    < loop carried > \n |"354          << "\n +----> " << ToIID << ".";355      printInstruction(FOS, Source[ToIID], HasColors);356    }357    FOS.PadToColumn(58);358 359    const DependencyEdge::Dependency &Dep = DE->Dep;360    if (HasColors)361      FOS.changeColor(raw_ostream::SAVEDCOLOR, true, false);362 363    if (Dep.Type == DependencyEdge::DT_REGISTER) {364      FOS << "## REGISTER dependency:  ";365      if (HasColors)366        FOS.changeColor(raw_ostream::MAGENTA, true, false);367      getInstPrinter().printRegName(FOS, Dep.ResourceOrRegID);368    } else if (Dep.Type == DependencyEdge::DT_MEMORY) {369      FOS << "## MEMORY dependency.";370    } else {371      assert(Dep.Type == DependencyEdge::DT_RESOURCE &&372             "Unsupported dependency type!");373      FOS << "## RESOURCE interference:  ";374      if (HasColors)375        FOS.changeColor(raw_ostream::MAGENTA, true, false);376      FOS << Tracker.resolveResourceName(Dep.ResourceOrRegID);377      if (HasColors) {378        FOS.resetColor();379        FOS.changeColor(raw_ostream::SAVEDCOLOR, true, false);380      }381      FOS << " [ probability: " << ((DE->Frequency * 100) / Iterations)382          << "% ]";383    }384    if (HasColors)385      FOS.resetColor();386    ++CurrentIID;387  }388 389  while (CurrentIID < Source.size()) {390    FOS << "\n        " << CurrentIID << ".";391    printInstruction(FOS, Source[CurrentIID]);392    CurrentIID++;393  }394 395  FOS << '\n';396  FOS.flush();397}398 399#ifndef NDEBUG400void DependencyGraph::dump(raw_ostream &OS, MCInstPrinter &MCIP) const {401  OS << "\nREG DEPS\n";402  for (const DGNode &Node : Nodes)403    for (const DependencyEdge &DE : Node.OutgoingEdges)404      if (DE.Dep.Type == DependencyEdge::DT_REGISTER)405        dumpDependencyEdge(OS, DE, MCIP);406 407  OS << "\nMEM DEPS\n";408  for (const DGNode &Node : Nodes)409    for (const DependencyEdge &DE : Node.OutgoingEdges)410      if (DE.Dep.Type == DependencyEdge::DT_MEMORY)411        dumpDependencyEdge(OS, DE, MCIP);412 413  OS << "\nRESOURCE DEPS\n";414  for (const DGNode &Node : Nodes)415    for (const DependencyEdge &DE : Node.OutgoingEdges)416      if (DE.Dep.Type == DependencyEdge::DT_RESOURCE)417        dumpDependencyEdge(OS, DE, MCIP);418}419#endif // NDEBUG420 421void DependencyGraph::addDependency(unsigned From, unsigned To,422                                    DependencyEdge::Dependency &&Dep) {423  DGNode &NodeFrom = Nodes[From];424  DGNode &NodeTo = Nodes[To];425  SmallVectorImpl<DependencyEdge> &Vec = NodeFrom.OutgoingEdges;426 427  auto It = find_if(Vec, [To, Dep](DependencyEdge &DE) {428    return DE.ToIID == To && DE.Dep.ResourceOrRegID == Dep.ResourceOrRegID;429  });430 431  if (It != Vec.end()) {432    It->Dep.Cost += Dep.Cost;433    It->Frequency++;434    return;435  }436 437  DependencyEdge DE = {Dep, From, To, 1};438  Vec.emplace_back(DE);439  NodeTo.NumPredecessors++;440}441 442BottleneckAnalysis::BottleneckAnalysis(const MCSubtargetInfo &sti,443                                       MCInstPrinter &Printer,444                                       ArrayRef<MCInst> S, unsigned NumIter)445    : InstructionView(sti, Printer, S), Tracker(sti.getSchedModel()),446      DG(S.size() * 3), Iterations(NumIter), TotalCycles(0),447      PressureIncreasedBecauseOfResources(false),448      PressureIncreasedBecauseOfRegisterDependencies(false),449      PressureIncreasedBecauseOfMemoryDependencies(false),450      SeenStallCycles(false), BPI() {}451 452void BottleneckAnalysis::addRegisterDep(unsigned From, unsigned To,453                                        unsigned RegID, unsigned Cost) {454  bool IsLoopCarried = From >= To;455  unsigned SourceSize = getSource().size();456  if (IsLoopCarried) {457    DG.addRegisterDep(From, To + SourceSize, RegID, Cost);458    DG.addRegisterDep(From + SourceSize, To + (SourceSize * 2), RegID, Cost);459    return;460  }461  DG.addRegisterDep(From + SourceSize, To + SourceSize, RegID, Cost);462}463 464void BottleneckAnalysis::addMemoryDep(unsigned From, unsigned To,465                                      unsigned Cost) {466  bool IsLoopCarried = From >= To;467  unsigned SourceSize = getSource().size();468  if (IsLoopCarried) {469    DG.addMemoryDep(From, To + SourceSize, Cost);470    DG.addMemoryDep(From + SourceSize, To + (SourceSize * 2), Cost);471    return;472  }473  DG.addMemoryDep(From + SourceSize, To + SourceSize, Cost);474}475 476void BottleneckAnalysis::addResourceDep(unsigned From, unsigned To,477                                        uint64_t Mask, unsigned Cost) {478  bool IsLoopCarried = From >= To;479  unsigned SourceSize = getSource().size();480  if (IsLoopCarried) {481    DG.addResourceDep(From, To + SourceSize, Mask, Cost);482    DG.addResourceDep(From + SourceSize, To + (SourceSize * 2), Mask, Cost);483    return;484  }485  DG.addResourceDep(From + SourceSize, To + SourceSize, Mask, Cost);486}487 488void BottleneckAnalysis::onEvent(const HWInstructionEvent &Event) {489  const unsigned IID = Event.IR.getSourceIndex();490  if (Event.Type == HWInstructionEvent::Dispatched) {491    Tracker.onInstructionDispatched(IID);492    return;493  }494  if (Event.Type == HWInstructionEvent::Executed) {495    Tracker.onInstructionExecuted(IID);496    return;497  }498 499  if (Event.Type != HWInstructionEvent::Issued)500    return;501 502  ArrayRef<llvm::MCInst> Source = getSource();503  const Instruction &IS = *Event.IR.getInstruction();504  unsigned To = IID % Source.size();505 506  unsigned Cycles = 2 * Tracker.getResourcePressureCycles(IID);507  uint64_t ResourceMask = IS.getCriticalResourceMask();508  SmallVector<std::pair<unsigned, unsigned>, 4> Users;509  while (ResourceMask) {510    uint64_t Current = ResourceMask & (-ResourceMask);511    Tracker.getResourceUsers(Current, Users);512    for (const std::pair<unsigned, unsigned> &U : Users)513      addResourceDep(U.first % Source.size(), To, Current, U.second + Cycles);514    Users.clear();515    ResourceMask ^= Current;516  }517 518  const CriticalDependency &RegDep = IS.getCriticalRegDep();519  if (RegDep.Cycles) {520    Cycles = RegDep.Cycles + 2 * Tracker.getRegisterPressureCycles(IID);521    unsigned From = RegDep.IID % Source.size();522    addRegisterDep(From, To, RegDep.RegID, Cycles);523  }524 525  const CriticalDependency &MemDep = IS.getCriticalMemDep();526  if (MemDep.Cycles) {527    Cycles = MemDep.Cycles + 2 * Tracker.getMemoryPressureCycles(IID);528    unsigned From = MemDep.IID % Source.size();529    addMemoryDep(From, To, Cycles);530  }531 532  Tracker.handleInstructionIssuedEvent(533      static_cast<const HWInstructionIssuedEvent &>(Event));534 535  // Check if this is the last simulated instruction.536  if (IID == ((Iterations * Source.size()) - 1))537    DG.finalizeGraph(Iterations);538}539 540void BottleneckAnalysis::onEvent(const HWPressureEvent &Event) {541  assert(Event.Reason != HWPressureEvent::INVALID &&542         "Unexpected invalid event!");543 544  Tracker.handlePressureEvent(Event);545 546  switch (Event.Reason) {547  default:548    break;549 550  case HWPressureEvent::RESOURCES:551    PressureIncreasedBecauseOfResources = true;552    break;553  case HWPressureEvent::REGISTER_DEPS:554    PressureIncreasedBecauseOfRegisterDependencies = true;555    break;556  case HWPressureEvent::MEMORY_DEPS:557    PressureIncreasedBecauseOfMemoryDependencies = true;558    break;559  }560}561 562void BottleneckAnalysis::onCycleEnd() {563  ++TotalCycles;564 565  bool PressureIncreasedBecauseOfDataDependencies =566      PressureIncreasedBecauseOfRegisterDependencies ||567      PressureIncreasedBecauseOfMemoryDependencies;568  if (!PressureIncreasedBecauseOfResources &&569      !PressureIncreasedBecauseOfDataDependencies)570    return;571 572  ++BPI.PressureIncreaseCycles;573  if (PressureIncreasedBecauseOfRegisterDependencies)574    ++BPI.RegisterDependencyCycles;575  if (PressureIncreasedBecauseOfMemoryDependencies)576    ++BPI.MemoryDependencyCycles;577  if (PressureIncreasedBecauseOfDataDependencies)578    ++BPI.DataDependencyCycles;579  if (PressureIncreasedBecauseOfResources)580    ++BPI.ResourcePressureCycles;581  PressureIncreasedBecauseOfResources = false;582  PressureIncreasedBecauseOfRegisterDependencies = false;583  PressureIncreasedBecauseOfMemoryDependencies = false;584}585 586void BottleneckAnalysis::printBottleneckHints(raw_ostream &OS) const {587  if (!SeenStallCycles || !BPI.PressureIncreaseCycles) {588    OS << "\n\nNo resource or data dependency bottlenecks discovered.\n";589    return;590  }591 592  double PressurePerCycle =593      (double)BPI.PressureIncreaseCycles * 100 / TotalCycles;594  double ResourcePressurePerCycle =595      (double)BPI.ResourcePressureCycles * 100 / TotalCycles;596  double DDPerCycle = (double)BPI.DataDependencyCycles * 100 / TotalCycles;597  double RegDepPressurePerCycle =598      (double)BPI.RegisterDependencyCycles * 100 / TotalCycles;599  double MemDepPressurePerCycle =600      (double)BPI.MemoryDependencyCycles * 100 / TotalCycles;601 602  OS << "\n\nCycles with backend pressure increase [ "603     << format("%.2f", floor((PressurePerCycle * 100) + 0.5) / 100) << "% ]";604 605  OS << "\nThroughput Bottlenecks: "606     << "\n  Resource Pressure       [ "607     << format("%.2f", floor((ResourcePressurePerCycle * 100) + 0.5) / 100)608     << "% ]";609 610  if (BPI.PressureIncreaseCycles) {611    ArrayRef<unsigned> Distribution = Tracker.getResourcePressureDistribution();612    const MCSchedModel &SM = getSubTargetInfo().getSchedModel();613    for (unsigned I = 0, E = Distribution.size(); I < E; ++I) {614      unsigned ReleaseAtCycles = Distribution[I];615      if (ReleaseAtCycles) {616        double Frequency = (double)ReleaseAtCycles * 100 / TotalCycles;617        const MCProcResourceDesc &PRDesc = *SM.getProcResource(I);618        OS << "\n  - " << PRDesc.Name << "  [ "619           << format("%.2f", floor((Frequency * 100) + 0.5) / 100) << "% ]";620      }621    }622  }623 624  OS << "\n  Data Dependencies:      [ "625     << format("%.2f", floor((DDPerCycle * 100) + 0.5) / 100) << "% ]";626  OS << "\n  - Register Dependencies [ "627     << format("%.2f", floor((RegDepPressurePerCycle * 100) + 0.5) / 100)628     << "% ]";629  OS << "\n  - Memory Dependencies   [ "630     << format("%.2f", floor((MemDepPressurePerCycle * 100) + 0.5) / 100)631     << "% ]\n";632}633 634void BottleneckAnalysis::printView(raw_ostream &OS) const {635  std::string Buffer;636  raw_string_ostream TempStream(Buffer);637  printBottleneckHints(TempStream);638  TempStream.flush();639  OS << Buffer;640  printCriticalSequence(OS);641}642 643json::Value BottleneckAnalysis::toJSON() const {644  if (!SeenStallCycles || !BPI.PressureIncreaseCycles) {645    json::Object JO({{"PressureIncreaseCycles", 0}});646    return JO;647  }648 649  json::Array CriticalSequence;650  // get critical sequence651  SmallVector<const DependencyEdge *, 16> Seq;652  DG.getCriticalSequence(Seq);653  if (!Seq.empty()) {654    for (const DependencyEdge *&DE : Seq) {655      json::Object DEJO({{"FromID", DE->FromIID},656                         {"ToID", DE->ToIID},657                         {"Type", static_cast<unsigned>(DE->Dep.Type)},658                         {"ResourceOrRegID", DE->Dep.ResourceOrRegID}});659      CriticalSequence.push_back(std::move(DEJO));660    }661  }662 663  json::Array ResourcePressure;664  if (BPI.PressureIncreaseCycles) {665    ArrayRef<unsigned> Distribution = Tracker.getResourcePressureDistribution();666    const MCSchedModel &SM = getSubTargetInfo().getSchedModel();667    for (unsigned I = 0, E = Distribution.size(); I < E; ++I) {668      unsigned ReleaseAtCycles = Distribution[I];669      if (ReleaseAtCycles) {670        const MCProcResourceDesc &PRDesc = *SM.getProcResource(I);671        json::Object RPJO({{PRDesc.Name, ReleaseAtCycles}});672        ResourcePressure.push_back(std::move(RPJO));673      }674    }675  }676 677  json::Object JO({{"PressureIncreaseCycles", BPI.PressureIncreaseCycles},678                   {"ResourcePressureCycles", BPI.ResourcePressureCycles},679                   {"DataDependencyCycles", BPI.DataDependencyCycles},680                   {"RegisterDependencyCycles", BPI.RegisterDependencyCycles},681                   {"MemoryDependencyCycles", BPI.MemoryDependencyCycles},682                   {"TotalCycles", TotalCycles},683                   {"DependencyEdge", std::move(CriticalSequence)},684                   {"ResourcePressure", std::move(ResourcePressure)}});685 686  return JO;687}688 689} // namespace mca.690} // namespace llvm691