Skip to content

Commit 07a2cab

Browse files
committed
[InstrPGO] Instrument sampling profile based cold function
1 parent f404207 commit 07a2cab

File tree

8 files changed

+99
-1
lines changed

8 files changed

+99
-1
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,6 +1784,12 @@ defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling",
17841784
PosFlag<SetTrue, [], [ClangOption, CC1Option],
17851785
"Emit extra debug info to make sample profile more accurate">,
17861786
NegFlag<SetFalse>>;
1787+
def fprofile_generate_cold_function_coverage : Flag<["-"], "fprofile-generate-cold-function-coverage">,
1788+
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
1789+
HelpText<"Generate instrumented code to cold functions into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
1790+
def fprofile_generate_cold_function_coverage_EQ : Joined<["-"], "fprofile-generate-cold-function-coverage=">,
1791+
Group<f_Group>, Visibility<[ClangOption, CLOption]>, MetaVarName<"<directory>">,
1792+
HelpText<"Generate instrumented code to cold functions into <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
17871793
def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">,
17881794
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
17891795
HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;

clang/lib/Driver/ToolChain.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,9 @@ bool ToolChain::needsProfileRT(const ArgList &Args) {
889889
Args.hasArg(options::OPT_fprofile_instr_generate) ||
890890
Args.hasArg(options::OPT_fprofile_instr_generate_EQ) ||
891891
Args.hasArg(options::OPT_fcreate_profile) ||
892-
Args.hasArg(options::OPT_forder_file_instrumentation);
892+
Args.hasArg(options::OPT_forder_file_instrumentation) ||
893+
Args.hasArg(options::OPT_fprofile_generate_cold_function_coverage) ||
894+
Args.hasArg(options::OPT_fprofile_generate_cold_function_coverage_EQ);
893895
}
894896

895897
bool ToolChain::needsGCovInstrumentation(const llvm::opt::ArgList &Args) {

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,24 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
649649
}
650650
}
651651

652+
if (auto *ColdFuncCoverageArg = Args.getLastArg(
653+
options::OPT_fprofile_generate_cold_function_coverage,
654+
options::OPT_fprofile_generate_cold_function_coverage_EQ)) {
655+
SmallString<128> Path(
656+
ColdFuncCoverageArg->getOption().matches(
657+
options::OPT_fprofile_generate_cold_function_coverage_EQ)
658+
? ColdFuncCoverageArg->getValue()
659+
: "");
660+
llvm::sys::path::append(Path, "default_%m.profraw");
661+
CmdArgs.push_back("-mllvm");
662+
CmdArgs.push_back(Args.MakeArgString(
663+
Twine("--instrument-sample-cold-function-path=") + Path));
664+
CmdArgs.push_back("-mllvm");
665+
CmdArgs.push_back("--instrument-cold-function-coverage");
666+
CmdArgs.push_back("-mllvm");
667+
CmdArgs.push_back("--pgo-function-entry-coverage");
668+
}
669+
652670
Arg *PGOGenArg = nullptr;
653671
if (PGOGenerateArg) {
654672
assert(!CSPGOGenerateArg);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
foo:1:1
2+
1: 1
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Test -fprofile-generate-cold-function-coverage
2+
// RUN: %clang -O2 -fprofile-generate-cold-function-coverage=/xxx/yyy/ -fprofile-sample-accurate -fprofile-sample-use=%S/Inputs/pgo-cold-func.prof -S -emit-llvm -o - %s | FileCheck %s
3+
4+
// CHECK: @__llvm_profile_filename = {{.*}} c"/xxx/yyy/default_%m.profraw\00"
5+
6+
// CHECK: @__profc_bar
7+
// CHECK-NOT: @__profc_foo
8+
9+
int bar(int x) { return x;}
10+
int foo(int x) {
11+
return x;
12+
}

llvm/lib/Passes/PassBuilderPipelines.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,13 @@ static cl::opt<bool> UseLoopVersioningLICM(
296296
"enable-loop-versioning-licm", cl::init(false), cl::Hidden,
297297
cl::desc("Enable the experimental Loop Versioning LICM pass"));
298298

299+
static cl::opt<std::string> InstrumentSampleColdFuncPath(
300+
"instrument-sample-cold-function-path", cl::init(""),
301+
cl::desc("File path for instrumenting sampling PGO guided cold functions"),
302+
cl::Hidden);
303+
299304
extern cl::opt<std::string> UseCtxProfile;
305+
extern cl::opt<bool> InstrumentColdFunctionCoverage;
300306

301307
namespace llvm {
302308
extern cl::opt<bool> EnableMemProfContextDisambiguation;
@@ -1119,6 +1125,18 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
11191125
// removed.
11201126
MPM.addPass(
11211127
PGOIndirectCallPromotion(true /* IsInLTO */, true /* SamplePGO */));
1128+
1129+
if (InstrumentSampleColdFuncPath.getNumOccurrences() &&
1130+
Phase != ThinOrFullLTOPhase::ThinLTOPostLink) {
1131+
assert(!InstrumentSampleColdFuncPath.empty() &&
1132+
"File path is requeired for instrumentation generation");
1133+
InstrumentColdFunctionCoverage = true;
1134+
addPreInlinerPasses(MPM, Level, Phase);
1135+
addPGOInstrPasses(MPM, Level, /* RunProfileGen */ true,
1136+
/* IsCS */ false, /* AtomicCounterUpdate */ false,
1137+
InstrumentSampleColdFuncPath, "",
1138+
IntrusiveRefCntPtr<vfs::FileSystem>());
1139+
}
11221140
}
11231141

11241142
// Try to perform OpenMP specific optimizations on the module. This is a

llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,18 @@ static cl::opt<unsigned> PGOFunctionCriticalEdgeThreshold(
319319
cl::desc("Do not instrument functions with the number of critical edges "
320320
" greater than this threshold."));
321321

322+
cl::opt<bool> InstrumentColdFunctionCoverage(
323+
"instrument-cold-function-coverage", cl::init(false), cl::Hidden,
324+
cl::desc("Enable cold function coverage instrumentation (currently only "
325+
"used under sampling "
326+
" PGO pipeline))"));
327+
328+
static cl::opt<uint64_t> ColdFuncCoverageMaxEntryCount(
329+
"cold-function-coverage-max-entry-count", cl::init(0), cl::Hidden,
330+
cl::desc("When enabling cold function coverage instrumentation, skip "
331+
"instrumenting the "
332+
"function whose entry count is above the given value"));
333+
322334
extern cl::opt<unsigned> MaxNumVTableAnnotations;
323335

324336
namespace llvm {
@@ -1891,6 +1903,10 @@ static bool skipPGOGen(const Function &F) {
18911903
return true;
18921904
if (F.getInstructionCount() < PGOFunctionSizeThreshold)
18931905
return true;
1906+
if (InstrumentColdFunctionCoverage &&
1907+
(!F.getEntryCount() ||
1908+
F.getEntryCount()->getCount() > ColdFuncCoverageMaxEntryCount))
1909+
return true;
18941910
return false;
18951911
}
18961912

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
; RUN: opt < %s --passes=pgo-instr-gen -instrument-cold-function-coverage -S | FileCheck --check-prefixes=COLD %s
2+
; RUN: opt < %s --passes=pgo-instr-gen -instrument-cold-function-coverage -cold-function-coverage-max-entry-count=1 -S | FileCheck --check-prefixes=ENTRY-COUNT %s
3+
4+
; COLD: call void @llvm.instrprof.increment(ptr @__profn_foo, i64 [[#]], i32 1, i32 0)
5+
; COLD-NOT: __profn_main
6+
7+
; ENTRY-COUNT: call void @llvm.instrprof.increment(ptr @__profn_foo, i64 [[#]], i32 1, i32 0)
8+
; ENTRY-COUNT: call void @llvm.instrprof.increment(ptr @__profn_main, i64 [[#]], i32 1, i32 0)
9+
10+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
11+
target triple = "x86_64-unknown-linux-gnu"
12+
13+
define void @foo() !prof !0 {
14+
entry:
15+
ret void
16+
}
17+
18+
define i32 @main() !prof !1 {
19+
entry:
20+
ret i32 0
21+
}
22+
23+
!0 = !{!"function_entry_count", i64 0}
24+
!1 = !{!"function_entry_count", i64 1}

0 commit comments

Comments
 (0)