ResourcePressureView.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. //===--------------------- ResourcePressureView.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-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. /// \file
  9. ///
  10. /// This file implements methods in the ResourcePressureView interface.
  11. ///
  12. //===----------------------------------------------------------------------===//
  13. #include "Views/ResourcePressureView.h"
  14. #include "llvm/Support/FormattedStream.h"
  15. #include "llvm/Support/raw_ostream.h"
  16. namespace llvm {
  17. namespace mca {
  18. ResourcePressureView::ResourcePressureView(const llvm::MCSubtargetInfo &sti,
  19. MCInstPrinter &Printer,
  20. ArrayRef<MCInst> S)
  21. : InstructionView(sti, Printer, S), LastInstructionIdx(0) {
  22. // Populate the map of resource descriptors.
  23. unsigned R2VIndex = 0;
  24. const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
  25. for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
  26. const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
  27. unsigned NumUnits = ProcResource.NumUnits;
  28. // Skip groups and invalid resources with zero units.
  29. if (ProcResource.SubUnitsIdxBegin || !NumUnits)
  30. continue;
  31. Resource2VecIndex.insert(std::pair<unsigned, unsigned>(I, R2VIndex));
  32. R2VIndex += ProcResource.NumUnits;
  33. }
  34. NumResourceUnits = R2VIndex;
  35. ResourceUsage.resize(NumResourceUnits * (getSource().size() + 1));
  36. std::fill(ResourceUsage.begin(), ResourceUsage.end(), 0.0);
  37. }
  38. void ResourcePressureView::onEvent(const HWInstructionEvent &Event) {
  39. if (Event.Type == HWInstructionEvent::Dispatched) {
  40. LastInstructionIdx = Event.IR.getSourceIndex();
  41. return;
  42. }
  43. // We're only interested in Issue events.
  44. if (Event.Type != HWInstructionEvent::Issued)
  45. return;
  46. const auto &IssueEvent = static_cast<const HWInstructionIssuedEvent &>(Event);
  47. ArrayRef<llvm::MCInst> Source = getSource();
  48. const unsigned SourceIdx = Event.IR.getSourceIndex() % Source.size();
  49. for (const std::pair<ResourceRef, ResourceCycles> &Use :
  50. IssueEvent.UsedResources) {
  51. const ResourceRef &RR = Use.first;
  52. assert(Resource2VecIndex.find(RR.first) != Resource2VecIndex.end());
  53. unsigned R2VIndex = Resource2VecIndex[RR.first];
  54. R2VIndex += countTrailingZeros(RR.second);
  55. ResourceUsage[R2VIndex + NumResourceUnits * SourceIdx] += Use.second;
  56. ResourceUsage[R2VIndex + NumResourceUnits * Source.size()] += Use.second;
  57. }
  58. }
  59. static void printColumnNames(formatted_raw_ostream &OS,
  60. const MCSchedModel &SM) {
  61. unsigned Column = OS.getColumn();
  62. for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
  63. I < E; ++I) {
  64. const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
  65. unsigned NumUnits = ProcResource.NumUnits;
  66. // Skip groups and invalid resources with zero units.
  67. if (ProcResource.SubUnitsIdxBegin || !NumUnits)
  68. continue;
  69. for (unsigned J = 0; J < NumUnits; ++J) {
  70. Column += 7;
  71. OS << "[" << ResourceIndex;
  72. if (NumUnits > 1)
  73. OS << '.' << J;
  74. OS << ']';
  75. OS.PadToColumn(Column);
  76. }
  77. ResourceIndex++;
  78. }
  79. }
  80. static void printResourcePressure(formatted_raw_ostream &OS, double Pressure,
  81. unsigned Col) {
  82. if (!Pressure || Pressure < 0.005) {
  83. OS << " - ";
  84. } else {
  85. // Round to the value to the nearest hundredth and then print it.
  86. OS << format("%.2f", floor((Pressure * 100) + 0.5) / 100);
  87. }
  88. OS.PadToColumn(Col);
  89. }
  90. void ResourcePressureView::printResourcePressurePerIter(raw_ostream &OS) const {
  91. std::string Buffer;
  92. raw_string_ostream TempStream(Buffer);
  93. formatted_raw_ostream FOS(TempStream);
  94. FOS << "\n\nResources:\n";
  95. const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
  96. for (unsigned I = 1, ResourceIndex = 0, E = SM.getNumProcResourceKinds();
  97. I < E; ++I) {
  98. const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
  99. unsigned NumUnits = ProcResource.NumUnits;
  100. // Skip groups and invalid resources with zero units.
  101. if (ProcResource.SubUnitsIdxBegin || !NumUnits)
  102. continue;
  103. for (unsigned J = 0; J < NumUnits; ++J) {
  104. FOS << '[' << ResourceIndex;
  105. if (NumUnits > 1)
  106. FOS << '.' << J;
  107. FOS << ']';
  108. FOS.PadToColumn(6);
  109. FOS << "- " << ProcResource.Name << '\n';
  110. }
  111. ResourceIndex++;
  112. }
  113. FOS << "\n\nResource pressure per iteration:\n";
  114. FOS.flush();
  115. printColumnNames(FOS, SM);
  116. FOS << '\n';
  117. FOS.flush();
  118. ArrayRef<llvm::MCInst> Source = getSource();
  119. const unsigned Executions = LastInstructionIdx / Source.size() + 1;
  120. for (unsigned I = 0, E = NumResourceUnits; I < E; ++I) {
  121. double Usage = ResourceUsage[I + Source.size() * E];
  122. printResourcePressure(FOS, Usage / Executions, (I + 1) * 7);
  123. }
  124. FOS.flush();
  125. OS << Buffer;
  126. }
  127. void ResourcePressureView::printResourcePressurePerInst(raw_ostream &OS) const {
  128. std::string Buffer;
  129. raw_string_ostream TempStream(Buffer);
  130. formatted_raw_ostream FOS(TempStream);
  131. FOS << "\n\nResource pressure by instruction:\n";
  132. printColumnNames(FOS, getSubTargetInfo().getSchedModel());
  133. FOS << "Instructions:\n";
  134. unsigned InstrIndex = 0;
  135. ArrayRef<llvm::MCInst> Source = getSource();
  136. const unsigned Executions = LastInstructionIdx / Source.size() + 1;
  137. for (const MCInst &MCI : Source) {
  138. unsigned BaseEltIdx = InstrIndex * NumResourceUnits;
  139. for (unsigned J = 0; J < NumResourceUnits; ++J) {
  140. double Usage = ResourceUsage[J + BaseEltIdx];
  141. printResourcePressure(FOS, Usage / Executions, (J + 1) * 7);
  142. }
  143. FOS << printInstructionString(MCI) << '\n';
  144. FOS.flush();
  145. OS << Buffer;
  146. Buffer = "";
  147. ++InstrIndex;
  148. }
  149. }
  150. json::Value ResourcePressureView::toJSON() const {
  151. // We're dumping the instructions and the ResourceUsage array.
  152. json::Array ResourcePressureInfo;
  153. // The ResourceUsage matrix is sparse, so we only consider
  154. // non-zero values.
  155. ArrayRef<llvm::MCInst> Source = getSource();
  156. const unsigned Executions = LastInstructionIdx / Source.size() + 1;
  157. for (const auto &R : enumerate(ResourceUsage)) {
  158. const ResourceCycles &RU = R.value();
  159. if (RU.getNumerator() == 0)
  160. continue;
  161. unsigned InstructionIndex = R.index() / NumResourceUnits;
  162. unsigned ResourceIndex = R.index() % NumResourceUnits;
  163. double Usage = RU / Executions;
  164. ResourcePressureInfo.push_back(
  165. json::Object({{"InstructionIndex", InstructionIndex},
  166. {"ResourceIndex", ResourceIndex},
  167. {"ResourceUsage", Usage}}));
  168. }
  169. json::Object JO({{"ResourcePressureInfo", std::move(ResourcePressureInfo)}});
  170. return JO;
  171. }
  172. } // namespace mca
  173. } // namespace llvm