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