1 | //===--------------------- RegisterFileStatistics.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 the RegisterFileStatistics interface. |
11 | /// |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "Views/RegisterFileStatistics.h" |
15 | #include "llvm/Support/Format.h" |
16 | |
17 | namespace llvm { |
18 | namespace mca { |
19 | |
20 | RegisterFileStatistics::RegisterFileStatistics(const MCSubtargetInfo &sti) |
21 | : STI(sti) { |
22 | const MCSchedModel &SM = STI.getSchedModel(); |
23 | RegisterFileUsage RFUEmpty = {.TotalMappings: 0, .MaxUsedMappings: 0, .CurrentlyUsedMappings: 0}; |
24 | MoveEliminationInfo MEIEmpty = {.TotalMoveEliminationCandidates: 0, .TotalMovesEliminated: 0, .TotalMovesThatPropagateZero: 0, .MaxMovesEliminatedPerCycle: 0, .CurrentMovesEliminated: 0}; |
25 | if (!SM.hasExtraProcessorInfo()) { |
26 | // Assume a single register file. |
27 | PRFUsage.emplace_back(Args&: RFUEmpty); |
28 | MoveElimInfo.emplace_back(Args&: MEIEmpty); |
29 | return; |
30 | } |
31 | |
32 | // Initialize a RegisterFileUsage for every user defined register file, plus |
33 | // the default register file which is always at index #0. |
34 | const MCExtraProcessorInfo &PI = SM.getExtraProcessorInfo(); |
35 | // There is always an "InvalidRegisterFile" entry in tablegen. That entry can |
36 | // be skipped. If there are no user defined register files, then reserve a |
37 | // single entry for the default register file at index #0. |
38 | unsigned NumRegFiles = std::max(a: PI.NumRegisterFiles, b: 1U); |
39 | |
40 | PRFUsage.resize(N: NumRegFiles); |
41 | std::fill(first: PRFUsage.begin(), last: PRFUsage.end(), value: RFUEmpty); |
42 | |
43 | MoveElimInfo.resize(N: NumRegFiles); |
44 | std::fill(first: MoveElimInfo.begin(), last: MoveElimInfo.end(), value: MEIEmpty); |
45 | } |
46 | |
47 | void RegisterFileStatistics::updateRegisterFileUsage( |
48 | ArrayRef<unsigned> UsedPhysRegs) { |
49 | for (unsigned I = 0, E = PRFUsage.size(); I < E; ++I) { |
50 | RegisterFileUsage &RFU = PRFUsage[I]; |
51 | unsigned NumUsedPhysRegs = UsedPhysRegs[I]; |
52 | RFU.CurrentlyUsedMappings += NumUsedPhysRegs; |
53 | RFU.TotalMappings += NumUsedPhysRegs; |
54 | RFU.MaxUsedMappings = |
55 | std::max(a: RFU.MaxUsedMappings, b: RFU.CurrentlyUsedMappings); |
56 | } |
57 | } |
58 | |
59 | void RegisterFileStatistics::updateMoveElimInfo(const Instruction &Inst) { |
60 | if (!Inst.isOptimizableMove()) |
61 | return; |
62 | |
63 | if (Inst.getDefs().size() != Inst.getUses().size()) |
64 | return; |
65 | |
66 | for (size_t I = 0, E = Inst.getDefs().size(); I < E; ++I) { |
67 | const WriteState &WS = Inst.getDefs()[I]; |
68 | const ReadState &RS = Inst.getUses()[E - (I + 1)]; |
69 | |
70 | MoveEliminationInfo &Info = |
71 | MoveElimInfo[Inst.getDefs()[0].getRegisterFileID()]; |
72 | Info.TotalMoveEliminationCandidates++; |
73 | if (WS.isEliminated()) |
74 | Info.CurrentMovesEliminated++; |
75 | if (WS.isWriteZero() && RS.isReadZero()) |
76 | Info.TotalMovesThatPropagateZero++; |
77 | } |
78 | } |
79 | |
80 | void RegisterFileStatistics::onEvent(const HWInstructionEvent &Event) { |
81 | switch (Event.Type) { |
82 | default: |
83 | break; |
84 | case HWInstructionEvent::Retired: { |
85 | const auto &RE = static_cast<const HWInstructionRetiredEvent &>(Event); |
86 | for (unsigned I = 0, E = PRFUsage.size(); I < E; ++I) |
87 | PRFUsage[I].CurrentlyUsedMappings -= RE.FreedPhysRegs[I]; |
88 | break; |
89 | } |
90 | case HWInstructionEvent::Dispatched: { |
91 | const auto &DE = static_cast<const HWInstructionDispatchedEvent &>(Event); |
92 | updateRegisterFileUsage(UsedPhysRegs: DE.UsedPhysRegs); |
93 | updateMoveElimInfo(Inst: *DE.IR.getInstruction()); |
94 | } |
95 | } |
96 | } |
97 | |
98 | void RegisterFileStatistics::onCycleEnd() { |
99 | for (MoveEliminationInfo &MEI : MoveElimInfo) { |
100 | unsigned &CurrentMax = MEI.MaxMovesEliminatedPerCycle; |
101 | CurrentMax = std::max(a: CurrentMax, b: MEI.CurrentMovesEliminated); |
102 | MEI.TotalMovesEliminated += MEI.CurrentMovesEliminated; |
103 | MEI.CurrentMovesEliminated = 0; |
104 | } |
105 | } |
106 | |
107 | void RegisterFileStatistics::printView(raw_ostream &OS) const { |
108 | std::string Buffer; |
109 | raw_string_ostream TempStream(Buffer); |
110 | |
111 | TempStream << "\n\nRegister File statistics:" ; |
112 | const RegisterFileUsage &GlobalUsage = PRFUsage[0]; |
113 | TempStream << "\nTotal number of mappings created: " |
114 | << GlobalUsage.TotalMappings; |
115 | TempStream << "\nMax number of mappings used: " |
116 | << GlobalUsage.MaxUsedMappings << '\n'; |
117 | |
118 | for (unsigned I = 1, E = PRFUsage.size(); I < E; ++I) { |
119 | const RegisterFileUsage &RFU = PRFUsage[I]; |
120 | // Obtain the register file descriptor from the scheduling model. |
121 | assert(STI.getSchedModel().hasExtraProcessorInfo() && |
122 | "Unable to find register file info!" ); |
123 | const MCExtraProcessorInfo &PI = |
124 | STI.getSchedModel().getExtraProcessorInfo(); |
125 | assert(I <= PI.NumRegisterFiles && "Unexpected register file index!" ); |
126 | const MCRegisterFileDesc &RFDesc = PI.RegisterFiles[I]; |
127 | // Skip invalid register files. |
128 | if (!RFDesc.NumPhysRegs) |
129 | continue; |
130 | |
131 | TempStream << "\n* Register File #" << I; |
132 | TempStream << " -- " << StringRef(RFDesc.Name) << ':'; |
133 | TempStream << "\n Number of physical registers: " ; |
134 | if (!RFDesc.NumPhysRegs) |
135 | TempStream << "unbounded" ; |
136 | else |
137 | TempStream << RFDesc.NumPhysRegs; |
138 | TempStream << "\n Total number of mappings created: " |
139 | << RFU.TotalMappings; |
140 | TempStream << "\n Max number of mappings used: " |
141 | << RFU.MaxUsedMappings << '\n'; |
142 | const MoveEliminationInfo &MEI = MoveElimInfo[I]; |
143 | |
144 | if (MEI.TotalMoveEliminationCandidates) { |
145 | TempStream << " Number of optimizable moves: " |
146 | << MEI.TotalMoveEliminationCandidates; |
147 | double EliminatedMovProportion = (double)MEI.TotalMovesEliminated / |
148 | MEI.TotalMoveEliminationCandidates * |
149 | 100.0; |
150 | double ZeroMovProportion = (double)MEI.TotalMovesThatPropagateZero / |
151 | MEI.TotalMoveEliminationCandidates * 100.0; |
152 | TempStream << "\n Number of moves eliminated: " |
153 | << MEI.TotalMovesEliminated << " " |
154 | << format(Fmt: "(%.1f%%)" , |
155 | Vals: floor(x: (EliminatedMovProportion * 10) + 0.5) / 10); |
156 | TempStream << "\n Number of zero moves: " |
157 | << MEI.TotalMovesThatPropagateZero << " " |
158 | << format(Fmt: "(%.1f%%)" , |
159 | Vals: floor(x: (ZeroMovProportion * 10) + 0.5) / 10); |
160 | TempStream << "\n Max moves eliminated per cycle: " |
161 | << MEI.MaxMovesEliminatedPerCycle << '\n'; |
162 | } |
163 | } |
164 | |
165 | TempStream.flush(); |
166 | OS << Buffer; |
167 | } |
168 | |
169 | } // namespace mca |
170 | } // namespace llvm |
171 | |