llvm.org GIT mirror llvm / 25761c3
[llvm-mca] Use a small vector for instructions in the EntryStage. Use a simple SmallVector to track the lifetime of simulated instructions. An ordered map was not needed because instructions are already picked in program order. It is also much faster if we avoid searching for already retired instructions at the end of every cycle. The new policy only triggers a "garbage collection" when the number of retired instructions becomes significantly big when compared with the total size of the vector. While working on this, I noticed that instructions were correctly retired, but their internal state was not updated (i.e. there was no transition from the EXECUTED state, to the RETIRED state). While this was not a problem for the views, it prevented the EntryStage from correctly garbage collecting already retired instructions. That was a bad oversight, and this patch fixes it. The observed speedup on a debug build of llvm-mca after this patch is ~6%. On a release build of llvm-mca, the observed speedup is ~%15%. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@346487 91177308-0d34-0410-b5e6-96231b3b80d8 Andrea Di Biagio 10 months ago
3 changed file(s) with 15 addition(s) and 11 deletion(s). Raw diff Collapse all Expand all
1818
1919 #include "SourceMgr.h"
2020 #include "Stages/Stage.h"
21 #include
21 #include "llvm/ADT/SmallVector.h"
2222
2323 namespace llvm {
2424 namespace mca {
2525
2626 class EntryStage final : public Stage {
2727 InstRef CurrentInstruction;
28 using InstMap = std::map>;
29 InstMap Instructions;
28 SmallVector, 16> Instructions;
3029 SourceMgr &SM;
30 unsigned NumRetired;
3131
3232 // Updates the program counter, and sets 'CurrentInstruction'.
3333 void getNextInstruction();
3636 EntryStage &operator=(const EntryStage &Other) = delete;
3737
3838 public:
39 EntryStage(SourceMgr &SM) : CurrentInstruction(), SM(SM) {}
39 EntryStage(SourceMgr &SM) : CurrentInstruction(), SM(SM), NumRetired(0) { }
4040
4141 bool isAvailable(const InstRef &IR) const override;
4242 bool hasWorkToComplete() const override;
5959 }
6060
6161 void RetireControlUnit::consumeCurrentToken() {
62 const RetireControlUnit::RUToken &Current = peekCurrentToken();
62 RetireControlUnit::RUToken &Current = Queue[CurrentInstructionSlotIdx];
6363 assert(Current.NumSlots && "Reserved zero slots?");
6464 assert(Current.IR && "Invalid RUToken in the RCU queue.");
65 Current.IR.getInstruction()->retire();
6566
6667 // Update the slot index to be the next item in the circular queue.
6768 CurrentInstructionSlotIdx += Current.NumSlots;
3333 SourceRef SR = SM.peekNext();
3434 std::unique_ptr Inst = llvm::make_unique(SR.second);
3535 CurrentInstruction = InstRef(SR.first, Inst.get());
36 Instructions[SR.first] = std::move(Inst);
36 Instructions.emplace_back(std::move(Inst));
3737 SM.updateNext();
3838 }
3939
5656
5757 llvm::Error EntryStage::cycleEnd() {
5858 // Find the first instruction which hasn't been retired.
59 const InstMap::iterator It =
60 llvm::find_if(Instructions, [](const InstMap::value_type &KeyValuePair) {
61 return !KeyValuePair.second->isRetired();
62 });
59 auto Range = make_range(&Instructions[NumRetired], Instructions.end());
60 auto It = find_if(Range, [](const std::unique_ptr &I) {
61 return !I->isRetired();
62 });
6363
64 NumRetired = std::distance(Instructions.begin(), It);
6465 // Erase instructions up to the first that hasn't been retired.
65 if (It != Instructions.begin())
66 if ((NumRetired * 2) >= Instructions.size()) {
6667 Instructions.erase(Instructions.begin(), It);
68 NumRetired = 0;
69 }
6770
6871 return llvm::ErrorSuccess();
6972 }