-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[AMDGPU] Refine GCNHazardRecognizer hasHazard() #138841
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
0230c8e
2a18fbe
9532454
61a3e48
5a736bd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -441,42 +441,96 @@ using IsExpiredFn = function_ref<bool(const MachineInstr &, int WaitStates)>; | |||
| using GetNumWaitStatesFn = function_ref<unsigned int(const MachineInstr &)>; | ||||
|
|
||||
| // Search for a hazard in a block and its predecessors. | ||||
| // StateT must implement getHashValue() and isEqual(). | ||||
| template <typename StateT> | ||||
| static bool | ||||
| hasHazard(StateT State, | ||||
| hasHazard(StateT InitialState, | ||||
| function_ref<HazardFnResult(StateT &, const MachineInstr &)> IsHazard, | ||||
| function_ref<void(StateT &, const MachineInstr &)> UpdateState, | ||||
| const MachineBasicBlock *MBB, | ||||
| MachineBasicBlock::const_reverse_instr_iterator I, | ||||
| DenseSet<const MachineBasicBlock *> &Visited) { | ||||
| for (auto E = MBB->instr_rend(); I != E; ++I) { | ||||
| // No need to look at parent BUNDLE instructions. | ||||
| if (I->isBundle()) | ||||
| continue; | ||||
|
|
||||
| switch (IsHazard(State, *I)) { | ||||
| case HazardFound: | ||||
| return true; | ||||
| case HazardExpired: | ||||
| return false; | ||||
| default: | ||||
| // Continue search | ||||
| break; | ||||
| const MachineBasicBlock *InitialMBB, | ||||
| MachineBasicBlock::const_reverse_instr_iterator InitialI) { | ||||
| SmallVector<std::pair<const MachineBasicBlock *, unsigned>> Worklist; | ||||
| SmallDenseSet<std::pair<const MachineBasicBlock *, unsigned>> Visited; | ||||
| SmallVector<std::pair<unsigned, unsigned>, 1> Collisions; | ||||
perlfu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||
| SmallDenseMap<unsigned, unsigned> StateHash2Idx; | ||||
| SmallVector<StateT> States; | ||||
|
|
||||
| // States contains a vector of unique state structures. | ||||
|
||||
| /// Special DenseMapInfo traits to compare MachineInstr* by *value* of the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you could probably reimplement
MapVector<StateT, void>, usingMapVector::getArrayRef
getArrayRefonly provides access to the values, not the keys.
Stepping back a bit, why do you want this level of indirection in the first place?
Avoiding copying for performance is the primary reason. Because the data is backed by aSmallVectorpointers are also not an option (will invalid).
DenseMap allows for alternate Key and LookupKey types specified via traits.
I have reimplemented using this mechanism; however, the actual key type needs to be a pointer to the backing SmallVector and an index into it, because traits methods are static -- if they were not static I could capture the SmallVector reference and keys would only need to be indexes into the array.
Overall implementation is more code, but runs with comparable performance to previous version in this PR. Slightly worse, but still net improvement against current code without this patch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
however, the actual key type needs to be a pointer to the backing
SmallVectorand an index into it, because traits methods are static -- if they were not static I could capture theSmallVectorreference and keys would only need to be indexes into the array.
If you use std::deque then you can work with pointers to the StateT objects, not indexes, because deque promises not to move existing allocations as it grows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can put up a version that uses deque and SmallDenseMap from pointer to pointer if you prefer?
It doesn't look that different to this, but it is measurably a little slower.
A lot of the benefit of this refactor comes from the fact that most hasHazard calls can be handled within a block.
Hence avoiding touching any data structures and doing any memory allocation is beneficial -- most std::deque implementation do alloca on init AFAIK.
Beyond improved correctness the secondary goal of this patch is to try and claw back some of the impact of #138663.
Using std::deque certainly negates a lot of that.
Version prior to current was still the best.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I still don't like the hand-rolled hashtable implementation, but I guess I won't object if it's measurably faster and if you can find someone to review it for correctness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you accept the current implementation using SmallVector and SmallDenseMap?
To re-iterate, this version while not the best is still better than current implementation in both performance and correctness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I'll take another look at the current version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not something to address in the current patch, but I think this
IsHazard/UpdateStateinterface is confusing becauseIsHazardalso updates the state. So technically I think there is no need for the separateUpdateStatefunction, it could just become part of whatIsHazarddoes before returningNoHazardFound.