[llvm] r362933 - [MCA] Further refactor the bottleneck analysis view. NFCI.

Andrea Di Biagio via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 10 05:50:08 PDT 2019


Author: adibiagio
Date: Mon Jun 10 05:50:08 2019
New Revision: 362933

URL: http://llvm.org/viewvc/llvm-project?rev=362933&view=rev
Log:
[MCA] Further refactor the bottleneck analysis view. NFCI.

Modified:
    llvm/trunk/lib/MCA/HardwareUnits/Scheduler.cpp
    llvm/trunk/tools/llvm-mca/Views/BottleneckAnalysis.cpp
    llvm/trunk/tools/llvm-mca/Views/BottleneckAnalysis.h
    llvm/trunk/tools/llvm-mca/llvm-mca.cpp

Modified: llvm/trunk/lib/MCA/HardwareUnits/Scheduler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MCA/HardwareUnits/Scheduler.cpp?rev=362933&r1=362932&r2=362933&view=diff
==============================================================================
--- llvm/trunk/lib/MCA/HardwareUnits/Scheduler.cpp (original)
+++ llvm/trunk/lib/MCA/HardwareUnits/Scheduler.cpp Mon Jun 10 05:50:08 2019
@@ -198,7 +198,8 @@ InstRef Scheduler::select() {
         Strategy->compare(IR, ReadySet[QueueIndex])) {
       Instruction &IS = *IR.getInstruction();
       uint64_t BusyResourceMask = Resources->checkAvailability(IS.getDesc());
-      IS.setCriticalResourceMask(BusyResourceMask);
+      if (BusyResourceMask)
+        IS.setCriticalResourceMask(BusyResourceMask);
       BusyResourceUnits |= BusyResourceMask;
       if (!BusyResourceMask)
         QueueIndex = I;

Modified: llvm/trunk/tools/llvm-mca/Views/BottleneckAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/Views/BottleneckAnalysis.cpp?rev=362933&r1=362932&r2=362933&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/Views/BottleneckAnalysis.cpp (original)
+++ llvm/trunk/tools/llvm-mca/Views/BottleneckAnalysis.cpp Mon Jun 10 05:50:08 2019
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Views/BottleneckAnalysis.h"
+#include "llvm/MC/MCInst.h"
 #include "llvm/MCA/Support.h"
 #include "llvm/Support/Format.h"
 
@@ -40,43 +41,38 @@ PressureTracker::PressureTracker(const M
   }
 
   ResourceUsers.resize(NextResourceUsersIdx);
-  std::fill(ResourceUsers.begin(), ResourceUsers.end(), ~0U);
+  std::fill(ResourceUsers.begin(), ResourceUsers.end(),
+            std::make_pair<unsigned, unsigned>(~0U, 0U));
 }
 
-void PressureTracker::getUniqueUsers(
-    uint64_t ResourceMask, SmallVectorImpl<unsigned> &UniqueUsers) const {
+void PressureTracker::getResourceUsers(uint64_t ResourceMask,
+                                       SmallVectorImpl<User> &Users) const {
   unsigned Index = getResourceStateIndex(ResourceMask);
   unsigned ProcResID = ResIdx2ProcResID[Index];
   const MCProcResourceDesc &PRDesc = *SM.getProcResource(ProcResID);
   for (unsigned I = 0, E = PRDesc.NumUnits; I < E; ++I) {
-    unsigned From = getResourceUser(ProcResID, I);
-    if (find(UniqueUsers, From) == UniqueUsers.end())
-      UniqueUsers.emplace_back(From);
+    const User U = getResourceUser(ProcResID, I);
+    if (U.second && IPI.find(U.first) != IPI.end())
+      Users.emplace_back(U);
   }
 }
 
-void PressureTracker::handleInstructionEvent(const HWInstructionEvent &Event) {
+void PressureTracker::onInstructionDispatched(unsigned IID) {
+  IPI.insert(std::make_pair(IID, InstructionPressureInfo()));
+}
+
+void PressureTracker::onInstructionExecuted(unsigned IID) { IPI.erase(IID); }
+
+void PressureTracker::handleInstructionIssuedEvent(
+    const HWInstructionIssuedEvent &Event) {
   unsigned IID = Event.IR.getSourceIndex();
-  switch (Event.Type) {
-  default:
-    break;
-  case HWInstructionEvent::Dispatched:
-    IPI.insert(std::make_pair(IID, InstructionPressureInfo()));
-    break;
-  case HWInstructionEvent::Executed:
-    IPI.erase(IID);
-    break;
-  case HWInstructionEvent::Issued: {
-    const auto &IIE = static_cast<const HWInstructionIssuedEvent &>(Event);
-    using ResourceRef = HWInstructionIssuedEvent::ResourceRef;
-    using ResourceUse = std::pair<ResourceRef, ResourceCycles>;
-    for (const ResourceUse &Use : IIE.UsedResources) {
-      const ResourceRef &RR = Use.first;
-      unsigned Index = ProcResID2ResourceUsersIndex[RR.first];
-      Index += countTrailingZeros(RR.second);
-      ResourceUsers[Index] = IID;
-    }
-  }
+  using ResourceRef = HWInstructionIssuedEvent::ResourceRef;
+  using ResourceUse = std::pair<ResourceRef, ResourceCycles>;
+  for (const ResourceUse &Use : Event.UsedResources) {
+    const ResourceRef &RR = Use.first;
+    unsigned Index = ProcResID2ResourceUsersIndex[RR.first];
+    Index += countTrailingZeros(RR.second);
+    ResourceUsers[Index] = std::make_pair(IID, Use.second.getNumerator());
   }
 }
 
@@ -125,7 +121,8 @@ void PressureTracker::handlePressureEven
       if (!BusyResources)
         continue;
 
-      IPI[IR.getSourceIndex()].ResourcePressureCycles++;
+      unsigned IID = IR.getSourceIndex();
+      IPI[IID].ResourcePressureCycles++;
     }
     break;
   }
@@ -146,51 +143,59 @@ void PressureTracker::handlePressureEven
 }
 
 #ifndef NDEBUG
-void DependencyGraph::dumpRegDeps(raw_ostream &OS, MCInstPrinter &MCIP) const {
+void DependencyGraph::dumpDependencyEdge(raw_ostream &OS, unsigned FromIID,
+                                         const DependencyEdge &DE,
+                                         MCInstPrinter &MCIP) const {
+  bool LoopCarried = FromIID >= DE.IID;
+  OS << " FROM: " << FromIID << " TO: " << DE.IID
+     << (LoopCarried ? " (loop carried)" : "             ");
+  if (DE.Type == DT_REGISTER) {
+    OS << " - REGISTER: ";
+    MCIP.printRegName(OS, DE.ResourceOrRegID);
+  } else if (DE.Type == DT_MEMORY) {
+    OS << " - MEMORY";
+  } else {
+    assert(DE.Type == DT_RESOURCE && "Unexpected unsupported dependency type!");
+    OS << " - RESOURCE MASK: " << DE.ResourceOrRegID;
+  }
+  OS << " - CYCLES: " << DE.Cycles << '\n';
+}
+
+void DependencyGraph::dump(raw_ostream &OS, MCInstPrinter &MCIP) const {
   OS << "\nREG DEPS\n";
   for (unsigned I = 0, E = Nodes.size(); I < E; ++I) {
     const DGNode &Node = Nodes[I];
-    for (const DependencyEdge &DE : Node.RegDeps) {
-      bool LoopCarried = I >= DE.IID;
-      OS << " FROM: " << I << " TO: " << DE.IID
-         << (LoopCarried ? " (loop carried)" : "             ")
-         << " - REGISTER: ";
-      MCIP.printRegName(OS, DE.ResourceOrRegID);
-      OS << " - CYCLES: " << DE.Cycles << '\n';
+    for (const DependencyEdge &DE : Node.OutgoingEdges) {
+      if (DE.Type == DT_REGISTER)
+        dumpDependencyEdge(OS, I, DE, MCIP);
     }
   }
-}
 
-void DependencyGraph::dumpMemDeps(raw_ostream &OS) const {
   OS << "\nMEM DEPS\n";
   for (unsigned I = 0, E = Nodes.size(); I < E; ++I) {
     const DGNode &Node = Nodes[I];
-    for (const DependencyEdge &DE : Node.MemDeps) {
-      bool LoopCarried = I >= DE.IID;
-      OS << " FROM: " << I << " TO: " << DE.IID
-         << (LoopCarried ? " (loop carried)" : "             ")
-         << " - MEMORY - CYCLES: " << DE.Cycles << '\n';
+    for (const DependencyEdge &DE : Node.OutgoingEdges) {
+      if (DE.Type == DT_MEMORY)
+        dumpDependencyEdge(OS, I, DE, MCIP);
     }
   }
-}
 
-void DependencyGraph::dumpResDeps(raw_ostream &OS) const {
   OS << "\nRESOURCE DEPS\n";
   for (unsigned I = 0, E = Nodes.size(); I < E; ++I) {
     const DGNode &Node = Nodes[I];
-    for (const DependencyEdge &DE : Node.ResDeps) {
-      bool LoopCarried = I >= DE.IID;
-      OS << " FROM: " << I << " TO: " << DE.IID
-         << (LoopCarried ? "(loop carried)" : "             ")
-         << " - RESOURCE MASK: " << DE.ResourceOrRegID;
-      OS << " - CYCLES: " << DE.Cycles << '\n';
+    for (const DependencyEdge &DE : Node.OutgoingEdges) {
+      if (DE.Type == DT_RESOURCE)
+        dumpDependencyEdge(OS, I, DE, MCIP);
     }
   }
 }
 #endif // NDEBUG
 
-void DependencyGraph::addDepImpl(SmallVectorImpl<DependencyEdge> &Vec,
-                                 DependencyEdge &&Dep) {
+void DependencyGraph::addDependency(unsigned From, DependencyEdge &&Dep) {
+  DGNode &NodeFrom = Nodes[From];
+  DGNode &NodeTo = Nodes[Dep.IID];
+  SmallVectorImpl<DependencyEdge> &Vec = NodeFrom.OutgoingEdges;
+
   auto It = find_if(Vec, [Dep](DependencyEdge &DE) {
     return DE.IID == Dep.IID && DE.ResourceOrRegID == Dep.ResourceOrRegID;
   });
@@ -201,38 +206,102 @@ void DependencyGraph::addDepImpl(SmallVe
   }
 
   Vec.emplace_back(Dep);
-  Nodes[Dep.IID].NumPredecessors++;
+  NodeTo.NumPredecessors++;
 }
 
 BottleneckAnalysis::BottleneckAnalysis(const MCSubtargetInfo &sti,
-                                       ArrayRef<MCInst> Sequence)
-    : STI(sti), Tracker(STI.getSchedModel()), DG(Sequence.size()),
-      Source(Sequence), TotalCycles(0),
-      PressureIncreasedBecauseOfResources(false),
+                                       MCInstPrinter &Printer,
+                                       ArrayRef<MCInst> S)
+    : STI(sti), MCIP(Printer), Tracker(STI.getSchedModel()), DG(S.size() * 3),
+      Source(S), TotalCycles(0), PressureIncreasedBecauseOfResources(false),
       PressureIncreasedBecauseOfRegisterDependencies(false),
       PressureIncreasedBecauseOfMemoryDependencies(false),
       SeenStallCycles(false), BPI() {}
 
+void BottleneckAnalysis::addRegisterDep(unsigned From, unsigned To,
+                                        unsigned RegID, unsigned Cy) {
+  bool IsLoopCarried = From >= To;
+  unsigned SourceSize = Source.size();
+  if (IsLoopCarried) {
+    DG.addRegisterDep(From, To + SourceSize, RegID, Cy);
+    DG.addRegisterDep(From + SourceSize, To + (SourceSize * 2), RegID, Cy);
+    return;
+  }
+  DG.addRegisterDep(From + SourceSize, To + SourceSize, RegID, Cy);
+}
+
+void BottleneckAnalysis::addMemoryDep(unsigned From, unsigned To, unsigned Cy) {
+  bool IsLoopCarried = From >= To;
+  unsigned SourceSize = Source.size();
+  if (IsLoopCarried) {
+    DG.addMemoryDep(From, To + SourceSize, Cy);
+    DG.addMemoryDep(From + SourceSize, To + (SourceSize * 2), Cy);
+    return;
+  }
+  DG.addMemoryDep(From + SourceSize, To + SourceSize, Cy);
+}
+
+void BottleneckAnalysis::addResourceDep(unsigned From, unsigned To,
+                                        uint64_t Mask, unsigned Cy) {
+  bool IsLoopCarried = From >= To;
+  unsigned SourceSize = Source.size();
+  if (IsLoopCarried) {
+    DG.addResourceDep(From, To + SourceSize, Mask, Cy);
+    DG.addResourceDep(From + SourceSize, To + (SourceSize * 2), Mask, Cy);
+    return;
+  }
+  DG.addResourceDep(From + SourceSize, To + SourceSize, Mask, Cy);
+}
+
 void BottleneckAnalysis::onEvent(const HWInstructionEvent &Event) {
-  Tracker.handleInstructionEvent(Event);
+  const unsigned IID = Event.IR.getSourceIndex();
+  if (Event.Type == HWInstructionEvent::Dispatched) {
+    Tracker.onInstructionDispatched(IID);
+    return;
+  }
+  if (Event.Type == HWInstructionEvent::Executed) {
+    Tracker.onInstructionExecuted(IID);
+    return;
+  }
+
   if (Event.Type != HWInstructionEvent::Issued)
     return;
 
-  const unsigned IID = Event.IR.getSourceIndex();
   const Instruction &IS = *Event.IR.getInstruction();
-  unsigned Cycles = Tracker.getRegisterPressureCycles(IID);
   unsigned To = IID % Source.size();
+
+  unsigned Cycles = Tracker.getResourcePressureCycles(IID);
+  if (Cycles) {
+    uint64_t ResourceMask = IS.getCriticalResourceMask();
+    SmallVector<std::pair<unsigned, unsigned>, 4> Users;
+    while (ResourceMask) {
+      uint64_t Current = ResourceMask & (-ResourceMask);
+      Tracker.getResourceUsers(Current, Users);
+      for (const std::pair<unsigned, unsigned> &U : Users) {
+        unsigned Cost = std::min(U.second, Cycles);
+        addResourceDep(U.first % Source.size(), To, Current, Cost);
+      }
+      Users.clear();
+      ResourceMask ^= Current;
+    }
+  }
+
+  Cycles = Tracker.getRegisterPressureCycles(IID);
   if (Cycles) {
     const CriticalDependency &RegDep = IS.getCriticalRegDep();
     unsigned From = RegDep.IID % Source.size();
-    DG.addRegDep(From, To, RegDep.RegID, Cycles);
+    addRegisterDep(From, To, RegDep.RegID, Cycles);
   }
+
   Cycles = Tracker.getMemoryPressureCycles(IID);
   if (Cycles) {
     const CriticalDependency &MemDep = IS.getCriticalMemDep();
     unsigned From = MemDep.IID % Source.size();
-    DG.addMemDep(From, To, Cycles);
+    addMemoryDep(From, To, Cycles);
   }
+
+  Tracker.handleInstructionIssuedEvent(
+      static_cast<const HWInstructionIssuedEvent &>(Event));
 }
 
 void BottleneckAnalysis::onEvent(const HWPressureEvent &Event) {
@@ -245,28 +314,9 @@ void BottleneckAnalysis::onEvent(const H
   default:
     break;
 
-  case HWPressureEvent::RESOURCES: {
+  case HWPressureEvent::RESOURCES:
     PressureIncreasedBecauseOfResources = true;
-
-    SmallVector<unsigned, 4> UniqueUsers;
-    for (const InstRef &IR : Event.AffectedInstructions) {
-      const Instruction &IS = *IR.getInstruction();
-      unsigned To = IR.getSourceIndex() % Source.size();
-      unsigned BusyResources =
-          IS.getCriticalResourceMask() & Event.ResourceMask;
-      while (BusyResources) {
-        uint64_t Current = BusyResources & (-BusyResources);
-        Tracker.getUniqueUsers(Current, UniqueUsers);
-        for (unsigned User : UniqueUsers)
-          DG.addResourceDep(User % Source.size(), To, Current, 1);
-        BusyResources ^= Current;
-      }
-      UniqueUsers.clear();
-    }
-
     break;
-  }
-
   case HWPressureEvent::REGISTER_DEPS:
     PressureIncreasedBecauseOfRegisterDependencies = true;
     break;

Modified: llvm/trunk/tools/llvm-mca/Views/BottleneckAnalysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/Views/BottleneckAnalysis.h?rev=362933&r1=362932&r2=362933&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/Views/BottleneckAnalysis.h (original)
+++ llvm/trunk/tools/llvm-mca/Views/BottleneckAnalysis.h Mon Jun 10 05:50:08 2019
@@ -63,7 +63,8 @@ class PressureTracker {
   // There is one entry for every processor resource unit declared by the
   // processor model. An all_ones value is treated like an invalid instruction
   // identifier.
-  SmallVector<unsigned, 4> ResourceUsers;
+  using User = std::pair<unsigned, unsigned>;
+  SmallVector<User, 4> ResourceUsers;
 
   struct InstructionPressureInfo {
     unsigned RegisterPressureCycles;
@@ -74,7 +75,7 @@ class PressureTracker {
 
   void updateResourcePressureDistribution(uint64_t CumulativeMask);
 
-  unsigned getResourceUser(unsigned ProcResID, unsigned UnitID) const {
+  User getResourceUser(unsigned ProcResID, unsigned UnitID) const {
     unsigned Index = ProcResID2ResourceUsersIndex[ProcResID];
     return ResourceUsers[Index + UnitID];
   }
@@ -86,8 +87,8 @@ public:
     return ResourcePressureDistribution;
   }
 
-  void getUniqueUsers(uint64_t ResourceMask,
-                      SmallVectorImpl<unsigned> &Users) const;
+  void getResourceUsers(uint64_t ResourceMask,
+                        SmallVectorImpl<User> &Users) const;
 
   unsigned getRegisterPressureCycles(unsigned IID) const {
     assert(IPI.find(IID) != IPI.end() && "Instruction is not tracked!");
@@ -107,12 +108,18 @@ public:
     return Info.ResourcePressureCycles;
   }
 
+  void onInstructionDispatched(unsigned IID);
+  void onInstructionExecuted(unsigned IID);
+
   void handlePressureEvent(const HWPressureEvent &Event);
-  void handleInstructionEvent(const HWInstructionEvent &Event);
+  void handleInstructionIssuedEvent(const HWInstructionIssuedEvent &Event);
 };
 
 class DependencyGraph {
+  enum DependencyType { DT_REGISTER, DT_MEMORY, DT_RESOURCE };
+
   struct DependencyEdge {
+    DependencyType Type;
     unsigned IID;
     uint64_t ResourceOrRegID;
     uint64_t Cycles;
@@ -120,46 +127,44 @@ class DependencyGraph {
 
   struct DGNode {
     unsigned NumPredecessors;
-    SmallVector<DependencyEdge, 8> RegDeps;
-    SmallVector<DependencyEdge, 8> MemDeps;
-    SmallVector<DependencyEdge, 8> ResDeps;
+    SmallVector<DependencyEdge, 8> OutgoingEdges;
   };
   SmallVector<DGNode, 16> Nodes;
 
-  void addDepImpl(SmallVectorImpl<DependencyEdge> &Vec, DependencyEdge &&DE);
-
   DependencyGraph(const DependencyGraph &) = delete;
   DependencyGraph &operator=(const DependencyGraph &) = delete;
 
+  void addDependency(unsigned From, DependencyEdge &&DE);
+
+#ifndef NDEBUG
+  void dumpDependencyEdge(raw_ostream &OS, unsigned FromIID,
+                          const DependencyEdge &DE, MCInstPrinter &MCIP) const;
+#endif
+
 public:
-  DependencyGraph(unsigned NumNodes) : Nodes(NumNodes, DGNode()) {}
+  DependencyGraph(unsigned Size) : Nodes(Size) {}
 
-  void addRegDep(unsigned From, unsigned To, unsigned RegID, unsigned Cy) {
-    addDepImpl(Nodes[From].RegDeps, {To, RegID, Cy});
+  void addRegisterDep(unsigned From, unsigned To, unsigned RegID, unsigned Cy) {
+    addDependency(From, {DT_REGISTER, To, RegID, Cy});
   }
-  void addMemDep(unsigned From, unsigned To, unsigned Cy) {
-    addDepImpl(Nodes[From].MemDeps, {To, /* unused */ 0, Cy});
+
+  void addMemoryDep(unsigned From, unsigned To, unsigned Cy) {
+    addDependency(From, {DT_MEMORY, To, /* unused */ 0, Cy});
   }
+
   void addResourceDep(unsigned From, unsigned To, uint64_t Mask, unsigned Cy) {
-    addDepImpl(Nodes[From].ResDeps, {To, Mask, Cy});
+    addDependency(From, {DT_RESOURCE, To, Mask, Cy});
   }
 
 #ifndef NDEBUG
-  void dumpRegDeps(raw_ostream &OS, MCInstPrinter &MCIP) const;
-  void dumpMemDeps(raw_ostream &OS) const;
-  void dumpResDeps(raw_ostream &OS) const;
-
-  void dump(raw_ostream &OS, MCInstPrinter &MCIP) const {
-    dumpRegDeps(OS, MCIP);
-    dumpMemDeps(OS);
-    dumpResDeps(OS);
-  }
+  void dump(raw_ostream &OS, MCInstPrinter &MCIP) const;
 #endif
 };
 
 /// A view that collects and prints a few performance numbers.
 class BottleneckAnalysis : public View {
   const MCSubtargetInfo &STI;
+  MCInstPrinter &MCIP;
   PressureTracker Tracker;
   DependencyGraph DG;
 
@@ -189,8 +194,14 @@ class BottleneckAnalysis : public View {
   // Prints a bottleneck message to OS.
   void printBottleneckHints(raw_ostream &OS) const;
 
+  // Used to populate the dependency graph DG.
+  void addRegisterDep(unsigned From, unsigned To, unsigned RegID, unsigned Cy);
+  void addMemoryDep(unsigned From, unsigned To, unsigned Cy);
+  void addResourceDep(unsigned From, unsigned To, uint64_t Mask, unsigned Cy);
+
 public:
-  BottleneckAnalysis(const MCSubtargetInfo &STI, ArrayRef<MCInst> Sequence);
+  BottleneckAnalysis(const MCSubtargetInfo &STI, MCInstPrinter &MCIP,
+                     ArrayRef<MCInst> Sequence);
 
   void onCycleEnd() override;
   void onEvent(const HWStallEvent &Event) override { SeenStallCycles = true; }
@@ -200,7 +211,7 @@ public:
   void printView(raw_ostream &OS) const override;
 
 #ifndef NDEBUG
-  void dump(raw_ostream &OS, MCInstPrinter &MCIP) const { DG.dump(OS, MCIP); }
+  void dump(raw_ostream &OS) const { DG.dump(OS, MCIP); }
 #endif
 };
 

Modified: llvm/trunk/tools/llvm-mca/llvm-mca.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-mca/llvm-mca.cpp?rev=362933&r1=362932&r2=362933&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-mca/llvm-mca.cpp (original)
+++ llvm/trunk/tools/llvm-mca/llvm-mca.cpp Mon Jun 10 05:50:08 2019
@@ -487,7 +487,7 @@ int main(int argc, char **argv) {
           llvm::make_unique<mca::SummaryView>(SM, Insts, DispatchWidth));
 
     if (EnableBottleneckAnalysis)
-      Printer.addView(llvm::make_unique<mca::BottleneckAnalysis>(*STI, Insts));
+      Printer.addView(llvm::make_unique<mca::BottleneckAnalysis>(*STI, *IP, Insts));
 
     if (PrintInstructionInfoView)
       Printer.addView(




More information about the llvm-commits mailing list