-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[PseudoProbe] Add PseudoProbeDescUpdatePass #99839
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
Conversation
Add PseudoProbeDescUpdatePass to update pseudo_probe_desc metadata for functions generated by optimization transformation. Those functions may contain pseudo probe discriminator so that llvm-profgen will try to get its function name based on GUID and then crash.
|
Issue: #98127 |
|
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-pgo Author: Haohai Wen (HaohaiWen) Changes[PseudoProbe] Add PseudoProbeDescUpdatePass Add PseudoProbeDescUpdatePass to update pseudo_probe_desc metadata for Full diff: https://github.com/llvm/llvm-project/pull/99839.diff 5 Files Affected:
diff --git a/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h b/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h
index b52ef847d9db6..c15da7589dc7e 100644
--- a/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h
+++ b/llvm/include/llvm/Transforms/IPO/SampleProfileProbe.h
@@ -140,5 +140,13 @@ class PseudoProbeUpdatePass : public PassInfoMixin<PseudoProbeUpdatePass> {
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
};
+// Update pseudo_probe_desc metadata for functions generated by optimization
+// transformation.
+class PseudoProbeDescUpdatePass
+ : public PassInfoMixin<PseudoProbeDescUpdatePass> {
+public:
+ PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
+};
+
} // end namespace llvm
#endif // LLVM_TRANSFORMS_IPO_SAMPLEPROFILEPROBE_H
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 4fd5ee1946bb7..464379a5c638b 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -1581,9 +1581,12 @@ PassBuilder::buildPerModuleDefaultPipeline(OptimizationLevel Level,
// Now add the optimization pipeline.
MPM.addPass(buildModuleOptimizationPipeline(Level, LTOPhase));
- if (PGOOpt && PGOOpt->PseudoProbeForProfiling &&
- PGOOpt->Action == PGOOptions::SampleUse)
- MPM.addPass(PseudoProbeUpdatePass());
+ if (PGOOpt && PGOOpt->PseudoProbeForProfiling) {
+ if (PGOOpt->Action == PGOOptions::SampleUse)
+ MPM.addPass(PseudoProbeUpdatePass());
+ else
+ MPM.addPass(PseudoProbeDescUpdatePass());
+ }
// Emit annotation remarks.
addAnnotationRemarksPass(MPM);
@@ -1651,9 +1654,12 @@ PassBuilder::buildThinLTOPreLinkDefaultPipeline(OptimizationLevel Level) {
if (RunPartialInlining)
MPM.addPass(PartialInlinerPass());
- if (PGOOpt && PGOOpt->PseudoProbeForProfiling &&
- PGOOpt->Action == PGOOptions::SampleUse)
- MPM.addPass(PseudoProbeUpdatePass());
+ if (PGOOpt && PGOOpt->PseudoProbeForProfiling) {
+ if (PGOOpt->Action == PGOOptions::SampleUse)
+ MPM.addPass(PseudoProbeUpdatePass());
+ else
+ MPM.addPass(PseudoProbeDescUpdatePass());
+ }
// Handle Optimizer{Early,Last}EPCallbacks added by clang on PreLink. Actual
// optimization is going to be done in PostLink stage, but clang can't add
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 3b92823cd283b..6116785f580a7 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -119,6 +119,7 @@ MODULE_PASS("print<inline-advisor>", InlineAdvisorAnalysisPrinterPass(dbgs()))
MODULE_PASS("print<module-debuginfo>", ModuleDebugInfoPrinterPass(dbgs()))
MODULE_PASS("pseudo-probe", SampleProfileProbePass(TM))
MODULE_PASS("pseudo-probe-update", PseudoProbeUpdatePass())
+MODULE_PASS("pseudo-probe-desc-update", PseudoProbeDescUpdatePass())
MODULE_PASS("recompute-globalsaa", RecomputeGlobalsAAPass())
MODULE_PASS("rel-lookup-table-converter", RelLookupTableConverterPass())
MODULE_PASS("rewrite-statepoints-for-gc", RewriteStatepointsForGC())
diff --git a/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp b/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
index b489d4fdaa210..e83ca33b2c813 100644
--- a/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp
@@ -341,9 +341,7 @@ uint32_t SampleProfileProber::getCallsiteId(const Instruction *Call) const {
return Iter == CallProbeIds.end() ? 0 : Iter->second;
}
-void SampleProfileProber::instrumentOneFunc(Function &F, TargetMachine *TM) {
- Module *M = F.getParent();
- MDBuilder MDB(F.getContext());
+static StringRef getFuncName(const Function &F) {
// Since the GUID from probe desc and inline stack are computed separately, we
// need to make sure their names are consistent, so here also use the name
// from debug info.
@@ -353,6 +351,13 @@ void SampleProfileProber::instrumentOneFunc(Function &F, TargetMachine *TM) {
if (FName.empty())
FName = SP->getName();
}
+ return FName;
+}
+
+void SampleProfileProber::instrumentOneFunc(Function &F, TargetMachine *TM) {
+ Module *M = F.getParent();
+ MDBuilder MDB(F.getContext());
+ StringRef FName = getFuncName(F);
uint64_t Guid = Function::getGUID(FName);
// Assign an artificial debug line to a probe that doesn't come with a real
@@ -513,3 +518,31 @@ PreservedAnalyses PseudoProbeUpdatePass::run(Module &M,
}
return PreservedAnalyses::none();
}
+
+PreservedAnalyses PseudoProbeDescUpdatePass::run(Module &M,
+ ModuleAnalysisManager &AM) {
+ if (NamedMDNode *FuncInfo = M.getNamedMetadata(PseudoProbeDescMetadataName)) {
+ DenseSet<uint64_t> GuidSet;
+ for (const auto *Operand : FuncInfo->operands()) {
+ const auto *MD = cast<MDNode>(Operand);
+ auto *GUID = mdconst::dyn_extract<ConstantInt>(MD->getOperand(0));
+ GuidSet.insert(GUID->getZExtValue());
+ }
+
+ MDBuilder MDB(M.getContext());
+ for (Function &F : M) {
+ if (F.isDeclaration())
+ continue;
+ StringRef FName = getFuncName(F);
+ uint64_t Guid = Function::getGUID(FName);
+ if (GuidSet.insert(Guid).second) {
+ // Set those function's hash to 0 since it may vary depending on IR
+ // input to optimization transformation.
+ auto *MD = MDB.createPseudoProbeDesc(Guid, 0, FName);
+ FuncInfo->addOperand(MD);
+ LLVM_DEBUG(dbgs() << "New fixup pseudo_probe_desc MD: " << *MD << "\n");
+ }
+ }
+ }
+ return PreservedAnalyses::all();
+}
diff --git a/llvm/test/Transforms/SampleProfile/pseudo-probe-desc-update.ll b/llvm/test/Transforms/SampleProfile/pseudo-probe-desc-update.ll
new file mode 100644
index 0000000000000..4a114c5b11fb3
--- /dev/null
+++ b/llvm/test/Transforms/SampleProfile/pseudo-probe-desc-update.ll
@@ -0,0 +1,35 @@
+; RUN: opt < %s -passes='pseudo-probe-desc-update' -S | FileCheck %s
+
+; CHECK: !llvm.pseudo_probe_desc = !{!0, !1, !2, !3, !4, !5}
+; CHECK: !0 = !{i64 -2012135647395072713, i64 4294967295, !"bar"}
+; CHECK-NEXT: !1 = !{i64 9204417991963109735, i64 72617220756, !"work"}
+; CHECK-NEXT: !2 = !{i64 6699318081062747564, i64 844700110938769, !"foo"}
+; CHECK-NEXT: !3 = !{i64 -2624081020897602054, i64 281563657672557, !"main"}
+; CHECK-NEXT: !4 = !{i64 6028998432455395745, i64 0, !"extract1"}
+; CHECK-NEXT: !5 = !{i64 -8314581669044049530, i64 0, !"_Zextract2v"}
+
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @extract1() !dbg !1 {
+entry:
+ ret void
+}
+
+define void @extract2() !dbg !2 {
+entry:
+ ret void
+}
+
+!llvm.pseudo_probe_desc = !{!4, !5, !6, !7}
+!llvm.module.flags = !{!8, !9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, emissionKind: FullDebug, splitDebugInlining: false, debugInfoForProfiling: true)
+!1 = distinct !DISubprogram(name: "extract1", unit: !0)
+!2 = distinct !DISubprogram(name: "extract2", linkageName: "_Zextract2v", unit: !0)
+!3 = !DIFile(filename: "foo.c", directory: "/home/test")
+!4 = !{i64 -2012135647395072713, i64 4294967295, !"bar"}
+!5 = !{i64 9204417991963109735, i64 72617220756, !"work"}
+!6 = !{i64 6699318081062747564, i64 844700110938769, !"foo"}
+!7 = !{i64 -2624081020897602054, i64 281563657672557, !"main"}
+!8 = !{i32 7, !"Dwarf Version", i32 5}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
|
WenleiHe
left a comment
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'm not sure if this is the right fix. PGO generally operates with pre-split functions. So ideally we want all the funclets to map back to the same original functions as opposed to using separate functions to represent funclets.
Compiler generated functions are not unique to partial inline. Coroutine split is another example. How is that handled and how is partial inline different? cc @wlei-llvm
| if (PGOOpt->Action == PGOOptions::SampleUse) | ||
| MPM.addPass(PseudoProbeUpdatePass()); | ||
| else | ||
| MPM.addPass(PseudoProbeDescUpdatePass()); |
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.
Why is this not applicable to SampleUse path?
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 think we don't use pseudo_probe_desc for SampleUse?
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.
We do. PseudoProbeUpdatePass for pseudo-probe.
wlei-llvm
left a comment
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.
Do you have a small repro for the crash? I'm curious about what the missing function name looks like. For pseudo probe, it tries to use function name from debug info/dwarf to compute the GUID so that the symbol can be matched to the source code function, otherwise it's not meaningful to generate a function profile that compiler can't consume.
If this is only a rare case(like the debug info is missing for that function), we can probably just ignore it in llvm-profgen(add some stats/warning), or we may need to fix or maintain the function to use symbol from dwarf.
It's cpu2017/500.perlbench when partialinliner is on. PartialInliner creates a new function. |
We use debug info symbol so that the different suffix function can be mapped to the original function, it seems also applicable to partial inlining. but maybe the debug info is only missing for that function: |
Lost of debug info should be fixed. |
So, if missing debug info for partial inline funclet is the root case, we can deal with this by:
|
I think 2 is necessary and better to fix 1 since lost debug info is something always happened. |
Why is this something that always happened? This is about an entire function missing debug info. Evidently, we haven't run into any such cases in any of our code base. Fixing #1 is handling the root cause, while fixing #2 is just hiding the underlying issue.
We will get to that, feel free to send a patch too. But fixing root cause (#1) should be prioritized over this. |
I had fixed several debug info missing issues. I believe there must be other places. |
|
Regarding debug info, with current implementation, I doubt we can map the debug info after PartialInline to the original function: #100327 |
[PseudoProbe] Add PseudoProbeDescUpdatePass
Issue: #98127
Add PseudoProbeDescUpdatePass to update pseudo_probe_desc metadata for
functions generated by optimization transformation. Those functions may
contain pseudo probe discriminator so that llvm-profgen will try to get
its function name based on GUID and then crash.