Skip to content

Commit 8e61aae

Browse files
w2yehiaWael Yehia
andauthored
[profile] Add a clang option -fprofile-continuous that enables continuous instrumentation profiling mode (#124353)
In Continuous instrumentation profiling mode, profile or coverage data collected via compiler instrumentation is continuously synced to the profile file. This feature has existed for a while, and is documented here: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html#running-the-instrumented-program This PR creates a user facing option to enable the feature. --------- Co-authored-by: Wael Yehia <[email protected]>
1 parent 1e0a489 commit 8e61aae

File tree

7 files changed

+112
-21
lines changed

7 files changed

+112
-21
lines changed

clang/docs/UsersManual.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3125,6 +3125,24 @@ indexed format, regardeless whether it is produced by frontend or the IR pass.
31253125
overhead. ``prefer-atomic`` will be transformed to ``atomic`` when supported
31263126
by the target, or ``single`` otherwise.
31273127

3128+
.. option:: -fprofile-continuous
3129+
3130+
Enables the continuous instrumentation profiling where profile counter updates
3131+
are continuously synced to a file. This option sets any neccessary modifiers
3132+
(currently ``%c``) in the default profile filename and passes any necessary
3133+
flags to the middle-end to support this mode. Value profiling is not supported
3134+
in continuous mode.
3135+
3136+
.. code-block:: console
3137+
3138+
$ clang++ -O2 -fprofile-generate -fprofile-continuous code.cc -o code
3139+
3140+
Running ``./code`` will collect the profile and write it to the
3141+
``default_xxxx.profraw`` file. However, if ``./code`` abruptly terminates or
3142+
does not call ``exit()``, in continuous mode the profile collected up to the
3143+
point of termination will be available in ``default_xxxx.profraw`` while in
3144+
the non-continuous mode, no profile file is generated.
3145+
31283146
.. option:: -ftemporal-profile
31293147

31303148
Enables the temporal profiling extension for IRPGO to improve startup time by

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ AFFECTING_VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option spec
221221
AFFECTING_VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.
222222

223223
CODEGENOPT(AtomicProfileUpdate , 1, 0) ///< Set -fprofile-update=atomic
224+
CODEGENOPT(ContinuousProfileSync, 1, 0) ///< Enable continuous instrumentation profiling
224225
/// Choose profile instrumenation kind or no instrumentation.
225226
ENUM_CODEGENOPT(ProfileInstr, ProfileInstrKind, 2, ProfileNone)
226227
/// Choose profile kind for PGO use compilation.

clang/include/clang/Driver/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,6 +1795,11 @@ def fprofile_update_EQ : Joined<["-"], "fprofile-update=">,
17951795
Values<"atomic,prefer-atomic,single">,
17961796
MetaVarName<"<method>">, HelpText<"Set update method of profile counters">,
17971797
MarshallingInfoFlag<CodeGenOpts<"AtomicProfileUpdate">>;
1798+
def fprofile_continuous : Flag<["-"], "fprofile-continuous">,
1799+
Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
1800+
HelpText<"Enable continuous instrumentation profiling mode">,
1801+
MarshallingInfoFlag<CodeGenOpts<"ContinuousProfileSync">>;
1802+
17981803
defm pseudo_probe_for_profiling : BoolFOption<"pseudo-probe-for-profiling",
17991804
CodeGenOpts<"PseudoProbeForProfiling">, DefaultFalse,
18001805
PosFlag<SetTrue, [], [ClangOption], "Emit">,

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,25 @@ namespace clang {
124124
extern llvm::cl::opt<bool> ClSanitizeGuardChecks;
125125
}
126126

127-
namespace {
128-
129127
// Default filename used for profile generation.
130-
std::string getDefaultProfileGenName() {
128+
static std::string getDefaultProfileGenName() {
131129
return DebugInfoCorrelate || ProfileCorrelate != InstrProfCorrelator::NONE
132130
? "default_%m.proflite"
133131
: "default_%m.profraw";
134132
}
135133

134+
// Path and name of file used for profile generation
135+
static std::string getProfileGenName(const CodeGenOptions &CodeGenOpts) {
136+
std::string FileName = CodeGenOpts.InstrProfileOutput.empty()
137+
? getDefaultProfileGenName()
138+
: CodeGenOpts.InstrProfileOutput;
139+
if (CodeGenOpts.ContinuousProfileSync)
140+
FileName = "%c" + FileName;
141+
return FileName;
142+
}
143+
144+
namespace {
145+
136146
class EmitAssemblyHelper {
137147
CompilerInstance &CI;
138148
DiagnosticsEngine &Diags;
@@ -551,7 +561,9 @@ getInstrProfOptions(const CodeGenOptions &CodeGenOpts,
551561
return std::nullopt;
552562
InstrProfOptions Options;
553563
Options.NoRedZone = CodeGenOpts.DisableRedZone;
554-
Options.InstrProfileOutput = CodeGenOpts.InstrProfileOutput;
564+
Options.InstrProfileOutput = CodeGenOpts.ContinuousProfileSync
565+
? ("%c" + CodeGenOpts.InstrProfileOutput)
566+
: CodeGenOpts.InstrProfileOutput;
555567
Options.Atomic = CodeGenOpts.AtomicProfileUpdate;
556568
return Options;
557569
}
@@ -822,13 +834,12 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
822834

823835
if (CodeGenOpts.hasProfileIRInstr())
824836
// -fprofile-generate.
825-
PGOOpt = PGOOptions(
826-
CodeGenOpts.InstrProfileOutput.empty() ? getDefaultProfileGenName()
827-
: CodeGenOpts.InstrProfileOutput,
828-
"", "", CodeGenOpts.MemoryProfileUsePath, nullptr, PGOOptions::IRInstr,
829-
PGOOptions::NoCSAction, ClPGOColdFuncAttr,
830-
CodeGenOpts.DebugInfoForProfiling,
831-
/*PseudoProbeForProfiling=*/false, CodeGenOpts.AtomicProfileUpdate);
837+
PGOOpt = PGOOptions(getProfileGenName(CodeGenOpts), "", "",
838+
CodeGenOpts.MemoryProfileUsePath, nullptr,
839+
PGOOptions::IRInstr, PGOOptions::NoCSAction,
840+
ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling,
841+
/*PseudoProbeForProfiling=*/false,
842+
CodeGenOpts.AtomicProfileUpdate);
832843
else if (CodeGenOpts.hasProfileIRUse()) {
833844
// -fprofile-use.
834845
auto CSAction = CodeGenOpts.hasProfileCSIRUse() ? PGOOptions::CSIRUse
@@ -872,18 +883,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
872883
PGOOpt->Action != PGOOptions::SampleUse &&
873884
"Cannot run CSProfileGen pass with ProfileGen or SampleUse "
874885
" pass");
875-
PGOOpt->CSProfileGenFile = CodeGenOpts.InstrProfileOutput.empty()
876-
? getDefaultProfileGenName()
877-
: CodeGenOpts.InstrProfileOutput;
886+
PGOOpt->CSProfileGenFile = getProfileGenName(CodeGenOpts);
878887
PGOOpt->CSAction = PGOOptions::CSIRInstr;
879888
} else
880-
PGOOpt = PGOOptions("",
881-
CodeGenOpts.InstrProfileOutput.empty()
882-
? getDefaultProfileGenName()
883-
: CodeGenOpts.InstrProfileOutput,
884-
"", /*MemoryProfile=*/"", nullptr,
885-
PGOOptions::NoAction, PGOOptions::CSIRInstr,
886-
ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling);
889+
PGOOpt = PGOOptions("", getProfileGenName(CodeGenOpts), "",
890+
/*MemoryProfile=*/"", nullptr, PGOOptions::NoAction,
891+
PGOOptions::CSIRInstr, ClPGOColdFuncAttr,
892+
CodeGenOpts.DebugInfoForProfiling);
887893
}
888894
if (TM)
889895
TM->setPGOOption(PGOOpt);

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
580580
const ArgList &Args, SanitizerArgs &SanArgs,
581581
ArgStringList &CmdArgs) {
582582
const Driver &D = TC.getDriver();
583+
const llvm::Triple &T = TC.getTriple();
583584
auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate,
584585
options::OPT_fprofile_generate_EQ,
585586
options::OPT_fno_profile_generate);
@@ -785,6 +786,34 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
785786
D.Diag(diag::err_drv_unsupported_option_argument)
786787
<< A->getSpelling() << Val;
787788
}
789+
if (const auto *A = Args.getLastArg(options::OPT_fprofile_continuous)) {
790+
if (!PGOGenerateArg && !CSPGOGenerateArg && !ProfileGenerateArg)
791+
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
792+
<< A->getSpelling()
793+
<< "-fprofile-generate, -fprofile-instr-generate, or "
794+
"-fcs-profile-generate";
795+
else {
796+
CmdArgs.push_back("-fprofile-continuous");
797+
// Platforms that require a bias variable:
798+
if (T.isOSBinFormatELF() || T.isOSAIX()) {
799+
CmdArgs.push_back("-mllvm");
800+
CmdArgs.push_back("-runtime-counter-relocation");
801+
}
802+
// -fprofile-instr-generate does not decide the profile file name in the
803+
// FE, and so it does not define the filename symbol
804+
// (__llvm_profile_filename). Instead, the runtime uses the name
805+
// "default.profraw" for the profile file. When continuous mode is ON, we
806+
// will create the filename symbol so that we can insert the "%c"
807+
// modifier.
808+
if (ProfileGenerateArg &&
809+
(ProfileGenerateArg->getOption().matches(
810+
options::OPT_fprofile_instr_generate) ||
811+
(ProfileGenerateArg->getOption().matches(
812+
options::OPT_fprofile_instr_generate_EQ) &&
813+
strlen(ProfileGenerateArg->getValue()) == 0)))
814+
CmdArgs.push_back("-fprofile-instrument-path=default.profraw");
815+
}
816+
}
788817

789818
int FunctionGroups = 1;
790819
int SelectedFunctionGroup = 0;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %clang_cc1 -emit-llvm -fprofile-instrument=llvm -fprofile-continuous %s -o - | FileCheck %s --check-prefix=IRPGO
2+
// RUN: %clang_cc1 -emit-llvm -fprofile-instrument=llvm -fprofile-continuous -fprofile-instrument-path=mydir/default_%m.profraw -mllvm -runtime-counter-relocation %s -o - \
3+
// RUN: | FileCheck %s --check-prefix=IRPGO_EQ
4+
// RUN: %clang_cc1 -emit-llvm -O2 -fprofile-instrument=csllvm -fprofile-continuous %s -o - | FileCheck %s --check-prefix=CSIRPGO
5+
// RUN: %clang_cc1 -emit-llvm -fprofile-instrument=clang -fprofile-continuous -fprofile-instrument-path=default.profraw %s -o - | FileCheck %s --check-prefix=CLANG_PGO
6+
7+
// IRPGO: @__llvm_profile_filename = {{.*}} c"%cdefault_%m.profraw\00"
8+
// IRPGO_EQ: @__llvm_profile_filename = {{.*}} c"%cmydir/default_%m.profraw\00"
9+
// CSIRPGO: @__llvm_profile_filename = {{.*}} c"%cdefault_%m.profraw\00"
10+
// CLANG_PGO: @__llvm_profile_filename = {{.*}} c"%cdefault.profraw\00"
11+
void foo(){}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// 1) test on platforms that (do or do not) require runtime relocation
2+
3+
// RUN: %clang --target=x86_64-darwin -fprofile-generate -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=NO_RELOC
4+
// NO_RELOC: "-cc1" {{.*}} "-fprofile-continuous"
5+
// NO_RELOC-NOT: "-mllvm" "-runtime-counter-relocation"
6+
7+
// RUN: %clang --target=powerpc64-ibm-aix -fprofile-generate -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=RELOC
8+
// RUN: %clang --target=x86_64-unknown-fuchsia -fprofile-generate -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=RELOC
9+
// RELOC: "-cc1" {{.*}} "-fprofile-continuous" "-mllvm" "-runtime-counter-relocation"
10+
11+
// 2) test -fprofile-continuous with cs-profile-generate and -fprofile-instr-generate
12+
13+
// RUN: %clang --target=powerpc-ibm-aix -fprofile-instr-generate -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=CLANG_PGO
14+
// RUN: %clang --target=powerpc64le-unknown-linux -fprofile-instr-generate= -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=CLANG_PGO
15+
// CLANG_PGO: "-cc1" {{.*}} "-fprofile-continuous" "-mllvm" "-runtime-counter-relocation" "-fprofile-instrument-path=default.profraw"
16+
17+
// RUN: %clang --target=x86_64-unknown-fuchsia -fcs-profile-generate -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=RELOC
18+
19+
// RUN: not %clang -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=ERROR
20+
// ERROR: error: invalid argument '-fprofile-continuous' only allowed with '-fprofile-generate, -fprofile-instr-generate, or -fcs-profile-generate'
21+
void foo(){}

0 commit comments

Comments
 (0)