1*0b57cec5SDimitry Andric //===--------------------- RetireControlUnitStatistics.cpp ------*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric /// \file
9*0b57cec5SDimitry Andric ///
10*0b57cec5SDimitry Andric /// This file implements the RetireControlUnitStatistics interface.
11*0b57cec5SDimitry Andric ///
12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric #include "Views/RetireControlUnitStatistics.h"
15*0b57cec5SDimitry Andric #include "llvm/Support/Format.h"
16*0b57cec5SDimitry Andric 
17*0b57cec5SDimitry Andric namespace llvm {
18*0b57cec5SDimitry Andric namespace mca {
19*0b57cec5SDimitry Andric 
RetireControlUnitStatistics(const MCSchedModel & SM)20*0b57cec5SDimitry Andric RetireControlUnitStatistics::RetireControlUnitStatistics(const MCSchedModel &SM)
21*0b57cec5SDimitry Andric     : NumRetired(0), NumCycles(0), EntriesInUse(0), MaxUsedEntries(0),
22*0b57cec5SDimitry Andric       SumOfUsedEntries(0) {
23*0b57cec5SDimitry Andric   TotalROBEntries = SM.MicroOpBufferSize;
24*0b57cec5SDimitry Andric   if (SM.hasExtraProcessorInfo()) {
25*0b57cec5SDimitry Andric     const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo();
26*0b57cec5SDimitry Andric     if (EPI.ReorderBufferSize)
27*0b57cec5SDimitry Andric       TotalROBEntries = EPI.ReorderBufferSize;
28*0b57cec5SDimitry Andric   }
29*0b57cec5SDimitry Andric }
30*0b57cec5SDimitry Andric 
onEvent(const HWInstructionEvent & Event)31*0b57cec5SDimitry Andric void RetireControlUnitStatistics::onEvent(const HWInstructionEvent &Event) {
32*0b57cec5SDimitry Andric   if (Event.Type == HWInstructionEvent::Dispatched) {
33*0b57cec5SDimitry Andric     unsigned NumEntries =
34*0b57cec5SDimitry Andric         static_cast<const HWInstructionDispatchedEvent &>(Event).MicroOpcodes;
35*0b57cec5SDimitry Andric     EntriesInUse += NumEntries;
36*0b57cec5SDimitry Andric   }
37*0b57cec5SDimitry Andric 
38*0b57cec5SDimitry Andric   if (Event.Type == HWInstructionEvent::Retired) {
39*0b57cec5SDimitry Andric     unsigned ReleasedEntries = Event.IR.getInstruction()->getDesc().NumMicroOps;
40*0b57cec5SDimitry Andric     assert(EntriesInUse >= ReleasedEntries && "Invalid internal state!");
41*0b57cec5SDimitry Andric     EntriesInUse -= ReleasedEntries;
42*0b57cec5SDimitry Andric     ++NumRetired;
43*0b57cec5SDimitry Andric   }
44*0b57cec5SDimitry Andric }
45*0b57cec5SDimitry Andric 
onCycleEnd()46*0b57cec5SDimitry Andric void RetireControlUnitStatistics::onCycleEnd() {
47*0b57cec5SDimitry Andric   // Update histogram
48*0b57cec5SDimitry Andric   RetiredPerCycle[NumRetired]++;
49*0b57cec5SDimitry Andric   NumRetired = 0;
50*0b57cec5SDimitry Andric   ++NumCycles;
51*0b57cec5SDimitry Andric   MaxUsedEntries = std::max(MaxUsedEntries, EntriesInUse);
52*0b57cec5SDimitry Andric   SumOfUsedEntries += EntriesInUse;
53*0b57cec5SDimitry Andric }
54*0b57cec5SDimitry Andric 
printView(raw_ostream & OS) const55*0b57cec5SDimitry Andric void RetireControlUnitStatistics::printView(raw_ostream &OS) const {
56*0b57cec5SDimitry Andric   std::string Buffer;
57*0b57cec5SDimitry Andric   raw_string_ostream TempStream(Buffer);
58*0b57cec5SDimitry Andric   TempStream << "\n\nRetire Control Unit - "
59*0b57cec5SDimitry Andric              << "number of cycles where we saw N instructions retired:\n";
60*0b57cec5SDimitry Andric   TempStream << "[# retired], [# cycles]\n";
61*0b57cec5SDimitry Andric 
62*0b57cec5SDimitry Andric   for (const std::pair<const unsigned, unsigned> &Entry : RetiredPerCycle) {
63*0b57cec5SDimitry Andric     TempStream << " " << Entry.first;
64*0b57cec5SDimitry Andric     if (Entry.first < 10)
65*0b57cec5SDimitry Andric       TempStream << ",           ";
66*0b57cec5SDimitry Andric     else
67*0b57cec5SDimitry Andric       TempStream << ",          ";
68*0b57cec5SDimitry Andric     TempStream << Entry.second << "  ("
69*0b57cec5SDimitry Andric                << format("%.1f", ((double)Entry.second / NumCycles) * 100.0)
70*0b57cec5SDimitry Andric                << "%)\n";
71*0b57cec5SDimitry Andric   }
72*0b57cec5SDimitry Andric 
73*0b57cec5SDimitry Andric   unsigned AvgUsage = (double)SumOfUsedEntries / NumCycles;
74*0b57cec5SDimitry Andric   double MaxUsagePercentage =
75*0b57cec5SDimitry Andric       ((double)MaxUsedEntries / TotalROBEntries) * 100.0;
76*0b57cec5SDimitry Andric   double NormalizedMaxPercentage = floor((MaxUsagePercentage * 10) + 0.5) / 10;
77*0b57cec5SDimitry Andric   double AvgUsagePercentage = ((double)AvgUsage / TotalROBEntries) * 100.0;
78*0b57cec5SDimitry Andric   double NormalizedAvgPercentage = floor((AvgUsagePercentage * 10) + 0.5) / 10;
79*0b57cec5SDimitry Andric 
80*0b57cec5SDimitry Andric   TempStream << "\nTotal ROB Entries:                " << TotalROBEntries
81*0b57cec5SDimitry Andric              << "\nMax Used ROB Entries:             " << MaxUsedEntries
82*0b57cec5SDimitry Andric              << format("  ( %.1f%% )", NormalizedMaxPercentage)
83*0b57cec5SDimitry Andric              << "\nAverage Used ROB Entries per cy:  " << AvgUsage
84*0b57cec5SDimitry Andric              << format("  ( %.1f%% )\n", NormalizedAvgPercentage);
85*0b57cec5SDimitry Andric 
86*0b57cec5SDimitry Andric   TempStream.flush();
87*0b57cec5SDimitry Andric   OS << Buffer;
88*0b57cec5SDimitry Andric }
89*0b57cec5SDimitry Andric 
90*0b57cec5SDimitry Andric } // namespace mca
91 } // namespace llvm
92