]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/llvm-mca/TimelineView.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / llvm-mca / TimelineView.cpp
1 //===--------------------- TimelineView.cpp ---------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 /// \brief
10 ///
11 /// This file implements the TimelineView interface.
12 ///
13 //===----------------------------------------------------------------------===//
14
15 #include "TimelineView.h"
16
17 using namespace llvm;
18
19 namespace mca {
20
21 void TimelineView::initialize(unsigned MaxIterations) {
22   unsigned NumInstructions =
23       AsmSequence.getNumIterations() * AsmSequence.size();
24   if (!MaxIterations)
25     MaxIterations = DEFAULT_ITERATIONS;
26   unsigned NumEntries =
27       std::min(NumInstructions, MaxIterations * AsmSequence.size());
28   Timeline.resize(NumEntries);
29   TimelineViewEntry NullTVEntry = {0, 0, 0, 0, 0};
30   std::fill(Timeline.begin(), Timeline.end(), NullTVEntry);
31
32   WaitTime.resize(AsmSequence.size());
33   WaitTimeEntry NullWTEntry = {0, 0, 0, 0};
34   std::fill(WaitTime.begin(), WaitTime.end(), NullWTEntry);
35 }
36
37 void TimelineView::onEvent(const HWInstructionEvent &Event) {
38   const unsigned Index = Event.IR.getSourceIndex();
39   if (CurrentCycle >= MaxCycle || Index >= Timeline.size())
40     return;
41   switch (Event.Type) {
42   case HWInstructionEvent::Retired: {
43     TimelineViewEntry &TVEntry = Timeline[Index];
44     TVEntry.CycleRetired = CurrentCycle;
45
46     // Update the WaitTime entry which corresponds to this Index.
47     WaitTimeEntry &WTEntry = WaitTime[Index % AsmSequence.size()];
48     WTEntry.Executions++;
49     WTEntry.CyclesSpentInSchedulerQueue +=
50         TVEntry.CycleIssued - TVEntry.CycleDispatched;
51     assert(TVEntry.CycleDispatched <= TVEntry.CycleReady);
52     WTEntry.CyclesSpentInSQWhileReady +=
53         TVEntry.CycleIssued - TVEntry.CycleReady;
54     WTEntry.CyclesSpentAfterWBAndBeforeRetire +=
55         (TVEntry.CycleRetired - 1) - TVEntry.CycleExecuted;
56     break;
57   }
58   case HWInstructionEvent::Ready:
59     Timeline[Index].CycleReady = CurrentCycle;
60     break;
61   case HWInstructionEvent::Issued:
62     Timeline[Index].CycleIssued = CurrentCycle;
63     break;
64   case HWInstructionEvent::Executed:
65     Timeline[Index].CycleExecuted = CurrentCycle;
66     break;
67   case HWInstructionEvent::Dispatched:
68     Timeline[Index].CycleDispatched = CurrentCycle;
69     break;
70   default:
71     return;
72   }
73   LastCycle = std::max(LastCycle, CurrentCycle);
74 }
75
76 void TimelineView::printWaitTimeEntry(formatted_raw_ostream &OS,
77                                       const WaitTimeEntry &Entry,
78                                       unsigned SourceIndex) const {
79   OS << SourceIndex << '.';
80   OS.PadToColumn(7);
81
82   if (Entry.Executions == 0) {
83     OS << "-      -      -      -     ";
84   } else {
85     double AverageTime1, AverageTime2, AverageTime3;
86     unsigned Executions = Entry.Executions;
87     AverageTime1 = (double)Entry.CyclesSpentInSchedulerQueue / Executions;
88     AverageTime2 = (double)Entry.CyclesSpentInSQWhileReady / Executions;
89     AverageTime3 = (double)Entry.CyclesSpentAfterWBAndBeforeRetire / Executions;
90
91     OS << Executions;
92     OS.PadToColumn(13);
93
94     OS << format("%.1f", floor((AverageTime1 * 10) + 0.5) / 10);
95     OS.PadToColumn(20);
96     OS << format("%.1f", floor((AverageTime2 * 10) + 0.5) / 10);
97     OS.PadToColumn(27);
98     OS << format("%.1f", floor((AverageTime3 * 10) + 0.5) / 10);
99     OS.PadToColumn(34);
100   }
101 }
102
103 void TimelineView::printAverageWaitTimes(raw_ostream &OS) const {
104   if (WaitTime.empty())
105     return;
106
107   std::string Buffer;
108   raw_string_ostream TempStream(Buffer);
109   formatted_raw_ostream FOS(TempStream);
110
111   FOS << "\n\nAverage Wait times (based on the timeline view):\n"
112       << "[0]: Executions\n"
113       << "[1]: Average time spent waiting in a scheduler's queue\n"
114       << "[2]: Average time spent waiting in a scheduler's queue while ready\n"
115       << "[3]: Average time elapsed from WB until retire stage\n\n";
116   FOS << "      [0]    [1]    [2]    [3]\n";
117
118   // Use a different string stream for the instruction.
119   std::string Instruction;
120   raw_string_ostream InstrStream(Instruction);
121
122   for (unsigned I = 0, E = WaitTime.size(); I < E; ++I) {
123     printWaitTimeEntry(FOS, WaitTime[I], I);
124     // Append the instruction info at the end of the line.
125     const MCInst &Inst = AsmSequence.getMCInstFromIndex(I);
126
127     MCIP.printInst(&Inst, InstrStream, "", STI);
128     InstrStream.flush();
129
130     // Consume any tabs or spaces at the beginning of the string.
131     StringRef Str(Instruction);
132     Str = Str.ltrim();
133     FOS << "   " << Str << '\n';
134     FOS.flush();
135     Instruction = "";
136
137     OS << Buffer;
138     Buffer = "";
139   }
140 }
141
142 void TimelineView::printTimelineViewEntry(formatted_raw_ostream &OS,
143                                           const TimelineViewEntry &Entry,
144                                           unsigned Iteration,
145                                           unsigned SourceIndex) const {
146   if (Iteration == 0 && SourceIndex == 0)
147     OS << '\n';
148   OS << '[' << Iteration << ',' << SourceIndex << ']';
149   OS.PadToColumn(10);
150   for (unsigned I = 0, E = Entry.CycleDispatched; I < E; ++I)
151     OS << ((I % 5 == 0) ? '.' : ' ');
152   OS << TimelineView::DisplayChar::Dispatched;
153   if (Entry.CycleDispatched != Entry.CycleExecuted) {
154     // Zero latency instructions have the same value for CycleDispatched,
155     // CycleIssued and CycleExecuted.
156     for (unsigned I = Entry.CycleDispatched + 1, E = Entry.CycleIssued; I < E;
157          ++I)
158       OS << TimelineView::DisplayChar::Waiting;
159     if (Entry.CycleIssued == Entry.CycleExecuted)
160       OS << TimelineView::DisplayChar::DisplayChar::Executed;
161     else {
162       if (Entry.CycleDispatched != Entry.CycleIssued)
163         OS << TimelineView::DisplayChar::Executing;
164       for (unsigned I = Entry.CycleIssued + 1, E = Entry.CycleExecuted; I < E;
165            ++I)
166         OS << TimelineView::DisplayChar::Executing;
167       OS << TimelineView::DisplayChar::Executed;
168     }
169   }
170
171   for (unsigned I = Entry.CycleExecuted + 1, E = Entry.CycleRetired; I < E; ++I)
172     OS << TimelineView::DisplayChar::RetireLag;
173   OS << TimelineView::DisplayChar::Retired;
174
175   // Skip other columns.
176   for (unsigned I = Entry.CycleRetired + 1, E = LastCycle; I <= E; ++I)
177     OS << ((I % 5 == 0 || I == LastCycle) ? '.' : ' ');
178 }
179
180 static void printTimelineHeader(formatted_raw_ostream &OS, unsigned Cycles) {
181   OS << "\n\nTimeline view:\n";
182   if (Cycles >= 10) {
183     OS.PadToColumn(10);
184     for (unsigned I = 0; I <= Cycles; ++I) {
185       if (((I / 10) & 1) == 0)
186         OS << ' ';
187       else
188         OS << I % 10;
189     }
190     OS << '\n';
191   }
192
193   OS << "Index";
194   OS.PadToColumn(10);
195   for (unsigned I = 0; I <= Cycles; ++I) {
196     if (((I / 10) & 1) == 0)
197       OS << I % 10;
198     else
199       OS << ' ';
200   }
201   OS << '\n';
202 }
203
204 void TimelineView::printTimeline(raw_ostream &OS) const {
205   std::string Buffer;
206   raw_string_ostream StringStream(Buffer);
207   formatted_raw_ostream FOS(StringStream);
208
209   printTimelineHeader(FOS, LastCycle);
210   FOS.flush();
211   OS << Buffer;
212
213   // Use a different string stream for the instruction.
214   std::string Instruction;
215   raw_string_ostream InstrStream(Instruction);
216
217   for (unsigned I = 0, E = Timeline.size(); I < E; ++I) {
218     Buffer = "";
219     const TimelineViewEntry &Entry = Timeline[I];
220     if (Entry.CycleRetired == 0)
221       return;
222
223     unsigned Iteration = I / AsmSequence.size();
224     unsigned SourceIndex = I % AsmSequence.size();
225     printTimelineViewEntry(FOS, Entry, Iteration, SourceIndex);
226     // Append the instruction info at the end of the line.
227     const MCInst &Inst = AsmSequence.getMCInstFromIndex(I);
228     MCIP.printInst(&Inst, InstrStream, "", STI);
229     InstrStream.flush();
230
231     // Consume any tabs or spaces at the beginning of the string.
232     StringRef Str(Instruction);
233     Str = Str.ltrim();
234     FOS << "   " << Str << '\n';
235     FOS.flush();
236     Instruction = "";
237     OS << Buffer;
238   }
239 }
240 } // namespace mca