xref: /llvm-project/llvm/tools/llvm-mca/Views/TimelineView.cpp (revision 923dbb01ea6be1ec919d0b71b34551ae91169bc7)
110aa09f0SMatt Davis //===--------------------- TimelineView.cpp ---------------------*- C++ -*-===//
210aa09f0SMatt Davis //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610aa09f0SMatt Davis //
710aa09f0SMatt Davis //===----------------------------------------------------------------------===//
810aa09f0SMatt Davis /// \brief
910aa09f0SMatt Davis ///
1010aa09f0SMatt Davis /// This file implements the TimelineView interface.
1110aa09f0SMatt Davis ///
1210aa09f0SMatt Davis //===----------------------------------------------------------------------===//
1310aa09f0SMatt Davis 
1410aa09f0SMatt Davis #include "Views/TimelineView.h"
15a5e65c1cSRoman Lebedev #include <numeric>
1610aa09f0SMatt Davis 
175a8fd657SFangrui Song namespace llvm {
1810aa09f0SMatt Davis namespace mca {
1910aa09f0SMatt Davis 
TimelineView(const MCSubtargetInfo & sti,MCInstPrinter & Printer,llvm::ArrayRef<llvm::MCInst> S,unsigned Iterations,unsigned Cycles)20d17d371cSAndrea Di Biagio TimelineView::TimelineView(const MCSubtargetInfo &sti, MCInstPrinter &Printer,
2184d00513SAndrea Di Biagio                            llvm::ArrayRef<llvm::MCInst> S, unsigned Iterations,
22d17d371cSAndrea Di Biagio                            unsigned Cycles)
23e02920feSWolfgang Pieb     : InstructionView(sti, Printer, S), CurrentCycle(0),
24beebe5a0SJay Foad       MaxCycle(Cycles == 0 ? std::numeric_limits<unsigned>::max() : Cycles),
25beebe5a0SJay Foad       LastCycle(0), WaitTime(S.size()), UsedBuffer(S.size()) {
26e02920feSWolfgang Pieb   unsigned NumInstructions = getSource().size();
2784d00513SAndrea Di Biagio   assert(Iterations && "Invalid number of iterations specified!");
2884d00513SAndrea Di Biagio   NumInstructions *= Iterations;
29d17d371cSAndrea Di Biagio   Timeline.resize(NumInstructions);
307f2230ffSAndrea Di Biagio   TimelineViewEntry InvalidTVEntry = {-1, 0, 0, 0, 0};
318b647dcfSAndrea Di Biagio   std::fill(Timeline.begin(), Timeline.end(), InvalidTVEntry);
3210aa09f0SMatt Davis 
33d17d371cSAndrea Di Biagio   WaitTimeEntry NullWTEntry = {0, 0, 0};
3410aa09f0SMatt Davis   std::fill(WaitTime.begin(), WaitTime.end(), NullWTEntry);
354269d64bSAndrea Di Biagio 
364269d64bSAndrea Di Biagio   std::pair<unsigned, int> NullUsedBufferEntry = {/* Invalid resource ID*/ 0,
374269d64bSAndrea Di Biagio                                                   /* unknown buffer size */ -1};
384269d64bSAndrea Di Biagio   std::fill(UsedBuffer.begin(), UsedBuffer.end(), NullUsedBufferEntry);
3910aa09f0SMatt Davis }
4010aa09f0SMatt Davis 
onReservedBuffers(const InstRef & IR,ArrayRef<unsigned> Buffers)41d17d371cSAndrea Di Biagio void TimelineView::onReservedBuffers(const InstRef &IR,
42d17d371cSAndrea Di Biagio                                      ArrayRef<unsigned> Buffers) {
43e02920feSWolfgang Pieb   if (IR.getSourceIndex() >= getSource().size())
44d17d371cSAndrea Di Biagio     return;
45d17d371cSAndrea Di Biagio 
46e02920feSWolfgang Pieb   const MCSchedModel &SM = getSubTargetInfo().getSchedModel();
474269d64bSAndrea Di Biagio   std::pair<unsigned, int> BufferInfo = {0, -1};
48d17d371cSAndrea Di Biagio   for (const unsigned Buffer : Buffers) {
49d17d371cSAndrea Di Biagio     const MCProcResourceDesc &MCDesc = *SM.getProcResource(Buffer);
504269d64bSAndrea Di Biagio     if (!BufferInfo.first || BufferInfo.second > MCDesc.BufferSize) {
51d17d371cSAndrea Di Biagio       BufferInfo.first = Buffer;
524269d64bSAndrea Di Biagio       BufferInfo.second = MCDesc.BufferSize;
53d17d371cSAndrea Di Biagio     }
54d17d371cSAndrea Di Biagio   }
55d17d371cSAndrea Di Biagio 
56d17d371cSAndrea Di Biagio   UsedBuffer[IR.getSourceIndex()] = BufferInfo;
57d17d371cSAndrea Di Biagio }
58d17d371cSAndrea Di Biagio 
onEvent(const HWInstructionEvent & Event)5910aa09f0SMatt Davis void TimelineView::onEvent(const HWInstructionEvent &Event) {
6010aa09f0SMatt Davis   const unsigned Index = Event.IR.getSourceIndex();
61d17d371cSAndrea Di Biagio   if (Index >= Timeline.size())
6210aa09f0SMatt Davis     return;
63d17d371cSAndrea Di Biagio 
6410aa09f0SMatt Davis   switch (Event.Type) {
6510aa09f0SMatt Davis   case HWInstructionEvent::Retired: {
6610aa09f0SMatt Davis     TimelineViewEntry &TVEntry = Timeline[Index];
67d17d371cSAndrea Di Biagio     if (CurrentCycle < MaxCycle)
6810aa09f0SMatt Davis       TVEntry.CycleRetired = CurrentCycle;
6910aa09f0SMatt Davis 
7010aa09f0SMatt Davis     // Update the WaitTime entry which corresponds to this Index.
718b647dcfSAndrea Di Biagio     assert(TVEntry.CycleDispatched >= 0 && "Invalid TVEntry found!");
728b647dcfSAndrea Di Biagio     unsigned CycleDispatched = static_cast<unsigned>(TVEntry.CycleDispatched);
73e02920feSWolfgang Pieb     WaitTimeEntry &WTEntry = WaitTime[Index % getSource().size()];
7410aa09f0SMatt Davis     WTEntry.CyclesSpentInSchedulerQueue +=
758b647dcfSAndrea Di Biagio         TVEntry.CycleIssued - CycleDispatched;
768b647dcfSAndrea Di Biagio     assert(CycleDispatched <= TVEntry.CycleReady &&
778b647dcfSAndrea Di Biagio            "Instruction cannot be ready if it hasn't been dispatched yet!");
7810aa09f0SMatt Davis     WTEntry.CyclesSpentInSQWhileReady +=
7910aa09f0SMatt Davis         TVEntry.CycleIssued - TVEntry.CycleReady;
80292da93dSAndrew Savonichev     if (CurrentCycle > TVEntry.CycleExecuted) {
8110aa09f0SMatt Davis       WTEntry.CyclesSpentAfterWBAndBeforeRetire +=
82d17d371cSAndrea Di Biagio           (CurrentCycle - 1) - TVEntry.CycleExecuted;
83292da93dSAndrew Savonichev     }
8410aa09f0SMatt Davis     break;
8510aa09f0SMatt Davis   }
8610aa09f0SMatt Davis   case HWInstructionEvent::Ready:
8710aa09f0SMatt Davis     Timeline[Index].CycleReady = CurrentCycle;
8810aa09f0SMatt Davis     break;
8910aa09f0SMatt Davis   case HWInstructionEvent::Issued:
9010aa09f0SMatt Davis     Timeline[Index].CycleIssued = CurrentCycle;
9110aa09f0SMatt Davis     break;
9210aa09f0SMatt Davis   case HWInstructionEvent::Executed:
9310aa09f0SMatt Davis     Timeline[Index].CycleExecuted = CurrentCycle;
9410aa09f0SMatt Davis     break;
9510aa09f0SMatt Davis   case HWInstructionEvent::Dispatched:
968b647dcfSAndrea Di Biagio     // There may be multiple dispatch events. Microcoded instructions that are
978b647dcfSAndrea Di Biagio     // expanded into multiple uOps may require multiple dispatch cycles. Here,
988b647dcfSAndrea Di Biagio     // we want to capture the first dispatch cycle.
998b647dcfSAndrea Di Biagio     if (Timeline[Index].CycleDispatched == -1)
1008b647dcfSAndrea Di Biagio       Timeline[Index].CycleDispatched = static_cast<int>(CurrentCycle);
10110aa09f0SMatt Davis     break;
10210aa09f0SMatt Davis   default:
10310aa09f0SMatt Davis     return;
10410aa09f0SMatt Davis   }
105d17d371cSAndrea Di Biagio   if (CurrentCycle < MaxCycle)
10610aa09f0SMatt Davis     LastCycle = std::max(LastCycle, CurrentCycle);
10710aa09f0SMatt Davis }
10810aa09f0SMatt Davis 
chooseColor(unsigned CumulativeCycles,unsigned Executions,int BufferSize)1094d41c332SRui Ueyama static raw_ostream::Colors chooseColor(unsigned CumulativeCycles,
1104269d64bSAndrea Di Biagio                                        unsigned Executions, int BufferSize) {
1114269d64bSAndrea Di Biagio   if (CumulativeCycles && BufferSize < 0)
112d17d371cSAndrea Di Biagio     return raw_ostream::MAGENTA;
1134269d64bSAndrea Di Biagio   unsigned Size = static_cast<unsigned>(BufferSize);
1144269d64bSAndrea Di Biagio   if (CumulativeCycles >= Size * Executions)
115d17d371cSAndrea Di Biagio     return raw_ostream::RED;
1164269d64bSAndrea Di Biagio   if ((CumulativeCycles * 2) >= Size * Executions)
117d17d371cSAndrea Di Biagio     return raw_ostream::YELLOW;
118d17d371cSAndrea Di Biagio   return raw_ostream::SAVEDCOLOR;
119d17d371cSAndrea Di Biagio }
120d17d371cSAndrea Di Biagio 
tryChangeColor(raw_ostream & OS,unsigned Cycles,unsigned Executions,int BufferSize)121d17d371cSAndrea Di Biagio static void tryChangeColor(raw_ostream &OS, unsigned Cycles,
1224269d64bSAndrea Di Biagio                            unsigned Executions, int BufferSize) {
123d17d371cSAndrea Di Biagio   if (!OS.has_colors())
124d17d371cSAndrea Di Biagio     return;
125d17d371cSAndrea Di Biagio 
1264d41c332SRui Ueyama   raw_ostream::Colors Color = chooseColor(Cycles, Executions, BufferSize);
127d17d371cSAndrea Di Biagio   if (Color == raw_ostream::SAVEDCOLOR) {
128d17d371cSAndrea Di Biagio     OS.resetColor();
129d17d371cSAndrea Di Biagio     return;
130d17d371cSAndrea Di Biagio   }
131d17d371cSAndrea Di Biagio   OS.changeColor(Color, /* bold */ true, /* BG */ false);
132d17d371cSAndrea Di Biagio }
133d17d371cSAndrea Di Biagio 
printWaitTimeEntry(formatted_raw_ostream & OS,const WaitTimeEntry & Entry,unsigned SourceIndex,unsigned Executions) const13410aa09f0SMatt Davis void TimelineView::printWaitTimeEntry(formatted_raw_ostream &OS,
13510aa09f0SMatt Davis                                       const WaitTimeEntry &Entry,
136d17d371cSAndrea Di Biagio                                       unsigned SourceIndex,
137d17d371cSAndrea Di Biagio                                       unsigned Executions) const {
138e02920feSWolfgang Pieb   bool PrintingTotals = SourceIndex == getSource().size();
139a5e65c1cSRoman Lebedev   unsigned CumulativeExecutions = PrintingTotals ? Timeline.size() : Executions;
140a5e65c1cSRoman Lebedev 
141a5e65c1cSRoman Lebedev   if (!PrintingTotals)
14210aa09f0SMatt Davis     OS << SourceIndex << '.';
143a5e65c1cSRoman Lebedev 
14410aa09f0SMatt Davis   OS.PadToColumn(7);
14510aa09f0SMatt Davis 
14610aa09f0SMatt Davis   double AverageTime1, AverageTime2, AverageTime3;
147a5e65c1cSRoman Lebedev   AverageTime1 =
14845685a1fSAndrea Di Biagio       (double)(Entry.CyclesSpentInSchedulerQueue * 10) / CumulativeExecutions;
14945685a1fSAndrea Di Biagio   AverageTime2 =
15045685a1fSAndrea Di Biagio       (double)(Entry.CyclesSpentInSQWhileReady * 10) / CumulativeExecutions;
15145685a1fSAndrea Di Biagio   AverageTime3 = (double)(Entry.CyclesSpentAfterWBAndBeforeRetire * 10) /
15245685a1fSAndrea Di Biagio                  CumulativeExecutions;
15310aa09f0SMatt Davis 
15410aa09f0SMatt Davis   OS << Executions;
15510aa09f0SMatt Davis   OS.PadToColumn(13);
156a5e65c1cSRoman Lebedev 
157a5e65c1cSRoman Lebedev   int BufferSize = PrintingTotals ? 0 : UsedBuffer[SourceIndex].second;
158a5e65c1cSRoman Lebedev   if (!PrintingTotals)
159a5e65c1cSRoman Lebedev     tryChangeColor(OS, Entry.CyclesSpentInSchedulerQueue, CumulativeExecutions,
160a5e65c1cSRoman Lebedev                    BufferSize);
16145685a1fSAndrea Di Biagio   OS << format("%.1f", floor(AverageTime1 + 0.5) / 10);
16210aa09f0SMatt Davis   OS.PadToColumn(20);
163a5e65c1cSRoman Lebedev   if (!PrintingTotals)
164a5e65c1cSRoman Lebedev     tryChangeColor(OS, Entry.CyclesSpentInSQWhileReady, CumulativeExecutions,
165a5e65c1cSRoman Lebedev                    BufferSize);
16645685a1fSAndrea Di Biagio   OS << format("%.1f", floor(AverageTime2 + 0.5) / 10);
16710aa09f0SMatt Davis   OS.PadToColumn(27);
168a5e65c1cSRoman Lebedev   if (!PrintingTotals)
169a5e65c1cSRoman Lebedev     tryChangeColor(OS, Entry.CyclesSpentAfterWBAndBeforeRetire,
170e02920feSWolfgang Pieb                    CumulativeExecutions,
171e02920feSWolfgang Pieb                    getSubTargetInfo().getSchedModel().MicroOpBufferSize);
17245685a1fSAndrea Di Biagio   OS << format("%.1f", floor(AverageTime3 + 0.5) / 10);
173d17d371cSAndrea Di Biagio 
174d17d371cSAndrea Di Biagio   if (OS.has_colors())
175d17d371cSAndrea Di Biagio     OS.resetColor();
17610aa09f0SMatt Davis   OS.PadToColumn(34);
17710aa09f0SMatt Davis }
17810aa09f0SMatt Davis 
printAverageWaitTimes(raw_ostream & OS) const17910aa09f0SMatt Davis void TimelineView::printAverageWaitTimes(raw_ostream &OS) const {
180d17d371cSAndrea Di Biagio   std::string Header =
181d17d371cSAndrea Di Biagio       "\n\nAverage Wait times (based on the timeline view):\n"
182d17d371cSAndrea Di Biagio       "[0]: Executions\n"
183d17d371cSAndrea Di Biagio       "[1]: Average time spent waiting in a scheduler's queue\n"
184d17d371cSAndrea Di Biagio       "[2]: Average time spent waiting in a scheduler's queue while ready\n"
185d17d371cSAndrea Di Biagio       "[3]: Average time elapsed from WB until retire stage\n\n"
186d17d371cSAndrea Di Biagio       "      [0]    [1]    [2]    [3]\n";
187d17d371cSAndrea Di Biagio   OS << Header;
188d17d371cSAndrea Di Biagio   formatted_raw_ostream FOS(OS);
189e02920feSWolfgang Pieb   unsigned Executions = Timeline.size() / getSource().size();
1907be45b0fSAndrea Di Biagio   unsigned IID = 0;
191e02920feSWolfgang Pieb   for (const MCInst &Inst : getSource()) {
1927be45b0fSAndrea Di Biagio     printWaitTimeEntry(FOS, WaitTime[IID], IID, Executions);
193e02920feSWolfgang Pieb     FOS << "   " << printInstructionString(Inst) << '\n';
19410aa09f0SMatt Davis     FOS.flush();
1957be45b0fSAndrea Di Biagio     ++IID;
19610aa09f0SMatt Davis   }
197a5e65c1cSRoman Lebedev 
198a5e65c1cSRoman Lebedev   // If the timeline contains more than one instruction,
199a5e65c1cSRoman Lebedev   // let's also print global averages.
200e02920feSWolfgang Pieb   if (getSource().size() != 1) {
201a5e65c1cSRoman Lebedev     WaitTimeEntry TotalWaitTime = std::accumulate(
202a5e65c1cSRoman Lebedev         WaitTime.begin(), WaitTime.end(), WaitTimeEntry{0, 0, 0},
203a5e65c1cSRoman Lebedev         [](const WaitTimeEntry &A, const WaitTimeEntry &B) {
204a5e65c1cSRoman Lebedev           return WaitTimeEntry{
205a5e65c1cSRoman Lebedev               A.CyclesSpentInSchedulerQueue + B.CyclesSpentInSchedulerQueue,
206a5e65c1cSRoman Lebedev               A.CyclesSpentInSQWhileReady + B.CyclesSpentInSQWhileReady,
207a5e65c1cSRoman Lebedev               A.CyclesSpentAfterWBAndBeforeRetire +
208a5e65c1cSRoman Lebedev                   B.CyclesSpentAfterWBAndBeforeRetire};
209a5e65c1cSRoman Lebedev         });
210a5e65c1cSRoman Lebedev     printWaitTimeEntry(FOS, TotalWaitTime, IID, Executions);
211a5e65c1cSRoman Lebedev     FOS << "   "
212a5e65c1cSRoman Lebedev         << "<total>" << '\n';
213e02920feSWolfgang Pieb     FOS.flush();
214a5e65c1cSRoman Lebedev   }
21510aa09f0SMatt Davis }
21610aa09f0SMatt Davis 
printTimelineViewEntry(formatted_raw_ostream & OS,const TimelineViewEntry & Entry,unsigned Iteration,unsigned SourceIndex) const21710aa09f0SMatt Davis void TimelineView::printTimelineViewEntry(formatted_raw_ostream &OS,
21810aa09f0SMatt Davis                                           const TimelineViewEntry &Entry,
21910aa09f0SMatt Davis                                           unsigned Iteration,
22010aa09f0SMatt Davis                                           unsigned SourceIndex) const {
22110aa09f0SMatt Davis   if (Iteration == 0 && SourceIndex == 0)
22210aa09f0SMatt Davis     OS << '\n';
22310aa09f0SMatt Davis   OS << '[' << Iteration << ',' << SourceIndex << ']';
22410aa09f0SMatt Davis   OS.PadToColumn(10);
2258b647dcfSAndrea Di Biagio   assert(Entry.CycleDispatched >= 0 && "Invalid TimelineViewEntry!");
2268b647dcfSAndrea Di Biagio   unsigned CycleDispatched = static_cast<unsigned>(Entry.CycleDispatched);
2278b647dcfSAndrea Di Biagio   for (unsigned I = 0, E = CycleDispatched; I < E; ++I)
22810aa09f0SMatt Davis     OS << ((I % 5 == 0) ? '.' : ' ');
22910aa09f0SMatt Davis   OS << TimelineView::DisplayChar::Dispatched;
2308b647dcfSAndrea Di Biagio   if (CycleDispatched != Entry.CycleExecuted) {
23110aa09f0SMatt Davis     // Zero latency instructions have the same value for CycleDispatched,
23210aa09f0SMatt Davis     // CycleIssued and CycleExecuted.
2338b647dcfSAndrea Di Biagio     for (unsigned I = CycleDispatched + 1, E = Entry.CycleIssued; I < E; ++I)
23410aa09f0SMatt Davis       OS << TimelineView::DisplayChar::Waiting;
23510aa09f0SMatt Davis     if (Entry.CycleIssued == Entry.CycleExecuted)
23610aa09f0SMatt Davis       OS << TimelineView::DisplayChar::DisplayChar::Executed;
23710aa09f0SMatt Davis     else {
2388b647dcfSAndrea Di Biagio       if (CycleDispatched != Entry.CycleIssued)
23910aa09f0SMatt Davis         OS << TimelineView::DisplayChar::Executing;
24010aa09f0SMatt Davis       for (unsigned I = Entry.CycleIssued + 1, E = Entry.CycleExecuted; I < E;
24110aa09f0SMatt Davis            ++I)
24210aa09f0SMatt Davis         OS << TimelineView::DisplayChar::Executing;
24310aa09f0SMatt Davis       OS << TimelineView::DisplayChar::Executed;
24410aa09f0SMatt Davis     }
24510aa09f0SMatt Davis   }
24610aa09f0SMatt Davis 
24710aa09f0SMatt Davis   for (unsigned I = Entry.CycleExecuted + 1, E = Entry.CycleRetired; I < E; ++I)
24810aa09f0SMatt Davis     OS << TimelineView::DisplayChar::RetireLag;
249292da93dSAndrew Savonichev   if (Entry.CycleExecuted < Entry.CycleRetired)
25010aa09f0SMatt Davis     OS << TimelineView::DisplayChar::Retired;
25110aa09f0SMatt Davis 
25210aa09f0SMatt Davis   // Skip other columns.
25310aa09f0SMatt Davis   for (unsigned I = Entry.CycleRetired + 1, E = LastCycle; I <= E; ++I)
25410aa09f0SMatt Davis     OS << ((I % 5 == 0 || I == LastCycle) ? '.' : ' ');
25510aa09f0SMatt Davis }
25610aa09f0SMatt Davis 
printTimelineHeader(formatted_raw_ostream & OS,unsigned Cycles)25710aa09f0SMatt Davis static void printTimelineHeader(formatted_raw_ostream &OS, unsigned Cycles) {
25810aa09f0SMatt Davis   OS << "\n\nTimeline view:\n";
25910aa09f0SMatt Davis   if (Cycles >= 10) {
26010aa09f0SMatt Davis     OS.PadToColumn(10);
26110aa09f0SMatt Davis     for (unsigned I = 0; I <= Cycles; ++I) {
26210aa09f0SMatt Davis       if (((I / 10) & 1) == 0)
26310aa09f0SMatt Davis         OS << ' ';
26410aa09f0SMatt Davis       else
26510aa09f0SMatt Davis         OS << I % 10;
26610aa09f0SMatt Davis     }
26710aa09f0SMatt Davis     OS << '\n';
26810aa09f0SMatt Davis   }
26910aa09f0SMatt Davis 
27010aa09f0SMatt Davis   OS << "Index";
27110aa09f0SMatt Davis   OS.PadToColumn(10);
27210aa09f0SMatt Davis   for (unsigned I = 0; I <= Cycles; ++I) {
27310aa09f0SMatt Davis     if (((I / 10) & 1) == 0)
27410aa09f0SMatt Davis       OS << I % 10;
27510aa09f0SMatt Davis     else
27610aa09f0SMatt Davis       OS << ' ';
27710aa09f0SMatt Davis   }
27810aa09f0SMatt Davis   OS << '\n';
27910aa09f0SMatt Davis }
28010aa09f0SMatt Davis 
printTimeline(raw_ostream & OS) const28110aa09f0SMatt Davis void TimelineView::printTimeline(raw_ostream &OS) const {
282d17d371cSAndrea Di Biagio   formatted_raw_ostream FOS(OS);
28310aa09f0SMatt Davis   printTimelineHeader(FOS, LastCycle);
28410aa09f0SMatt Davis   FOS.flush();
28510aa09f0SMatt Davis 
2867be45b0fSAndrea Di Biagio   unsigned IID = 0;
287e02920feSWolfgang Pieb   ArrayRef<llvm::MCInst> Source = getSource();
28884d00513SAndrea Di Biagio   const unsigned Iterations = Timeline.size() / Source.size();
2897be45b0fSAndrea Di Biagio   for (unsigned Iteration = 0; Iteration < Iterations; ++Iteration) {
29084d00513SAndrea Di Biagio     for (const MCInst &Inst : Source) {
2917be45b0fSAndrea Di Biagio       const TimelineViewEntry &Entry = Timeline[IID];
29270040de3SPatrick Holland       // When an instruction is retired after timeline-max-cycles,
29370040de3SPatrick Holland       // its CycleRetired is left at 0. However, it's possible for
29470040de3SPatrick Holland       // a 0 latency instruction to be retired during cycle 0 and we
29570040de3SPatrick Holland       // don't want to early exit in that case. The CycleExecuted
29670040de3SPatrick Holland       // attribute is set correctly whether or not it is greater
29770040de3SPatrick Holland       // than timeline-max-cycles so we can use that to ensure
29870040de3SPatrick Holland       // we don't early exit because of a 0 latency instruction.
2990a869ef3SDaniel Sanders       if (Entry.CycleRetired == 0 && Entry.CycleExecuted != 0) {
3000a869ef3SDaniel Sanders         FOS << "Truncated display due to cycle limit\n";
30170040de3SPatrick Holland         return;
3020a869ef3SDaniel Sanders       }
30310aa09f0SMatt Davis 
30484d00513SAndrea Di Biagio       unsigned SourceIndex = IID % Source.size();
30510aa09f0SMatt Davis       printTimelineViewEntry(FOS, Entry, Iteration, SourceIndex);
306e02920feSWolfgang Pieb       FOS << "   " << printInstructionString(Inst) << '\n';
30710aa09f0SMatt Davis       FOS.flush();
3087be45b0fSAndrea Di Biagio 
3097be45b0fSAndrea Di Biagio       ++IID;
3107be45b0fSAndrea Di Biagio     }
31110aa09f0SMatt Davis   }
31210aa09f0SMatt Davis }
313d38be2baSWolfgang Pieb 
toJSON() const314d38be2baSWolfgang Pieb json::Value TimelineView::toJSON() const {
315d38be2baSWolfgang Pieb   json::Array TimelineInfo;
316d38be2baSWolfgang Pieb 
317d38be2baSWolfgang Pieb   for (const TimelineViewEntry &TLE : Timeline) {
318*923dbb01SAndrea Di Biagio     // Check if the timeline-max-cycles has been reached.
319*923dbb01SAndrea Di Biagio     if (!TLE.CycleRetired && TLE.CycleExecuted)
320*923dbb01SAndrea Di Biagio       break;
321*923dbb01SAndrea Di Biagio 
322d38be2baSWolfgang Pieb     TimelineInfo.push_back(
323d38be2baSWolfgang Pieb         json::Object({{"CycleDispatched", TLE.CycleDispatched},
324d38be2baSWolfgang Pieb                       {"CycleReady", TLE.CycleReady},
325d38be2baSWolfgang Pieb                       {"CycleIssued", TLE.CycleIssued},
326d38be2baSWolfgang Pieb                       {"CycleExecuted", TLE.CycleExecuted},
327d38be2baSWolfgang Pieb                       {"CycleRetired", TLE.CycleRetired}}));
328d38be2baSWolfgang Pieb   }
329d38be2baSWolfgang Pieb   return json::Object({{"TimelineInfo", std::move(TimelineInfo)}});
330d38be2baSWolfgang Pieb }
33110aa09f0SMatt Davis } // namespace mca
3325a8fd657SFangrui Song } // namespace llvm
333