diff options
author | Andrea Di Biagio <Andrea_DiBiagio@sn.scee.net> | 2018-07-06 08:08:30 +0000 |
---|---|---|
committer | Andrea Di Biagio <Andrea_DiBiagio@sn.scee.net> | 2018-07-06 08:08:30 +0000 |
commit | 9e7cb445ca5d401ecb5506f84d59995b282e165f (patch) | |
tree | 6921c88209cebac63bc0c84755a09eb20650455d /tools/llvm-mca | |
parent | 2d76367f8238bb26af8940bf4f3ce8d2475e2463 (diff) |
[llvm-mca] improve the instruction issue logic implemented by the Scheduler.
This patch modifies the Scheduler heuristic used to select the next instruction
to issue to the pipelines.
The motivating example is test X86/BtVer2/add-sequence.s, for which llvm-mca
wrongly reported an estimated IPC of 1.50. According to perf, the actual IPC for
that test should have been ~2.00.
It turns out that an IPC of 2.00 for test add-sequence.s cannot possibly be
predicted by a Scheduler that only prioritizes instructions based on their
"age". A similar issue also affected test X86/BtVer2/dependent-pmuld-paddd.s,
for which llvm-mca wrongly estimated an IPC of 0.84 instead of an IPC of 1.00.
Instructions in the ReadyQueue are now ranked based on two factors:
- The "age" of an instruction.
- The number of unique users of writes associated with an instruction.
The new logic still prioritizes older instructions over younger instructions to
minimize the pressure on the reorder buffer. However, the number of users of an
instruction now also affects the overall rank. This potentially increases the
ability of the Scheduler to extract instruction level parallelism. This patch
fixes the problem with the wrong IPC reported for test add-sequence.s and test
dependent-pmuld-paddd.s.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@336420 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/llvm-mca')
-rw-r--r-- | tools/llvm-mca/Instruction.h | 10 | ||||
-rw-r--r-- | tools/llvm-mca/Scheduler.cpp | 29 |
2 files changed, 31 insertions, 8 deletions
diff --git a/tools/llvm-mca/Instruction.h b/tools/llvm-mca/Instruction.h index b15b17a2f51..c2d1761a200 100644 --- a/tools/llvm-mca/Instruction.h +++ b/tools/llvm-mca/Instruction.h @@ -125,6 +125,7 @@ public: unsigned getRegisterID() const { return RegisterID; } void addUser(ReadState *Use, int ReadAdvance); + unsigned getNumUsers() const { return Users.size(); } bool clearsSuperRegisters() const { return ClearsSuperRegs; } // On every cycle, update CyclesLeft and notify dependent users. @@ -306,7 +307,7 @@ class Instruction { public: Instruction(const InstrDesc &D) - : Desc(D), Stage(IS_INVALID), CyclesLeft(-1) {} + : Desc(D), Stage(IS_INVALID), CyclesLeft(UNKNOWN_CYCLES) {} Instruction(const Instruction &Other) = delete; Instruction &operator=(const Instruction &Other) = delete; @@ -317,6 +318,13 @@ public: const InstrDesc &getDesc() const { return Desc; } unsigned getRCUTokenID() const { return RCUTokenID; } + unsigned getNumUsers() const { + unsigned NumUsers = 0; + for (const UniqueDef &Def : Defs) + NumUsers += Def->getNumUsers(); + return NumUsers; + } + // Transition to the dispatch stage, and assign a RCUToken to this // instruction. The RCUToken is used to track the completion of every // register write performed by this instruction. diff --git a/tools/llvm-mca/Scheduler.cpp b/tools/llvm-mca/Scheduler.cpp index deefb461638..a2561fc3582 100644 --- a/tools/llvm-mca/Scheduler.cpp +++ b/tools/llvm-mca/Scheduler.cpp @@ -312,17 +312,32 @@ void Scheduler::promoteToReadyQueue(SmallVectorImpl<InstRef> &Ready) { } InstRef Scheduler::select() { - // Give priority to older instructions in the ReadyQueue. Since the ready - // queue is ordered by key, this will always prioritize older instructions. - const auto It = std::find_if(ReadyQueue.begin(), ReadyQueue.end(), - [&](const QueueEntryTy &Entry) { - const InstrDesc &D = Entry.second->getDesc(); - return Resources->canBeIssued(D); - }); + // Find the oldest ready-to-issue instruction in the ReadyQueue. + auto It = std::find_if(ReadyQueue.begin(), ReadyQueue.end(), + [&](const QueueEntryTy &Entry) { + const InstrDesc &D = Entry.second->getDesc(); + return Resources->canBeIssued(D); + }); if (It == ReadyQueue.end()) return {0, nullptr}; + // We want to prioritize older instructions over younger instructions to + // minimize the pressure on the reorder buffer. We also want to + // rank higher the instructions with more users to better expose ILP. + + // Compute a rank value based on the age of an instruction (i.e. its source + // index) and its number of users. The lower the rank value, the better. + int Rank = It->first - It->second->getNumUsers(); + for (auto I = It, E = ReadyQueue.end(); I != E; ++I) { + int CurrentRank = I->first - I->second->getNumUsers(); + if (CurrentRank < Rank) { + const InstrDesc &D = I->second->getDesc(); + if (Resources->canBeIssued(D)) + It = I; + } + } + // We found an instruction to issue. InstRef IR(It->first, It->second); ReadyQueue.erase(It); |