-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[coro][pgo] Do not insert counters in the suspend
block
#71262
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 1 commit
184936c
d77e267
6b85e45
713bbb7
18773ca
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 |
---|---|---|
|
@@ -19,6 +19,8 @@ | |
#include "llvm/Analysis/BlockFrequencyInfo.h" | ||
#include "llvm/Analysis/BranchProbabilityInfo.h" | ||
#include "llvm/Analysis/CFG.h" | ||
#include "llvm/IR/Instructions.h" | ||
#include "llvm/IR/IntrinsicInst.h" | ||
#include "llvm/Support/BranchProbability.h" | ||
#include "llvm/Support/Debug.h" | ||
#include "llvm/Support/raw_ostream.h" | ||
|
@@ -121,31 +123,70 @@ template <class Edge, class BBInfo> class CFGMST { | |
|
||
static const uint32_t CriticalEdgeMultiplier = 1000; | ||
|
||
auto GetCoroSuspendSwitch = | ||
[&](const Instruction *TI) -> const SwitchInst * { | ||
if (!F.isPresplitCoroutine()) | ||
return nullptr; | ||
if (auto *SWInst = dyn_cast<SwitchInst>(TI)) | ||
if (auto *Intrinsic = dyn_cast<IntrinsicInst>(SWInst->getCondition())) | ||
if (Intrinsic->getIntrinsicID() == Intrinsic::coro_suspend) | ||
return SWInst; | ||
return nullptr; | ||
}; | ||
|
||
for (BasicBlock &BB : F) { | ||
Instruction *TI = BB.getTerminator(); | ||
const SwitchInst *CoroSuspendSwitch = GetCoroSuspendSwitch(TI); | ||
uint64_t BBWeight = | ||
(BFI != nullptr ? BFI->getBlockFreq(&BB).getFrequency() : 2); | ||
uint64_t Weight = 2; | ||
if (int successors = TI->getNumSuccessors()) { | ||
for (int i = 0; i != successors; ++i) { | ||
BasicBlock *TargetBB = TI->getSuccessor(i); | ||
bool Critical = isCriticalEdge(TI, i); | ||
uint64_t scaleFactor = BBWeight; | ||
if (Critical) { | ||
if (scaleFactor < UINT64_MAX / CriticalEdgeMultiplier) | ||
scaleFactor *= CriticalEdgeMultiplier; | ||
else | ||
scaleFactor = UINT64_MAX; | ||
const bool Critical = isCriticalEdge(TI, i); | ||
const bool IsCoroSuspendTarget = | ||
CoroSuspendSwitch && | ||
CoroSuspendSwitch->getDefaultDest() == TargetBB; | ||
// We must not add instrumentation to the BB representing the | ||
// "suspend" path, else CoroSplit won't be able to lower | ||
// llvm.coro.suspend to a tail call. We do want profiling info for | ||
// the other branches (resume/destroy). So we do 2 things: | ||
// 1. we prefer instrumenting those other edges by setting the weight | ||
// of the "suspend" edge to max, and | ||
// 2. we mark the edge as "Removed" to guarantee it is not considered | ||
// for instrumentation. That could technically happen: | ||
// (from test/Transforms/Coroutines/coro-split-musttail.ll) | ||
// | ||
// %suspend = call i8 @llvm.coro.suspend(token %save, i1 false) | ||
// switch i8 %suspend, label %exit [ | ||
// i8 0, label %await.ready | ||
// i8 1, label %exit | ||
// ] | ||
if (IsCoroSuspendTarget) { | ||
Weight = UINT64_MAX; | ||
} else { | ||
bool Critical = isCriticalEdge(TI, i); | ||
uint64_t scaleFactor = BBWeight; | ||
if (Critical) { | ||
if (scaleFactor < UINT64_MAX / CriticalEdgeMultiplier) | ||
scaleFactor *= CriticalEdgeMultiplier; | ||
else | ||
scaleFactor = UINT64_MAX; | ||
} | ||
if (BPI != nullptr) | ||
Weight = | ||
BPI->getEdgeProbability(&BB, TargetBB).scale(scaleFactor); | ||
if (Weight == 0) | ||
Weight++; | ||
} | ||
if (BPI != nullptr) | ||
Weight = BPI->getEdgeProbability(&BB, TargetBB).scale(scaleFactor); | ||
if (Weight == 0) | ||
Weight++; | ||
auto *E = &addEdge(&BB, TargetBB, Weight); | ||
E->IsCritical = Critical; | ||
// See comment above - we must guarantee the coro suspend BB isn't | ||
// instrumented. | ||
if (IsCoroSuspendTarget) | ||
E->Removed = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is setting MAX weighted needed if the removed flag is set? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC yes (as per @xur-llvm) because it helps pick the other edges for instrumentation. If there's a more explicit way to do that, I'd prefer that instead. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I take that back. Fixing. |
||
LLVM_DEBUG(dbgs() << " Edge: from " << BB.getName() << " to " | ||
<< TargetBB->getName() << " w=" << Weight << "\n"); | ||
|
||
// Keep track of entry/exit edges: | ||
if (&BB == Entry) { | ||
if (Weight > MaxEntryOutWeight) { | ||
|
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 suggest move all co-routine handling code in one helper function and call it after Edge creation:
void HandleCoroutine(Edge *E, ....) {
if (!F.notPresplitCoroutine)
return;
if (!NotSwitch(SI))
return;
...
E->Weight = UINT64_MAX;
E->Removed = true;
}
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.
done