1 //===--------------------- TimelineView.cpp ---------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// This file implements the TimelineView interface.
13 //===----------------------------------------------------------------------===//
15 #include "Views/TimelineView.h"
21 TimelineView::TimelineView(const MCSubtargetInfo
&sti
, MCInstPrinter
&Printer
,
22 const SourceMgr
&S
, unsigned MaxIterations
,
24 : STI(sti
), MCIP(Printer
), AsmSequence(S
), CurrentCycle(0),
25 MaxCycle(Cycles
== 0 ? 80 : Cycles
), LastCycle(0), WaitTime(S
.size()),
26 UsedBuffer(S
.size()) {
27 unsigned NumInstructions
= AsmSequence
.size();
29 MaxIterations
= DEFAULT_ITERATIONS
;
30 NumInstructions
*= std::min(MaxIterations
, AsmSequence
.getNumIterations());
31 Timeline
.resize(NumInstructions
);
32 TimelineViewEntry InvalidTVEntry
= {-1, 0, 0, 0, 0};
33 std::fill(Timeline
.begin(), Timeline
.end(), InvalidTVEntry
);
35 WaitTimeEntry NullWTEntry
= {0, 0, 0};
36 std::fill(WaitTime
.begin(), WaitTime
.end(), NullWTEntry
);
38 std::pair
<unsigned, int> NullUsedBufferEntry
= {/* Invalid resource ID*/ 0,
39 /* unknown buffer size */ -1};
40 std::fill(UsedBuffer
.begin(), UsedBuffer
.end(), NullUsedBufferEntry
);
43 void TimelineView::onReservedBuffers(const InstRef
&IR
,
44 ArrayRef
<unsigned> Buffers
) {
45 if (IR
.getSourceIndex() >= AsmSequence
.size())
48 const MCSchedModel
&SM
= STI
.getSchedModel();
49 std::pair
<unsigned, int> BufferInfo
= {0, -1};
50 for (const unsigned Buffer
: Buffers
) {
51 const MCProcResourceDesc
&MCDesc
= *SM
.getProcResource(Buffer
);
52 if (!BufferInfo
.first
|| BufferInfo
.second
> MCDesc
.BufferSize
) {
53 BufferInfo
.first
= Buffer
;
54 BufferInfo
.second
= MCDesc
.BufferSize
;
58 UsedBuffer
[IR
.getSourceIndex()] = BufferInfo
;
61 void TimelineView::onEvent(const HWInstructionEvent
&Event
) {
62 const unsigned Index
= Event
.IR
.getSourceIndex();
63 if (Index
>= Timeline
.size())
67 case HWInstructionEvent::Retired
: {
68 TimelineViewEntry
&TVEntry
= Timeline
[Index
];
69 if (CurrentCycle
< MaxCycle
)
70 TVEntry
.CycleRetired
= CurrentCycle
;
72 // Update the WaitTime entry which corresponds to this Index.
73 assert(TVEntry
.CycleDispatched
>= 0 && "Invalid TVEntry found!");
74 unsigned CycleDispatched
= static_cast<unsigned>(TVEntry
.CycleDispatched
);
75 WaitTimeEntry
&WTEntry
= WaitTime
[Index
% AsmSequence
.size()];
76 WTEntry
.CyclesSpentInSchedulerQueue
+=
77 TVEntry
.CycleIssued
- CycleDispatched
;
78 assert(CycleDispatched
<= TVEntry
.CycleReady
&&
79 "Instruction cannot be ready if it hasn't been dispatched yet!");
80 WTEntry
.CyclesSpentInSQWhileReady
+=
81 TVEntry
.CycleIssued
- TVEntry
.CycleReady
;
82 WTEntry
.CyclesSpentAfterWBAndBeforeRetire
+=
83 (CurrentCycle
- 1) - TVEntry
.CycleExecuted
;
86 case HWInstructionEvent::Ready
:
87 Timeline
[Index
].CycleReady
= CurrentCycle
;
89 case HWInstructionEvent::Issued
:
90 Timeline
[Index
].CycleIssued
= CurrentCycle
;
92 case HWInstructionEvent::Executed
:
93 Timeline
[Index
].CycleExecuted
= CurrentCycle
;
95 case HWInstructionEvent::Dispatched
:
96 // There may be multiple dispatch events. Microcoded instructions that are
97 // expanded into multiple uOps may require multiple dispatch cycles. Here,
98 // we want to capture the first dispatch cycle.
99 if (Timeline
[Index
].CycleDispatched
== -1)
100 Timeline
[Index
].CycleDispatched
= static_cast<int>(CurrentCycle
);
105 if (CurrentCycle
< MaxCycle
)
106 LastCycle
= std::max(LastCycle
, CurrentCycle
);
109 static raw_ostream::Colors
chooseColor(unsigned CumulativeCycles
,
110 unsigned Executions
, int BufferSize
) {
111 if (CumulativeCycles
&& BufferSize
< 0)
112 return raw_ostream::MAGENTA
;
113 unsigned Size
= static_cast<unsigned>(BufferSize
);
114 if (CumulativeCycles
>= Size
* Executions
)
115 return raw_ostream::RED
;
116 if ((CumulativeCycles
* 2) >= Size
* Executions
)
117 return raw_ostream::YELLOW
;
118 return raw_ostream::SAVEDCOLOR
;
121 static void tryChangeColor(raw_ostream
&OS
, unsigned Cycles
,
122 unsigned Executions
, int BufferSize
) {
123 if (!OS
.has_colors())
126 raw_ostream::Colors Color
= chooseColor(Cycles
, Executions
, BufferSize
);
127 if (Color
== raw_ostream::SAVEDCOLOR
) {
131 OS
.changeColor(Color
, /* bold */ true, /* BG */ false);
134 void TimelineView::printWaitTimeEntry(formatted_raw_ostream
&OS
,
135 const WaitTimeEntry
&Entry
,
136 unsigned SourceIndex
,
137 unsigned Executions
) const {
138 OS
<< SourceIndex
<< '.';
141 double AverageTime1
, AverageTime2
, AverageTime3
;
142 AverageTime1
= (double)Entry
.CyclesSpentInSchedulerQueue
/ Executions
;
143 AverageTime2
= (double)Entry
.CyclesSpentInSQWhileReady
/ Executions
;
144 AverageTime3
= (double)Entry
.CyclesSpentAfterWBAndBeforeRetire
/ Executions
;
148 int BufferSize
= UsedBuffer
[SourceIndex
].second
;
149 tryChangeColor(OS
, Entry
.CyclesSpentInSchedulerQueue
, Executions
, BufferSize
);
150 OS
<< format("%.1f", floor((AverageTime1
* 10) + 0.5) / 10);
152 tryChangeColor(OS
, Entry
.CyclesSpentInSQWhileReady
, Executions
, BufferSize
);
153 OS
<< format("%.1f", floor((AverageTime2
* 10) + 0.5) / 10);
155 tryChangeColor(OS
, Entry
.CyclesSpentAfterWBAndBeforeRetire
, Executions
,
156 STI
.getSchedModel().MicroOpBufferSize
);
157 OS
<< format("%.1f", floor((AverageTime3
* 10) + 0.5) / 10);
164 void TimelineView::printAverageWaitTimes(raw_ostream
&OS
) const {
166 "\n\nAverage Wait times (based on the timeline view):\n"
168 "[1]: Average time spent waiting in a scheduler's queue\n"
169 "[2]: Average time spent waiting in a scheduler's queue while ready\n"
170 "[3]: Average time elapsed from WB until retire stage\n\n"
171 " [0] [1] [2] [3]\n";
174 // Use a different string stream for printing instructions.
175 std::string Instruction
;
176 raw_string_ostream
InstrStream(Instruction
);
178 formatted_raw_ostream
FOS(OS
);
179 unsigned Executions
= Timeline
.size() / AsmSequence
.size();
180 for (unsigned I
= 0, E
= WaitTime
.size(); I
< E
; ++I
) {
181 printWaitTimeEntry(FOS
, WaitTime
[I
], I
, Executions
);
182 // Append the instruction info at the end of the line.
183 const MCInst
&Inst
= AsmSequence
.getMCInstFromIndex(I
);
185 MCIP
.printInst(&Inst
, InstrStream
, "", STI
);
188 // Consume any tabs or spaces at the beginning of the string.
189 StringRef
Str(Instruction
);
191 FOS
<< " " << Str
<< '\n';
197 void TimelineView::printTimelineViewEntry(formatted_raw_ostream
&OS
,
198 const TimelineViewEntry
&Entry
,
200 unsigned SourceIndex
) const {
201 if (Iteration
== 0 && SourceIndex
== 0)
203 OS
<< '[' << Iteration
<< ',' << SourceIndex
<< ']';
205 assert(Entry
.CycleDispatched
>= 0 && "Invalid TimelineViewEntry!");
206 unsigned CycleDispatched
= static_cast<unsigned>(Entry
.CycleDispatched
);
207 for (unsigned I
= 0, E
= CycleDispatched
; I
< E
; ++I
)
208 OS
<< ((I
% 5 == 0) ? '.' : ' ');
209 OS
<< TimelineView::DisplayChar::Dispatched
;
210 if (CycleDispatched
!= Entry
.CycleExecuted
) {
211 // Zero latency instructions have the same value for CycleDispatched,
212 // CycleIssued and CycleExecuted.
213 for (unsigned I
= CycleDispatched
+ 1, E
= Entry
.CycleIssued
; I
< E
; ++I
)
214 OS
<< TimelineView::DisplayChar::Waiting
;
215 if (Entry
.CycleIssued
== Entry
.CycleExecuted
)
216 OS
<< TimelineView::DisplayChar::DisplayChar::Executed
;
218 if (CycleDispatched
!= Entry
.CycleIssued
)
219 OS
<< TimelineView::DisplayChar::Executing
;
220 for (unsigned I
= Entry
.CycleIssued
+ 1, E
= Entry
.CycleExecuted
; I
< E
;
222 OS
<< TimelineView::DisplayChar::Executing
;
223 OS
<< TimelineView::DisplayChar::Executed
;
227 for (unsigned I
= Entry
.CycleExecuted
+ 1, E
= Entry
.CycleRetired
; I
< E
; ++I
)
228 OS
<< TimelineView::DisplayChar::RetireLag
;
229 OS
<< TimelineView::DisplayChar::Retired
;
231 // Skip other columns.
232 for (unsigned I
= Entry
.CycleRetired
+ 1, E
= LastCycle
; I
<= E
; ++I
)
233 OS
<< ((I
% 5 == 0 || I
== LastCycle
) ? '.' : ' ');
236 static void printTimelineHeader(formatted_raw_ostream
&OS
, unsigned Cycles
) {
237 OS
<< "\n\nTimeline view:\n";
240 for (unsigned I
= 0; I
<= Cycles
; ++I
) {
241 if (((I
/ 10) & 1) == 0)
251 for (unsigned I
= 0; I
<= Cycles
; ++I
) {
252 if (((I
/ 10) & 1) == 0)
260 void TimelineView::printTimeline(raw_ostream
&OS
) const {
261 formatted_raw_ostream
FOS(OS
);
262 printTimelineHeader(FOS
, LastCycle
);
265 // Use a different string stream for the instruction.
266 std::string Instruction
;
267 raw_string_ostream
InstrStream(Instruction
);
269 for (unsigned I
= 0, E
= Timeline
.size(); I
< E
; ++I
) {
270 const TimelineViewEntry
&Entry
= Timeline
[I
];
271 if (Entry
.CycleRetired
== 0)
274 unsigned Iteration
= I
/ AsmSequence
.size();
275 unsigned SourceIndex
= I
% AsmSequence
.size();
276 printTimelineViewEntry(FOS
, Entry
, Iteration
, SourceIndex
);
277 // Append the instruction info at the end of the line.
278 const MCInst
&Inst
= AsmSequence
.getMCInstFromIndex(I
);
279 MCIP
.printInst(&Inst
, InstrStream
, "", STI
);
282 // Consume any tabs or spaces at the beginning of the string.
283 StringRef
Str(Instruction
);
285 FOS
<< " " << Str
<< '\n';