[llvm-mca] Move the logic that prints scheduler statistics from BackendStatistics to its own view.

Added flag -scheduler-stats to print scheduler related statistics.

llvm-svn: 329792
This commit is contained in:
Andrea Di Biagio 2018-04-11 11:37:46 +00:00
parent d928201ac5
commit 1cc29c045e
9 changed files with 244 additions and 131 deletions

View File

@ -139,8 +139,7 @@ option specifies "``-``", then the output will also be sent to standard output.
.. option:: -verbose
Enable verbose output. In particular, this flag enables a number of extra
statistics and performance counters for the dispatch logic, the reorder
buffer, the retire control unit and the register file.
statistics and performance counters for the retire control unit.
.. option:: -timeline
@ -170,6 +169,11 @@ option specifies "``-``", then the output will also be sent to standard output.
dispatch events, as well as static/dynamic dispatch stall events. This view
is disabled by default.
.. option:: -scheduler-stats
Enable extra scheduler statistics. This view collects and analyzes instruction
issue events. This view is disabled by default.
.. option:: -instruction-info
Enable the instruction info view. This is enabled by default.

View File

@ -1,7 +1,13 @@
# RUN: llvm-mca -march=aarch64 -mcpu=exynos-m3 -iterations=1 -verbose -resource-pressure=false -instruction-info=false < %s | FileCheck %s -check-prefix=ALL
# RUN: llvm-mca -march=aarch64 -mcpu=exynos-m1 -iterations=1 -verbose -resource-pressure=false -instruction-info=false < %s | FileCheck %s -check-prefix=ALL
# RUN: llvm-mca -march=aarch64 -mcpu=exynos-m3 -iterations=1 -scheduler-stats -resource-pressure=false -instruction-info=false < %s | FileCheck %s -check-prefix=ALL
# RUN: llvm-mca -march=aarch64 -mcpu=exynos-m1 -iterations=1 -scheduler-stats -resource-pressure=false -instruction-info=false < %s | FileCheck %s -check-prefix=ALL
b t
b t
# ALL: Schedulers - number of cycles where we saw N instructions issued:
# ALL-NEXT: [# issued], [# cycles]
# ALL-NEXT: 0, 1 (50.0%)
# ALL-NEXT: 1, 1 (50.0%)
# ALL: Scheduler's queue usage:
# ALL-NEXT: No scheduler resources used.

View File

@ -1,8 +1,31 @@
# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=1 -verbose < %s | FileCheck %s
# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=1 -scheduler-stats < %s | FileCheck %s
vmulps (%rsi), %xmm0, %xmm0
add %rsi, %rsi
# CHECK: Iterations: 1
# CHECK-NEXT: Instructions: 2
# CHECK-NEXT: Total Cycles: 10
# CHECK-NEXT: Dispatch Width: 2
# CHECK-NEXT: IPC: 0.20
# CHECK: Instruction Info:
# CHECK-NEXT: [1]: #uOps
# CHECK-NEXT: [2]: Latency
# CHECK-NEXT: [3]: RThroughput
# CHECK-NEXT: [4]: MayLoad
# CHECK-NEXT: [5]: MayStore
# CHECK-NEXT: [6]: HasSideEffects
# CHECK: [1] [2] [3] [4] [5] [6] Instructions:
# CHECK-NEXT: 1 7 1.00 * vmulps (%rsi), %xmm0, %xmm0
# CHECK-NEXT: 1 1 0.50 addq %rsi, %rsi
# CHECK: Schedulers - number of cycles where we saw N instructions issued:
# CHECK-NEXT: [# issued], [# cycles]
# CHECK-NEXT: 0, 9 (90.0%)
# CHECK-NEXT: 2, 1 (10.0%)
# CHECK: Scheduler's queue usage:
# CHECK-NEXT: JALU01, 1/20
# CHECK-NEXT: JFPU01, 1/18
@ -26,9 +49,10 @@ add %rsi, %rsi
# CHECK: Resource pressure per iteration:
# CHECK-NEXT: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13]
# CHECK-NEXT: - 1.00 - - 1.00 - 1.00 1.00 - - - - - -
# CHECK-NEXT: - 1.00 - - 1.00 - 1.00 1.00 - - - - - -
# CHECK: Resource pressure by instruction:
# CHECK-NEXT: [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] Instructions:
# CHECK-NEXT: - - - - 1.00 - 1.00 1.00 - - - - - - vmulps (%rsi), %xmm0, %xmm0
# CHECK-NEXT: - 1.00 - - - - - - - - - - - - addq %rsi, %rsi

View File

@ -21,42 +21,11 @@ using namespace llvm;
namespace mca {
void BackendStatistics::onInstructionEvent(const HWInstructionEvent &Event) {
switch (Event.Type) {
default:
break;
case HWInstructionEvent::Retired: {
if (Event.Type == HWInstructionEvent::Retired)
++NumRetired;
break;
}
case HWInstructionEvent::Issued:
++NumIssued;
}
}
void BackendStatistics::onReservedBuffers(ArrayRef<unsigned> Buffers) {
for (const unsigned Buffer : Buffers) {
if (BufferedResources.find(Buffer) != BufferedResources.end()) {
BufferUsage &BU = BufferedResources[Buffer];
BU.SlotsInUse++;
BU.MaxUsedSlots = std::max(BU.MaxUsedSlots, BU.SlotsInUse);
continue;
}
BufferedResources.insert(
std::pair<unsigned, BufferUsage>(Buffer, {1U, 1U}));
}
}
void BackendStatistics::onReleasedBuffers(ArrayRef<unsigned> Buffers) {
for (const unsigned Buffer : Buffers) {
assert(BufferedResources.find(Buffer) != BufferedResources.end() &&
"Buffered resource not in map?");
BufferUsage &BU = BufferedResources[Buffer];
BU.SlotsInUse--;
}
}
void BackendStatistics::printRetireUnitStatistics(llvm::raw_ostream &OS) const {
void BackendStatistics::printView(llvm::raw_ostream &OS) const {
std::string Buffer;
raw_string_ostream TempStream(Buffer);
TempStream << "\n\nRetire Control Unit - "
@ -78,46 +47,4 @@ void BackendStatistics::printRetireUnitStatistics(llvm::raw_ostream &OS) const {
OS << Buffer;
}
void BackendStatistics::printSchedulerStatistics(llvm::raw_ostream &OS) const {
std::string Buffer;
raw_string_ostream TempStream(Buffer);
TempStream << "\n\nSchedulers - number of cycles where we saw N instructions "
"issued:\n";
TempStream << "[# issued], [# cycles]\n";
for (const std::pair<unsigned, unsigned> &Entry : IssuedPerCycle) {
TempStream << " " << Entry.first << ", " << Entry.second << " ("
<< format("%.1f", ((double)Entry.second / NumCycles) * 100)
<< "%)\n";
}
TempStream.flush();
OS << Buffer;
}
void BackendStatistics::printSchedulerUsage(raw_ostream &OS,
const MCSchedModel &SM) const {
std::string Buffer;
raw_string_ostream TempStream(Buffer);
TempStream << "\n\nScheduler's queue usage:\n";
// Early exit if no buffered resources were consumed.
if (BufferedResources.empty()) {
TempStream << "No scheduler resources used.\n";
TempStream.flush();
OS << Buffer;
return;
}
for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
if (ProcResource.BufferSize <= 0)
continue;
const BufferUsage &BU = BufferedResources.lookup(I);
TempStream << ProcResource.Name << ", " << BU.MaxUsedSlots << '/'
<< ProcResource.BufferSize << '\n';
}
TempStream.flush();
OS << Buffer;
}
} // namespace mca

View File

@ -8,18 +8,12 @@
//===----------------------------------------------------------------------===//
/// \file
///
/// This file implements a printer class for printing generic Backend
/// statistics related to the scheduler and retire unit.
/// This file implements a View named BackendStatistics that knows how to
/// collect and print a few statistics related to the retire unit.
///
/// Example:
/// ========
///
/// Schedulers - number of cycles where we saw N instructions issued:
/// [# issued], [# cycles]
/// 0, 7 (5.4%)
/// 1, 4 (3.1%)
/// 2, 8 (6.2%)
///
/// Retire Control Unit - number of cycles where we saw N instructions retired:
/// [# retired], [# cycles]
/// 0, 9 (6.9%)
@ -27,11 +21,6 @@
/// 2, 1 (0.8%)
/// 4, 3 (2.3%)
///
/// Scheduler's queue usage:
/// JALU01, 0/20
/// JFPU01, 18/18
/// JLSAGU, 0/12
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_MCA_BACKENDSTATISTICS_H
@ -49,43 +38,21 @@ class BackendStatistics : public View {
using Histogram = llvm::DenseMap<unsigned, unsigned>;
Histogram RetiredPerCycle;
Histogram IssuedPerCycle;
unsigned NumIssued;
unsigned NumRetired;
unsigned NumCycles;
// Tracks the usage of a scheduler's queue.
struct BufferUsage {
unsigned SlotsInUse;
unsigned MaxUsedSlots;
};
// There is a map entry for each buffered resource in the scheduling model.
// Every time a buffer is consumed/freed, this view updates the corresponding
// entry.
llvm::DenseMap<unsigned, BufferUsage> BufferedResources;
void updateHistograms() {
IssuedPerCycle[NumIssued]++;
RetiredPerCycle[NumRetired]++;
NumIssued = 0;
NumRetired = 0;
}
void printRetireUnitStatistics(llvm::raw_ostream &OS) const;
void printSchedulerStatistics(llvm::raw_ostream &OS) const;
void printRCUStatistics(llvm::raw_ostream &OS, const Histogram &Histogram,
unsigned Cycles) const;
void printIssuePerCycle(const Histogram &IssuePerCycle,
unsigned TotalCycles) const;
void printSchedulerUsage(llvm::raw_ostream &OS,
const llvm::MCSchedModel &SM) const;
public:
BackendStatistics(const llvm::MCSubtargetInfo &sti)
: STI(sti), NumIssued(0), NumRetired(0), NumCycles(0) { }
: STI(sti), NumRetired(0), NumCycles(0) {}
void onInstructionEvent(const HWInstructionEvent &Event) override;
@ -93,19 +60,7 @@ public:
void onCycleEnd(unsigned Cycle) override { updateHistograms(); }
// Increases the number of used scheduler queue slots of every buffered
// resource in the Buffers set.
void onReservedBuffers(llvm::ArrayRef<unsigned> Buffers) override;
// Decreases by one the number of used scheduler queue slots of every
// buffered resource in the Buffers set.
void onReleasedBuffers(llvm::ArrayRef<unsigned> Buffers) override;
void printView(llvm::raw_ostream &OS) const override {
printSchedulerStatistics(OS);
printRetireUnitStatistics(OS);
printSchedulerUsage(OS, STI.getSchedModel());
}
void printView(llvm::raw_ostream &OS) const override;
};
} // namespace mca

View File

@ -26,6 +26,7 @@ add_llvm_tool(llvm-mca
RegisterFileStatistics.cpp
ResourcePressureView.cpp
Scheduler.cpp
SchedulerStatistics.cpp
Support.cpp
SummaryView.cpp
TimelineView.cpp

View File

@ -0,0 +1,92 @@
//===--------------------- SchedulerStatistics.cpp --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
///
/// This file implements the SchedulerStatistics interface.
///
//===----------------------------------------------------------------------===//
#include "SchedulerStatistics.h"
#include "llvm/Support/Format.h"
using namespace llvm;
namespace mca {
void SchedulerStatistics::onInstructionEvent(const HWInstructionEvent &Event) {
if (Event.Type == HWInstructionEvent::Issued)
++NumIssued;
}
void SchedulerStatistics::onReservedBuffers(ArrayRef<unsigned> Buffers) {
for (const unsigned Buffer : Buffers) {
if (BufferedResources.find(Buffer) != BufferedResources.end()) {
BufferUsage &BU = BufferedResources[Buffer];
BU.SlotsInUse++;
BU.MaxUsedSlots = std::max(BU.MaxUsedSlots, BU.SlotsInUse);
continue;
}
BufferedResources.insert(
std::pair<unsigned, BufferUsage>(Buffer, {1U, 1U}));
}
}
void SchedulerStatistics::onReleasedBuffers(ArrayRef<unsigned> Buffers) {
for (const unsigned Buffer : Buffers) {
assert(BufferedResources.find(Buffer) != BufferedResources.end() &&
"Buffered resource not in map?");
BufferUsage &BU = BufferedResources[Buffer];
BU.SlotsInUse--;
}
}
void SchedulerStatistics::printSchedulerStatistics(llvm::raw_ostream &OS) const {
std::string Buffer;
raw_string_ostream TempStream(Buffer);
TempStream << "\n\nSchedulers - number of cycles where we saw N instructions "
"issued:\n";
TempStream << "[# issued], [# cycles]\n";
for (const std::pair<unsigned, unsigned> &Entry : IssuedPerCycle) {
TempStream << " " << Entry.first << ", " << Entry.second << " ("
<< format("%.1f", ((double)Entry.second / NumCycles) * 100)
<< "%)\n";
}
TempStream.flush();
OS << Buffer;
}
void SchedulerStatistics::printSchedulerUsage(raw_ostream &OS,
const MCSchedModel &SM) const {
std::string Buffer;
raw_string_ostream TempStream(Buffer);
TempStream << "\n\nScheduler's queue usage:\n";
// Early exit if no buffered resources were consumed.
if (BufferedResources.empty()) {
TempStream << "No scheduler resources used.\n";
TempStream.flush();
OS << Buffer;
return;
}
for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
const MCProcResourceDesc &ProcResource = *SM.getProcResource(I);
if (ProcResource.BufferSize <= 0)
continue;
const BufferUsage &BU = BufferedResources.lookup(I);
TempStream << ProcResource.Name << ", " << BU.MaxUsedSlots << '/'
<< ProcResource.BufferSize << '\n';
}
TempStream.flush();
OS << Buffer;
}
} // namespace mca

View File

@ -0,0 +1,95 @@
//===--------------------- SchedulerStatistics.h ----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
///
/// This file defines class SchedulerStatistics. Class SchedulerStatistics is a
/// View that listens to instruction issue events in order to print general
/// statistics related to the hardware schedulers.
///
/// Example:
/// ========
///
/// Schedulers - number of cycles where we saw N instructions issued:
/// [# issued], [# cycles]
/// 0, 7 (5.4%)
/// 1, 4 (3.1%)
/// 2, 8 (6.2%)
///
/// Scheduler's queue usage:
/// JALU01, 0/20
/// JFPU01, 18/18
/// JLSAGU, 0/12
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_TOOLS_LLVM_MCA_SCHEDULERSTATISTICS_H
#define LLVM_TOOLS_LLVM_MCA_SCHEDULERSTATISTICS_H
#include "View.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/MC/MCSubtargetInfo.h"
namespace mca {
class SchedulerStatistics : public View {
const llvm::MCSubtargetInfo &STI;
using Histogram = llvm::DenseMap<unsigned, unsigned>;
Histogram IssuedPerCycle;
unsigned NumIssued;
unsigned NumCycles;
// Tracks the usage of a scheduler's queue.
struct BufferUsage {
unsigned SlotsInUse;
unsigned MaxUsedSlots;
};
llvm::DenseMap<unsigned, BufferUsage> BufferedResources;
void updateHistograms() {
IssuedPerCycle[NumIssued]++;
NumIssued = 0;
}
void printSchedulerStatistics(llvm::raw_ostream &OS) const;
void printIssuePerCycle(const Histogram &IssuePerCycle,
unsigned TotalCycles) const;
void printSchedulerUsage(llvm::raw_ostream &OS,
const llvm::MCSchedModel &SM) const;
public:
SchedulerStatistics(const llvm::MCSubtargetInfo &sti)
: STI(sti), NumIssued(0), NumCycles(0) { }
void onInstructionEvent(const HWInstructionEvent &Event) override;
void onCycleBegin(unsigned Cycle) override { NumCycles++; }
void onCycleEnd(unsigned Cycle) override { updateHistograms(); }
// Increases the number of used scheduler queue slots of every buffered
// resource in the Buffers set.
void onReservedBuffers(llvm::ArrayRef<unsigned> Buffers) override;
// Decreases by one the number of used scheduler queue slots of every
// buffered resource in the Buffers set.
void onReleasedBuffers(llvm::ArrayRef<unsigned> Buffers) override;
void printView(llvm::raw_ostream &OS) const override {
printSchedulerStatistics(OS);
printSchedulerUsage(OS, STI.getSchedModel());
}
};
} // namespace mca
#endif

View File

@ -29,6 +29,7 @@
#include "InstructionTables.h"
#include "RegisterFileStatistics.h"
#include "ResourcePressureView.h"
#include "SchedulerStatistics.h"
#include "SummaryView.h"
#include "TimelineView.h"
#include "llvm/MC/MCAsmInfo.h"
@ -99,6 +100,11 @@ static cl::opt<bool>
cl::desc("Print dispatch statistics"),
cl::init(false));
static cl::opt<bool>
PrintiSchedulerStats("scheduler-stats",
cl::desc("Print scheduler statistics"),
cl::init(false));
static cl::opt<bool>
PrintResourcePressureView("resource-pressure",
cl::desc("Print the resource pressure view"),
@ -432,6 +438,9 @@ int main(int argc, char **argv) {
if (PrintDispatchStats)
Printer.addView(llvm::make_unique<mca::DispatchStatistics>(*STI));
if (PrintiSchedulerStats)
Printer.addView(llvm::make_unique<mca::SchedulerStatistics>(*STI));
if (PrintModeVerbose)
Printer.addView(llvm::make_unique<mca::BackendStatistics>(*STI));