[llvm] r357259 - [NFC][llvm-exegesis] Refactor ResolvedSchedClass & friends
Roman Lebedev via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 29 07:24:28 PDT 2019
Author: lebedevri
Date: Fri Mar 29 07:24:27 2019
New Revision: 357259
URL: http://llvm.org/viewvc/llvm-project?rev=357259&view=rev
Log:
[NFC][llvm-exegesis] Refactor ResolvedSchedClass & friends
Summary:
`ResolvedSchedClass` will need to be used outside of `Analysis`
(before `InstructionBenchmarkClustering` even), therefore promote
it into a non-private top-level class, and while there also
move all of the functions that are only called by `ResolvedSchedClass`
into that same new file.
Reviewers: courbet, gchatelet
Reviewed By: courbet
Subscribers: mgorny, tschuett, mgrang, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D59993
Added:
llvm/trunk/tools/llvm-exegesis/lib/SchedClassResolution.cpp
llvm/trunk/tools/llvm-exegesis/lib/SchedClassResolution.h
llvm/trunk/unittests/tools/llvm-exegesis/X86/SchedClassResolutionTest.cpp
- copied, changed from r357257, llvm/trunk/unittests/tools/llvm-exegesis/X86/AnalysisTest.cpp
Removed:
llvm/trunk/unittests/tools/llvm-exegesis/X86/AnalysisTest.cpp
Modified:
llvm/trunk/tools/llvm-exegesis/lib/Analysis.cpp
llvm/trunk/tools/llvm-exegesis/lib/Analysis.h
llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt
llvm/trunk/unittests/tools/llvm-exegesis/X86/CMakeLists.txt
Modified: llvm/trunk/tools/llvm-exegesis/lib/Analysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Analysis.cpp?rev=357259&r1=357258&r2=357259&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Analysis.cpp (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Analysis.cpp Fri Mar 29 07:24:27 2019
@@ -20,16 +20,6 @@ namespace exegesis {
static const char kCsvSep = ',';
-static unsigned resolveSchedClassId(const llvm::MCSubtargetInfo &STI,
- unsigned SchedClassId,
- const llvm::MCInst &MCI) {
- const auto &SM = STI.getSchedModel();
- while (SchedClassId && SM.getSchedClassDesc(SchedClassId)->isVariant())
- SchedClassId =
- STI.resolveVariantSchedClass(SchedClassId, &MCI, SM.getProcessorID());
- return SchedClassId;
-}
-
namespace {
enum EscapeTag { kEscapeCsv, kEscapeHtml, kEscapeHtmlString };
@@ -150,9 +140,9 @@ void Analysis::printInstructionRowCsv(co
OS << kCsvSep;
assert(!Point.Key.Instructions.empty());
const llvm::MCInst &MCI = Point.keyInstruction();
- const unsigned SchedClassId = resolveSchedClassId(
- *SubtargetInfo_, InstrInfo_->get(MCI.getOpcode()).getSchedClass(), MCI);
-
+ unsigned SchedClassId;
+ std::tie(SchedClassId, std::ignore) = ResolvedSchedClass::resolveSchedClassId(
+ *SubtargetInfo_, *InstrInfo_, MCI);
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
const llvm::MCSchedClassDesc *const SCDesc =
SubtargetInfo_->getSchedModel().getSchedClassDesc(SchedClassId);
@@ -239,11 +229,11 @@ Analysis::makePointsPerSchedClass() cons
// FIXME: we should be using the tuple of classes for instructions in the
// snippet as key.
const llvm::MCInst &MCI = Point.keyInstruction();
- unsigned SchedClassId = InstrInfo_->get(MCI.getOpcode()).getSchedClass();
- const bool WasVariant = SchedClassId && SubtargetInfo_->getSchedModel()
- .getSchedClassDesc(SchedClassId)
- ->isVariant();
- SchedClassId = resolveSchedClassId(*SubtargetInfo_, SchedClassId, MCI);
+ unsigned SchedClassId;
+ bool WasVariant;
+ std::tie(SchedClassId, WasVariant) =
+ ResolvedSchedClass::resolveSchedClassId(*SubtargetInfo_, *InstrInfo_,
+ MCI);
const auto IndexIt = SchedClassIdToIndex.find(SchedClassId);
if (IndexIt == SchedClassIdToIndex.end()) {
// Create a new entry.
@@ -347,92 +337,6 @@ void Analysis::printSchedClassClustersHt
OS << "</table>";
}
-// Return the non-redundant list of WriteProcRes used by the given sched class.
-// The scheduling model for LLVM is such that each instruction has a certain
-// number of uops which consume resources which are described by WriteProcRes
-// entries. Each entry describe how many cycles are spent on a specific ProcRes
-// kind.
-// For example, an instruction might have 3 uOps, one dispatching on P0
-// (ProcResIdx=1) and two on P06 (ProcResIdx = 7).
-// Note that LLVM additionally denormalizes resource consumption to include
-// usage of super resources by subresources. So in practice if there exists a
-// P016 (ProcResIdx=10), then the cycles consumed by P0 are also consumed by
-// P06 (ProcResIdx = 7) and P016 (ProcResIdx = 10), and the resources consumed
-// by P06 are also consumed by P016. In the figure below, parenthesized cycles
-// denote implied usage of superresources by subresources:
-// P0 P06 P016
-// uOp1 1 (1) (1)
-// uOp2 1 (1)
-// uOp3 1 (1)
-// =============================
-// 1 3 3
-// Eventually we end up with three entries for the WriteProcRes of the
-// instruction:
-// {ProcResIdx=1, Cycles=1} // P0
-// {ProcResIdx=7, Cycles=3} // P06
-// {ProcResIdx=10, Cycles=3} // P016
-//
-// Note that in this case, P016 does not contribute any cycles, so it would
-// be removed by this function.
-// FIXME: Move this to MCSubtargetInfo and use it in llvm-mca.
-static llvm::SmallVector<llvm::MCWriteProcResEntry, 8>
-getNonRedundantWriteProcRes(const llvm::MCSchedClassDesc &SCDesc,
- const llvm::MCSubtargetInfo &STI) {
- llvm::SmallVector<llvm::MCWriteProcResEntry, 8> Result;
- const auto &SM = STI.getSchedModel();
- const unsigned NumProcRes = SM.getNumProcResourceKinds();
-
- // This assumes that the ProcResDescs are sorted in topological order, which
- // is guaranteed by the tablegen backend.
- llvm::SmallVector<float, 32> ProcResUnitUsage(NumProcRes);
- for (const auto *WPR = STI.getWriteProcResBegin(&SCDesc),
- *const WPREnd = STI.getWriteProcResEnd(&SCDesc);
- WPR != WPREnd; ++WPR) {
- const llvm::MCProcResourceDesc *const ProcResDesc =
- SM.getProcResource(WPR->ProcResourceIdx);
- if (ProcResDesc->SubUnitsIdxBegin == nullptr) {
- // This is a ProcResUnit.
- Result.push_back({WPR->ProcResourceIdx, WPR->Cycles});
- ProcResUnitUsage[WPR->ProcResourceIdx] += WPR->Cycles;
- } else {
- // This is a ProcResGroup. First see if it contributes any cycles or if
- // it has cycles just from subunits.
- float RemainingCycles = WPR->Cycles;
- for (const auto *SubResIdx = ProcResDesc->SubUnitsIdxBegin;
- SubResIdx != ProcResDesc->SubUnitsIdxBegin + ProcResDesc->NumUnits;
- ++SubResIdx) {
- RemainingCycles -= ProcResUnitUsage[*SubResIdx];
- }
- if (RemainingCycles < 0.01f) {
- // The ProcResGroup contributes no cycles of its own.
- continue;
- }
- // The ProcResGroup contributes `RemainingCycles` cycles of its own.
- Result.push_back({WPR->ProcResourceIdx,
- static_cast<uint16_t>(std::round(RemainingCycles))});
- // Spread the remaining cycles over all subunits.
- for (const auto *SubResIdx = ProcResDesc->SubUnitsIdxBegin;
- SubResIdx != ProcResDesc->SubUnitsIdxBegin + ProcResDesc->NumUnits;
- ++SubResIdx) {
- ProcResUnitUsage[*SubResIdx] += RemainingCycles / ProcResDesc->NumUnits;
- }
- }
- }
- return Result;
-}
-
-Analysis::ResolvedSchedClass::ResolvedSchedClass(
- const llvm::MCSubtargetInfo &STI, unsigned ResolvedSchedClassId,
- bool WasVariant)
- : SchedClassId(ResolvedSchedClassId), SCDesc(STI.getSchedModel().getSchedClassDesc(ResolvedSchedClassId)),
- WasVariant(WasVariant),
- NonRedundantWriteProcRes(getNonRedundantWriteProcRes(*SCDesc, STI)),
- IdealizedProcResPressure(computeIdealizedProcResPressure(
- STI.getSchedModel(), NonRedundantWriteProcRes)) {
- assert((SCDesc == nullptr || !SCDesc->isVariant()) &&
- "ResolvedSchedClass should never be variant");
-}
-
void Analysis::SchedClassCluster::addPoint(
size_t PointId, const InstructionBenchmarkClustering &Clustering) {
PointIds.push_back(PointId);
@@ -737,117 +641,5 @@ llvm::Error Analysis::run<Analysis::Prin
return llvm::Error::success();
}
-// Distributes a pressure budget as evenly as possible on the provided subunits
-// given the already existing port pressure distribution.
-//
-// The algorithm is as follows: while there is remaining pressure to
-// distribute, find the subunits with minimal pressure, and distribute
-// remaining pressure equally up to the pressure of the unit with
-// second-to-minimal pressure.
-// For example, let's assume we want to distribute 2*P1256
-// (Subunits = [P1,P2,P5,P6]), and the starting DensePressure is:
-// DensePressure = P0 P1 P2 P3 P4 P5 P6 P7
-// 0.1 0.3 0.2 0.0 0.0 0.5 0.5 0.5
-// RemainingPressure = 2.0
-// We sort the subunits by pressure:
-// Subunits = [(P2,p=0.2), (P1,p=0.3), (P5,p=0.5), (P6, p=0.5)]
-// We'll first start by the subunits with minimal pressure, which are at
-// the beginning of the sorted array. In this example there is one (P2).
-// The subunit with second-to-minimal pressure is the next one in the
-// array (P1). So we distribute 0.1 pressure to P2, and remove 0.1 cycles
-// from the budget.
-// Subunits = [(P2,p=0.3), (P1,p=0.3), (P5,p=0.5), (P5,p=0.5)]
-// RemainingPressure = 1.9
-// We repeat this process: distribute 0.2 pressure on each of the minimal
-// P2 and P1, decrease budget by 2*0.2:
-// Subunits = [(P2,p=0.5), (P1,p=0.5), (P5,p=0.5), (P5,p=0.5)]
-// RemainingPressure = 1.5
-// There are no second-to-minimal subunits so we just share the remaining
-// budget (1.5 cycles) equally:
-// Subunits = [(P2,p=0.875), (P1,p=0.875), (P5,p=0.875), (P5,p=0.875)]
-// RemainingPressure = 0.0
-// We stop as there is no remaining budget to distribute.
-void distributePressure(float RemainingPressure,
- llvm::SmallVector<uint16_t, 32> Subunits,
- llvm::SmallVector<float, 32> &DensePressure) {
- // Find the number of subunits with minimal pressure (they are at the
- // front).
- llvm::sort(Subunits, [&DensePressure](const uint16_t A, const uint16_t B) {
- return DensePressure[A] < DensePressure[B];
- });
- const auto getPressureForSubunit = [&DensePressure,
- &Subunits](size_t I) -> float & {
- return DensePressure[Subunits[I]];
- };
- size_t NumMinimalSU = 1;
- while (NumMinimalSU < Subunits.size() &&
- getPressureForSubunit(NumMinimalSU) == getPressureForSubunit(0)) {
- ++NumMinimalSU;
- }
- while (RemainingPressure > 0.0f) {
- if (NumMinimalSU == Subunits.size()) {
- // All units are minimal, just distribute evenly and be done.
- for (size_t I = 0; I < NumMinimalSU; ++I) {
- getPressureForSubunit(I) += RemainingPressure / NumMinimalSU;
- }
- return;
- }
- // Distribute the remaining pressure equally.
- const float MinimalPressure = getPressureForSubunit(NumMinimalSU - 1);
- const float SecondToMinimalPressure = getPressureForSubunit(NumMinimalSU);
- assert(MinimalPressure < SecondToMinimalPressure);
- const float Increment = SecondToMinimalPressure - MinimalPressure;
- if (RemainingPressure <= NumMinimalSU * Increment) {
- // There is not enough remaining pressure.
- for (size_t I = 0; I < NumMinimalSU; ++I) {
- getPressureForSubunit(I) += RemainingPressure / NumMinimalSU;
- }
- return;
- }
- // Bump all minimal pressure subunits to `SecondToMinimalPressure`.
- for (size_t I = 0; I < NumMinimalSU; ++I) {
- getPressureForSubunit(I) = SecondToMinimalPressure;
- RemainingPressure -= SecondToMinimalPressure;
- }
- while (NumMinimalSU < Subunits.size() &&
- getPressureForSubunit(NumMinimalSU) == SecondToMinimalPressure) {
- ++NumMinimalSU;
- }
- }
-}
-
-std::vector<std::pair<uint16_t, float>> computeIdealizedProcResPressure(
- const llvm::MCSchedModel &SM,
- llvm::SmallVector<llvm::MCWriteProcResEntry, 8> WPRS) {
- // DensePressure[I] is the port pressure for Proc Resource I.
- llvm::SmallVector<float, 32> DensePressure(SM.getNumProcResourceKinds());
- llvm::sort(WPRS, [](const llvm::MCWriteProcResEntry &A,
- const llvm::MCWriteProcResEntry &B) {
- return A.ProcResourceIdx < B.ProcResourceIdx;
- });
- for (const llvm::MCWriteProcResEntry &WPR : WPRS) {
- // Get units for the entry.
- const llvm::MCProcResourceDesc *const ProcResDesc =
- SM.getProcResource(WPR.ProcResourceIdx);
- if (ProcResDesc->SubUnitsIdxBegin == nullptr) {
- // This is a ProcResUnit.
- DensePressure[WPR.ProcResourceIdx] += WPR.Cycles;
- } else {
- // This is a ProcResGroup.
- llvm::SmallVector<uint16_t, 32> Subunits(ProcResDesc->SubUnitsIdxBegin,
- ProcResDesc->SubUnitsIdxBegin +
- ProcResDesc->NumUnits);
- distributePressure(WPR.Cycles, Subunits, DensePressure);
- }
- }
- // Turn dense pressure into sparse pressure by removing zero entries.
- std::vector<std::pair<uint16_t, float>> Pressure;
- for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
- if (DensePressure[I] > 0.0f)
- Pressure.emplace_back(I, DensePressure[I]);
- }
- return Pressure;
-}
-
} // namespace exegesis
} // namespace llvm
Modified: llvm/trunk/tools/llvm-exegesis/lib/Analysis.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/Analysis.h?rev=357259&r1=357258&r2=357259&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/Analysis.h (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/Analysis.h Fri Mar 29 07:24:27 2019
@@ -15,6 +15,7 @@
#define LLVM_TOOLS_LLVM_EXEGESIS_ANALYSIS_H
#include "Clustering.h"
+#include "SchedClassResolution.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
#include "llvm/MC/MCInstPrinter.h"
@@ -51,19 +52,6 @@ public:
private:
using ClusterId = InstructionBenchmarkClustering::ClusterId;
- // An llvm::MCSchedClassDesc augmented with some additional data.
- struct ResolvedSchedClass {
- ResolvedSchedClass(const llvm::MCSubtargetInfo &STI,
- unsigned ResolvedSchedClassId, bool WasVariant);
-
- const unsigned SchedClassId;
- const llvm::MCSchedClassDesc *const SCDesc;
- const bool WasVariant; // Whether the original class was variant.
- const llvm::SmallVector<llvm::MCWriteProcResEntry, 8>
- NonRedundantWriteProcRes;
- const std::vector<std::pair<uint16_t, float>> IdealizedProcResPressure;
- };
-
// Represents the intersection of a sched class and a cluster.
class SchedClassCluster {
public:
@@ -137,13 +125,6 @@ private:
const bool AnalysisDisplayUnstableOpcodes_;
};
-// Computes the idealized ProcRes Unit pressure. This is the expected
-// distribution if the CPU scheduler can distribute the load as evenly as
-// possible.
-std::vector<std::pair<uint16_t, float>> computeIdealizedProcResPressure(
- const llvm::MCSchedModel &SM,
- llvm::SmallVector<llvm::MCWriteProcResEntry, 8> WPRS);
-
} // namespace exegesis
} // namespace llvm
Modified: llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt?rev=357259&r1=357258&r2=357259&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt (original)
+++ llvm/trunk/tools/llvm-exegesis/lib/CMakeLists.txt Fri Mar 29 07:24:27 2019
@@ -28,8 +28,9 @@ add_library(LLVMExegesis
MCInstrDescView.cpp
PerfHelper.cpp
RegisterAliasing.cpp
- SnippetGenerator.cpp
RegisterValue.cpp
+ SchedClassResolution.cpp
+ SnippetGenerator.cpp
Target.cpp
Uops.cpp
)
Added: llvm/trunk/tools/llvm-exegesis/lib/SchedClassResolution.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/SchedClassResolution.cpp?rev=357259&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/SchedClassResolution.cpp (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/SchedClassResolution.cpp Fri Mar 29 07:24:27 2019
@@ -0,0 +1,243 @@
+//===-- SchedClassResolution.cpp --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SchedClassResolution.h"
+#include "BenchmarkResult.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <limits>
+#include <unordered_set>
+#include <vector>
+
+namespace llvm {
+namespace exegesis {
+
+// Return the non-redundant list of WriteProcRes used by the given sched class.
+// The scheduling model for LLVM is such that each instruction has a certain
+// number of uops which consume resources which are described by WriteProcRes
+// entries. Each entry describe how many cycles are spent on a specific ProcRes
+// kind.
+// For example, an instruction might have 3 uOps, one dispatching on P0
+// (ProcResIdx=1) and two on P06 (ProcResIdx = 7).
+// Note that LLVM additionally denormalizes resource consumption to include
+// usage of super resources by subresources. So in practice if there exists a
+// P016 (ProcResIdx=10), then the cycles consumed by P0 are also consumed by
+// P06 (ProcResIdx = 7) and P016 (ProcResIdx = 10), and the resources consumed
+// by P06 are also consumed by P016. In the figure below, parenthesized cycles
+// denote implied usage of superresources by subresources:
+// P0 P06 P016
+// uOp1 1 (1) (1)
+// uOp2 1 (1)
+// uOp3 1 (1)
+// =============================
+// 1 3 3
+// Eventually we end up with three entries for the WriteProcRes of the
+// instruction:
+// {ProcResIdx=1, Cycles=1} // P0
+// {ProcResIdx=7, Cycles=3} // P06
+// {ProcResIdx=10, Cycles=3} // P016
+//
+// Note that in this case, P016 does not contribute any cycles, so it would
+// be removed by this function.
+// FIXME: Move this to MCSubtargetInfo and use it in llvm-mca.
+static llvm::SmallVector<llvm::MCWriteProcResEntry, 8>
+getNonRedundantWriteProcRes(const llvm::MCSchedClassDesc &SCDesc,
+ const llvm::MCSubtargetInfo &STI) {
+ llvm::SmallVector<llvm::MCWriteProcResEntry, 8> Result;
+ const auto &SM = STI.getSchedModel();
+ const unsigned NumProcRes = SM.getNumProcResourceKinds();
+
+ // This assumes that the ProcResDescs are sorted in topological order, which
+ // is guaranteed by the tablegen backend.
+ llvm::SmallVector<float, 32> ProcResUnitUsage(NumProcRes);
+ for (const auto *WPR = STI.getWriteProcResBegin(&SCDesc),
+ *const WPREnd = STI.getWriteProcResEnd(&SCDesc);
+ WPR != WPREnd; ++WPR) {
+ const llvm::MCProcResourceDesc *const ProcResDesc =
+ SM.getProcResource(WPR->ProcResourceIdx);
+ if (ProcResDesc->SubUnitsIdxBegin == nullptr) {
+ // This is a ProcResUnit.
+ Result.push_back({WPR->ProcResourceIdx, WPR->Cycles});
+ ProcResUnitUsage[WPR->ProcResourceIdx] += WPR->Cycles;
+ } else {
+ // This is a ProcResGroup. First see if it contributes any cycles or if
+ // it has cycles just from subunits.
+ float RemainingCycles = WPR->Cycles;
+ for (const auto *SubResIdx = ProcResDesc->SubUnitsIdxBegin;
+ SubResIdx != ProcResDesc->SubUnitsIdxBegin + ProcResDesc->NumUnits;
+ ++SubResIdx) {
+ RemainingCycles -= ProcResUnitUsage[*SubResIdx];
+ }
+ if (RemainingCycles < 0.01f) {
+ // The ProcResGroup contributes no cycles of its own.
+ continue;
+ }
+ // The ProcResGroup contributes `RemainingCycles` cycles of its own.
+ Result.push_back({WPR->ProcResourceIdx,
+ static_cast<uint16_t>(std::round(RemainingCycles))});
+ // Spread the remaining cycles over all subunits.
+ for (const auto *SubResIdx = ProcResDesc->SubUnitsIdxBegin;
+ SubResIdx != ProcResDesc->SubUnitsIdxBegin + ProcResDesc->NumUnits;
+ ++SubResIdx) {
+ ProcResUnitUsage[*SubResIdx] += RemainingCycles / ProcResDesc->NumUnits;
+ }
+ }
+ }
+ return Result;
+}
+
+// Distributes a pressure budget as evenly as possible on the provided subunits
+// given the already existing port pressure distribution.
+//
+// The algorithm is as follows: while there is remaining pressure to
+// distribute, find the subunits with minimal pressure, and distribute
+// remaining pressure equally up to the pressure of the unit with
+// second-to-minimal pressure.
+// For example, let's assume we want to distribute 2*P1256
+// (Subunits = [P1,P2,P5,P6]), and the starting DensePressure is:
+// DensePressure = P0 P1 P2 P3 P4 P5 P6 P7
+// 0.1 0.3 0.2 0.0 0.0 0.5 0.5 0.5
+// RemainingPressure = 2.0
+// We sort the subunits by pressure:
+// Subunits = [(P2,p=0.2), (P1,p=0.3), (P5,p=0.5), (P6, p=0.5)]
+// We'll first start by the subunits with minimal pressure, which are at
+// the beginning of the sorted array. In this example there is one (P2).
+// The subunit with second-to-minimal pressure is the next one in the
+// array (P1). So we distribute 0.1 pressure to P2, and remove 0.1 cycles
+// from the budget.
+// Subunits = [(P2,p=0.3), (P1,p=0.3), (P5,p=0.5), (P5,p=0.5)]
+// RemainingPressure = 1.9
+// We repeat this process: distribute 0.2 pressure on each of the minimal
+// P2 and P1, decrease budget by 2*0.2:
+// Subunits = [(P2,p=0.5), (P1,p=0.5), (P5,p=0.5), (P5,p=0.5)]
+// RemainingPressure = 1.5
+// There are no second-to-minimal subunits so we just share the remaining
+// budget (1.5 cycles) equally:
+// Subunits = [(P2,p=0.875), (P1,p=0.875), (P5,p=0.875), (P5,p=0.875)]
+// RemainingPressure = 0.0
+// We stop as there is no remaining budget to distribute.
+static void distributePressure(float RemainingPressure,
+ llvm::SmallVector<uint16_t, 32> Subunits,
+ llvm::SmallVector<float, 32> &DensePressure) {
+ // Find the number of subunits with minimal pressure (they are at the
+ // front).
+ llvm::sort(Subunits, [&DensePressure](const uint16_t A, const uint16_t B) {
+ return DensePressure[A] < DensePressure[B];
+ });
+ const auto getPressureForSubunit = [&DensePressure,
+ &Subunits](size_t I) -> float & {
+ return DensePressure[Subunits[I]];
+ };
+ size_t NumMinimalSU = 1;
+ while (NumMinimalSU < Subunits.size() &&
+ getPressureForSubunit(NumMinimalSU) == getPressureForSubunit(0)) {
+ ++NumMinimalSU;
+ }
+ while (RemainingPressure > 0.0f) {
+ if (NumMinimalSU == Subunits.size()) {
+ // All units are minimal, just distribute evenly and be done.
+ for (size_t I = 0; I < NumMinimalSU; ++I) {
+ getPressureForSubunit(I) += RemainingPressure / NumMinimalSU;
+ }
+ return;
+ }
+ // Distribute the remaining pressure equally.
+ const float MinimalPressure = getPressureForSubunit(NumMinimalSU - 1);
+ const float SecondToMinimalPressure = getPressureForSubunit(NumMinimalSU);
+ assert(MinimalPressure < SecondToMinimalPressure);
+ const float Increment = SecondToMinimalPressure - MinimalPressure;
+ if (RemainingPressure <= NumMinimalSU * Increment) {
+ // There is not enough remaining pressure.
+ for (size_t I = 0; I < NumMinimalSU; ++I) {
+ getPressureForSubunit(I) += RemainingPressure / NumMinimalSU;
+ }
+ return;
+ }
+ // Bump all minimal pressure subunits to `SecondToMinimalPressure`.
+ for (size_t I = 0; I < NumMinimalSU; ++I) {
+ getPressureForSubunit(I) = SecondToMinimalPressure;
+ RemainingPressure -= SecondToMinimalPressure;
+ }
+ while (NumMinimalSU < Subunits.size() &&
+ getPressureForSubunit(NumMinimalSU) == SecondToMinimalPressure) {
+ ++NumMinimalSU;
+ }
+ }
+}
+
+std::vector<std::pair<uint16_t, float>> computeIdealizedProcResPressure(
+ const llvm::MCSchedModel &SM,
+ llvm::SmallVector<llvm::MCWriteProcResEntry, 8> WPRS) {
+ // DensePressure[I] is the port pressure for Proc Resource I.
+ llvm::SmallVector<float, 32> DensePressure(SM.getNumProcResourceKinds());
+ llvm::sort(WPRS, [](const llvm::MCWriteProcResEntry &A,
+ const llvm::MCWriteProcResEntry &B) {
+ return A.ProcResourceIdx < B.ProcResourceIdx;
+ });
+ for (const llvm::MCWriteProcResEntry &WPR : WPRS) {
+ // Get units for the entry.
+ const llvm::MCProcResourceDesc *const ProcResDesc =
+ SM.getProcResource(WPR.ProcResourceIdx);
+ if (ProcResDesc->SubUnitsIdxBegin == nullptr) {
+ // This is a ProcResUnit.
+ DensePressure[WPR.ProcResourceIdx] += WPR.Cycles;
+ } else {
+ // This is a ProcResGroup.
+ llvm::SmallVector<uint16_t, 32> Subunits(ProcResDesc->SubUnitsIdxBegin,
+ ProcResDesc->SubUnitsIdxBegin +
+ ProcResDesc->NumUnits);
+ distributePressure(WPR.Cycles, Subunits, DensePressure);
+ }
+ }
+ // Turn dense pressure into sparse pressure by removing zero entries.
+ std::vector<std::pair<uint16_t, float>> Pressure;
+ for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
+ if (DensePressure[I] > 0.0f)
+ Pressure.emplace_back(I, DensePressure[I]);
+ }
+ return Pressure;
+}
+
+ResolvedSchedClass::ResolvedSchedClass(const llvm::MCSubtargetInfo &STI,
+ unsigned ResolvedSchedClassId,
+ bool WasVariant)
+ : SchedClassId(ResolvedSchedClassId),
+ SCDesc(STI.getSchedModel().getSchedClassDesc(ResolvedSchedClassId)),
+ WasVariant(WasVariant),
+ NonRedundantWriteProcRes(getNonRedundantWriteProcRes(*SCDesc, STI)),
+ IdealizedProcResPressure(computeIdealizedProcResPressure(
+ STI.getSchedModel(), NonRedundantWriteProcRes)) {
+ assert((SCDesc == nullptr || !SCDesc->isVariant()) &&
+ "ResolvedSchedClass should never be variant");
+}
+
+static unsigned ResolveVariantSchedClassId(const llvm::MCSubtargetInfo &STI,
+ unsigned SchedClassId,
+ const llvm::MCInst &MCI) {
+ const auto &SM = STI.getSchedModel();
+ while (SchedClassId && SM.getSchedClassDesc(SchedClassId)->isVariant())
+ SchedClassId =
+ STI.resolveVariantSchedClass(SchedClassId, &MCI, SM.getProcessorID());
+ return SchedClassId;
+}
+
+std::pair<unsigned /*SchedClassId*/, bool /*WasVariant*/>
+ResolvedSchedClass::resolveSchedClassId(
+ const llvm::MCSubtargetInfo &SubtargetInfo,
+ const llvm::MCInstrInfo &InstrInfo, const llvm::MCInst &MCI) {
+ unsigned SchedClassId = InstrInfo.get(MCI.getOpcode()).getSchedClass();
+ const bool WasVariant = SchedClassId && SubtargetInfo.getSchedModel()
+ .getSchedClassDesc(SchedClassId)
+ ->isVariant();
+ SchedClassId = ResolveVariantSchedClassId(SubtargetInfo, SchedClassId, MCI);
+ return std::make_pair(SchedClassId, WasVariant);
+}
+
+} // namespace exegesis
+} // namespace llvm
Added: llvm/trunk/tools/llvm-exegesis/lib/SchedClassResolution.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-exegesis/lib/SchedClassResolution.h?rev=357259&view=auto
==============================================================================
--- llvm/trunk/tools/llvm-exegesis/lib/SchedClassResolution.h (added)
+++ llvm/trunk/tools/llvm-exegesis/lib/SchedClassResolution.h Fri Mar 29 07:24:27 2019
@@ -0,0 +1,58 @@
+//===-- SchedClassResolution.h ----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Analysis output for benchmark results.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_EXEGESIS_SCHEDCLASSRESOLUTION_H
+#define LLVM_TOOLS_LLVM_EXEGESIS_SCHEDCLASSRESOLUTION_H
+
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace exegesis {
+
+// Computes the idealized ProcRes Unit pressure. This is the expected
+// distribution if the CPU scheduler can distribute the load as evenly as
+// possible.
+std::vector<std::pair<uint16_t, float>> computeIdealizedProcResPressure(
+ const llvm::MCSchedModel &SM,
+ llvm::SmallVector<llvm::MCWriteProcResEntry, 8> WPRS);
+
+// An llvm::MCSchedClassDesc augmented with some additional data.
+struct ResolvedSchedClass {
+ ResolvedSchedClass(const llvm::MCSubtargetInfo &STI,
+ unsigned ResolvedSchedClassId, bool WasVariant);
+
+ static std::pair<unsigned /*SchedClassId*/, bool /*WasVariant*/>
+ resolveSchedClassId(const llvm::MCSubtargetInfo &SubtargetInfo,
+ const llvm::MCInstrInfo &InstrInfo,
+ const llvm::MCInst &MCI);
+
+ const unsigned SchedClassId;
+ const llvm::MCSchedClassDesc *const SCDesc;
+ const bool WasVariant; // Whether the original class was variant.
+ const llvm::SmallVector<llvm::MCWriteProcResEntry, 8>
+ NonRedundantWriteProcRes;
+ const std::vector<std::pair<uint16_t, float>> IdealizedProcResPressure;
+};
+
+} // namespace exegesis
+} // namespace llvm
+
+#endif // LLVM_TOOLS_LLVM_EXEGESIS_SCHEDCLASSRESOLUTION_H
Removed: llvm/trunk/unittests/tools/llvm-exegesis/X86/AnalysisTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/X86/AnalysisTest.cpp?rev=357258&view=auto
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/X86/AnalysisTest.cpp (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/X86/AnalysisTest.cpp (removed)
@@ -1,112 +0,0 @@
-//===-- AnalysisTest.cpp ---------------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "Analysis.h"
-
-#include <cassert>
-#include <memory>
-
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/TargetSelect.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-namespace llvm {
-namespace exegesis {
-namespace {
-
-using testing::Pair;
-using testing::UnorderedElementsAre;
-
-class AnalysisTest : public ::testing::Test {
-protected:
- AnalysisTest() {
- const std::string TT = "x86_64-unknown-linux";
- std::string error;
- const llvm::Target *const TheTarget =
- llvm::TargetRegistry::lookupTarget(TT, error);
- if (!TheTarget) {
- llvm::errs() << error << "\n";
- return;
- }
- STI.reset(TheTarget->createMCSubtargetInfo(TT, "haswell", ""));
-
- // Compute the ProxResIdx of ports uses in tests.
- const auto &SM = STI->getSchedModel();
- for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
- const std::string Name = SM.getProcResource(I)->Name;
- if (Name == "HWPort0") {
- P0Idx = I;
- } else if (Name == "HWPort1") {
- P1Idx = I;
- } else if (Name == "HWPort5") {
- P5Idx = I;
- } else if (Name == "HWPort6") {
- P6Idx = I;
- } else if (Name == "HWPort05") {
- P05Idx = I;
- } else if (Name == "HWPort0156") {
- P0156Idx = I;
- }
- }
- EXPECT_NE(P0Idx, 0);
- EXPECT_NE(P1Idx, 0);
- EXPECT_NE(P5Idx, 0);
- EXPECT_NE(P6Idx, 0);
- EXPECT_NE(P05Idx, 0);
- EXPECT_NE(P0156Idx, 0);
- }
-
- static void SetUpTestCase() {
- LLVMInitializeX86TargetInfo();
- LLVMInitializeX86Target();
- LLVMInitializeX86TargetMC();
- }
-
-protected:
- std::unique_ptr<const llvm::MCSubtargetInfo> STI;
- uint16_t P0Idx = 0;
- uint16_t P1Idx = 0;
- uint16_t P5Idx = 0;
- uint16_t P6Idx = 0;
- uint16_t P05Idx = 0;
- uint16_t P0156Idx = 0;
-};
-
-TEST_F(AnalysisTest, ComputeIdealizedProcResPressure_2P0) {
- const auto Pressure =
- computeIdealizedProcResPressure(STI->getSchedModel(), {{P0Idx, 2}});
- EXPECT_THAT(Pressure, UnorderedElementsAre(Pair(P0Idx, 2.0)));
-}
-
-TEST_F(AnalysisTest, ComputeIdealizedProcResPressure_2P05) {
- const auto Pressure =
- computeIdealizedProcResPressure(STI->getSchedModel(), {{P05Idx, 2}});
- EXPECT_THAT(Pressure,
- UnorderedElementsAre(Pair(P0Idx, 1.0), Pair(P5Idx, 1.0)));
-}
-
-TEST_F(AnalysisTest, ComputeIdealizedProcResPressure_2P05_2P0156) {
- const auto Pressure = computeIdealizedProcResPressure(
- STI->getSchedModel(), {{P05Idx, 2}, {P0156Idx, 2}});
- EXPECT_THAT(Pressure,
- UnorderedElementsAre(Pair(P0Idx, 1.0), Pair(P1Idx, 1.0),
- Pair(P5Idx, 1.0), Pair(P6Idx, 1.0)));
-}
-
-TEST_F(AnalysisTest, ComputeIdealizedProcResPressure_1P1_1P05_2P0156) {
- const auto Pressure = computeIdealizedProcResPressure(
- STI->getSchedModel(), {{P1Idx, 1}, {P05Idx, 1}, {P0156Idx, 2}});
- EXPECT_THAT(Pressure,
- UnorderedElementsAre(Pair(P0Idx, 1.0), Pair(P1Idx, 1.0),
- Pair(P5Idx, 1.0), Pair(P6Idx, 1.0)));
-}
-
-} // namespace
-} // namespace exegesis
-} // namespace llvm
Modified: llvm/trunk/unittests/tools/llvm-exegesis/X86/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/X86/CMakeLists.txt?rev=357259&r1=357258&r2=357259&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/X86/CMakeLists.txt (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/X86/CMakeLists.txt Fri Mar 29 07:24:27 2019
@@ -15,10 +15,10 @@ set(LLVM_LINK_COMPONENTS
add_llvm_unittest(LLVMExegesisX86Tests
AssemblerTest.cpp
- AnalysisTest.cpp
BenchmarkResultTest.cpp
- SnippetGeneratorTest.cpp
RegisterAliasingTest.cpp
+ SchedClassResolutionTest.cpp
+ SnippetGeneratorTest.cpp
TargetTest.cpp
)
target_link_libraries(LLVMExegesisX86Tests PRIVATE
Copied: llvm/trunk/unittests/tools/llvm-exegesis/X86/SchedClassResolutionTest.cpp (from r357257, llvm/trunk/unittests/tools/llvm-exegesis/X86/AnalysisTest.cpp)
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/tools/llvm-exegesis/X86/SchedClassResolutionTest.cpp?p2=llvm/trunk/unittests/tools/llvm-exegesis/X86/SchedClassResolutionTest.cpp&p1=llvm/trunk/unittests/tools/llvm-exegesis/X86/AnalysisTest.cpp&r1=357257&r2=357259&rev=357259&view=diff
==============================================================================
--- llvm/trunk/unittests/tools/llvm-exegesis/X86/AnalysisTest.cpp (original)
+++ llvm/trunk/unittests/tools/llvm-exegesis/X86/SchedClassResolutionTest.cpp Fri Mar 29 07:24:27 2019
@@ -1,4 +1,4 @@
-//===-- AnalysisTest.cpp ---------------------------------------*- C++ -*-===//
+//===-- SchedClassResolutionTest.cpp ----------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "Analysis.h"
+#include "SchedClassResolution.h"
#include <cassert>
#include <memory>
@@ -23,9 +23,9 @@ namespace {
using testing::Pair;
using testing::UnorderedElementsAre;
-class AnalysisTest : public ::testing::Test {
+class SchedClassResolutionTest : public ::testing::Test {
protected:
- AnalysisTest() {
+ SchedClassResolutionTest() {
const std::string TT = "x86_64-unknown-linux";
std::string error;
const llvm::Target *const TheTarget =
@@ -78,20 +78,20 @@ protected:
uint16_t P0156Idx = 0;
};
-TEST_F(AnalysisTest, ComputeIdealizedProcResPressure_2P0) {
+TEST_F(SchedClassResolutionTest, ComputeIdealizedProcResPressure_2P0) {
const auto Pressure =
computeIdealizedProcResPressure(STI->getSchedModel(), {{P0Idx, 2}});
EXPECT_THAT(Pressure, UnorderedElementsAre(Pair(P0Idx, 2.0)));
}
-TEST_F(AnalysisTest, ComputeIdealizedProcResPressure_2P05) {
+TEST_F(SchedClassResolutionTest, ComputeIdealizedProcResPressure_2P05) {
const auto Pressure =
computeIdealizedProcResPressure(STI->getSchedModel(), {{P05Idx, 2}});
EXPECT_THAT(Pressure,
UnorderedElementsAre(Pair(P0Idx, 1.0), Pair(P5Idx, 1.0)));
}
-TEST_F(AnalysisTest, ComputeIdealizedProcResPressure_2P05_2P0156) {
+TEST_F(SchedClassResolutionTest, ComputeIdealizedProcResPressure_2P05_2P0156) {
const auto Pressure = computeIdealizedProcResPressure(
STI->getSchedModel(), {{P05Idx, 2}, {P0156Idx, 2}});
EXPECT_THAT(Pressure,
@@ -99,7 +99,8 @@ TEST_F(AnalysisTest, ComputeIdealizedPro
Pair(P5Idx, 1.0), Pair(P6Idx, 1.0)));
}
-TEST_F(AnalysisTest, ComputeIdealizedProcResPressure_1P1_1P05_2P0156) {
+TEST_F(SchedClassResolutionTest,
+ ComputeIdealizedProcResPressure_1P1_1P05_2P0156) {
const auto Pressure = computeIdealizedProcResPressure(
STI->getSchedModel(), {{P1Idx, 1}, {P05Idx, 1}, {P0156Idx, 2}});
EXPECT_THAT(Pressure,
More information about the llvm-commits
mailing list