diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 260e84910c6f7..1ea252872e8fe 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -3033,6 +3033,24 @@ indexed format, regardeless whether it is produced by frontend or the IR pass. overhead. ``prefer-atomic`` will be transformed to ``atomic`` when supported by the target, or ``single`` otherwise. +.. option:: -fprofile-continuous + + Enables the continuous instrumentation profiling where profile counter updates + are continuously synced to a file. This option sets any neccessary modifiers + (currently ``%c``) in the default profile filename and passes any necessary + flags to the middle-end to support this mode. Value profiling is not supported + in continuous mode. + + .. code-block:: console + + $ clang++ -O2 -fprofile-generate -fprofile-continuous code.cc -o code + + Running ``./code`` will collect the profile and write it to the + ``default_xxxx.profraw`` file. However, if ``./code`` abruptly terminates or + does not call ``exit()``, in continuous mode the profile collected up to the + point of termination will be available in ``default_xxxx.profraw`` while in + the non-continuous mode, no profile file is generated. + .. option:: -ftemporal-profile Enables the temporal profiling extension for IRPGO to improve startup time by diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 0f4ed13d5f3d8..2b7e717237a15 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -221,6 +221,7 @@ AFFECTING_VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option spec AFFECTING_VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified. CODEGENOPT(AtomicProfileUpdate , 1, 0) ///< Set -fprofile-update=atomic +CODEGENOPT(ContinuousProfileSync, 1, 0) ///< Enable continuous instrumentation profiling /// Choose profile instrumenation kind or no instrumentation. ENUM_CODEGENOPT(ProfileInstr, ProfileInstrKind, 2, ProfileNone) /// Choose profile kind for PGO use compilation. diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 2721c1b5d8dc5..c39cc9f276fef 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1886,6 +1886,11 @@ def fprofile_update_EQ : Joined<["-"], "fprofile-update=">, Values<"atomic,prefer-atomic,single">, MetaVarName<"">, HelpText<"Set update method of profile counters">, MarshallingInfoFlag>; +def fprofile_continuous : Flag<["-"], "fprofile-continuous">, + Group, Visibility<[ClangOption, CC1Option]>, + HelpText<"Enable continuous instrumentation profiling mode">, + MarshallingInfoFlag>; + defm pseudo_probe_for_profiling : BoolFOption<"pseudo-probe-for-profiling", CodeGenOpts<"PseudoProbeForProfiling">, DefaultFalse, PosFlag, diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 3951ad01497cc..1aed835fb5fbb 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -124,15 +124,25 @@ namespace clang { extern llvm::cl::opt ClSanitizeGuardChecks; } -namespace { - // Default filename used for profile generation. -std::string getDefaultProfileGenName() { +static std::string getDefaultProfileGenName() { return DebugInfoCorrelate || ProfileCorrelate != InstrProfCorrelator::NONE ? "default_%m.proflite" : "default_%m.profraw"; } +// Path and name of file used for profile generation +static std::string getProfileGenName(const CodeGenOptions &CodeGenOpts) { + std::string FileName = CodeGenOpts.InstrProfileOutput.empty() + ? getDefaultProfileGenName() + : CodeGenOpts.InstrProfileOutput; + if (CodeGenOpts.ContinuousProfileSync) + FileName = "%c" + FileName; + return FileName; +} + +namespace { + class EmitAssemblyHelper { CompilerInstance &CI; DiagnosticsEngine &Diags; @@ -550,7 +560,9 @@ getInstrProfOptions(const CodeGenOptions &CodeGenOpts, return std::nullopt; InstrProfOptions Options; Options.NoRedZone = CodeGenOpts.DisableRedZone; - Options.InstrProfileOutput = CodeGenOpts.InstrProfileOutput; + Options.InstrProfileOutput = CodeGenOpts.ContinuousProfileSync + ? ("%c" + CodeGenOpts.InstrProfileOutput) + : CodeGenOpts.InstrProfileOutput; Options.Atomic = CodeGenOpts.AtomicProfileUpdate; return Options; } @@ -811,13 +823,12 @@ void EmitAssemblyHelper::RunOptimizationPipeline( if (CodeGenOpts.hasProfileIRInstr()) // -fprofile-generate. - PGOOpt = PGOOptions( - CodeGenOpts.InstrProfileOutput.empty() ? getDefaultProfileGenName() - : CodeGenOpts.InstrProfileOutput, - "", "", CodeGenOpts.MemoryProfileUsePath, nullptr, PGOOptions::IRInstr, - PGOOptions::NoCSAction, ClPGOColdFuncAttr, - CodeGenOpts.DebugInfoForProfiling, - /*PseudoProbeForProfiling=*/false, CodeGenOpts.AtomicProfileUpdate); + PGOOpt = PGOOptions(getProfileGenName(CodeGenOpts), "", "", + CodeGenOpts.MemoryProfileUsePath, nullptr, + PGOOptions::IRInstr, PGOOptions::NoCSAction, + ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling, + /*PseudoProbeForProfiling=*/false, + CodeGenOpts.AtomicProfileUpdate); else if (CodeGenOpts.hasProfileIRUse()) { // -fprofile-use. auto CSAction = CodeGenOpts.hasProfileCSIRUse() ? PGOOptions::CSIRUse @@ -861,18 +872,13 @@ void EmitAssemblyHelper::RunOptimizationPipeline( PGOOpt->Action != PGOOptions::SampleUse && "Cannot run CSProfileGen pass with ProfileGen or SampleUse " " pass"); - PGOOpt->CSProfileGenFile = CodeGenOpts.InstrProfileOutput.empty() - ? getDefaultProfileGenName() - : CodeGenOpts.InstrProfileOutput; + PGOOpt->CSProfileGenFile = getProfileGenName(CodeGenOpts); PGOOpt->CSAction = PGOOptions::CSIRInstr; } else - PGOOpt = PGOOptions("", - CodeGenOpts.InstrProfileOutput.empty() - ? getDefaultProfileGenName() - : CodeGenOpts.InstrProfileOutput, - "", /*MemoryProfile=*/"", nullptr, - PGOOptions::NoAction, PGOOptions::CSIRInstr, - ClPGOColdFuncAttr, CodeGenOpts.DebugInfoForProfiling); + PGOOpt = PGOOptions("", getProfileGenName(CodeGenOpts), "", + /*MemoryProfile=*/"", nullptr, PGOOptions::NoAction, + PGOOptions::CSIRInstr, ClPGOColdFuncAttr, + CodeGenOpts.DebugInfoForProfiling); } if (TM) TM->setPGOOption(PGOOpt); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 33f08cf28feca..8e91f3bff2a17 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -580,6 +580,7 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, const ArgList &Args, SanitizerArgs &SanArgs, ArgStringList &CmdArgs) { const Driver &D = TC.getDriver(); + const llvm::Triple &T = TC.getTriple(); auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate, options::OPT_fprofile_generate_EQ, options::OPT_fno_profile_generate); @@ -785,6 +786,34 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, D.Diag(diag::err_drv_unsupported_option_argument) << A->getSpelling() << Val; } + if (const auto *A = Args.getLastArg(options::OPT_fprofile_continuous)) { + if (!PGOGenerateArg && !CSPGOGenerateArg && !ProfileGenerateArg) + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << A->getSpelling() + << "-fprofile-generate, -fprofile-instr-generate, or " + "-fcs-profile-generate"; + else { + CmdArgs.push_back("-fprofile-continuous"); + // Platforms that require a bias variable: + if (T.isOSBinFormatELF() || T.isOSAIX()) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-runtime-counter-relocation"); + } + // -fprofile-instr-generate does not decide the profile file name in the + // FE, and so it does not define the filename symbol + // (__llvm_profile_filename). Instead, the runtime uses the name + // "default.profraw" for the profile file. When continuous mode is ON, we + // will create the filename symbol so that we can insert the "%c" + // modifier. + if (ProfileGenerateArg && + (ProfileGenerateArg->getOption().matches( + options::OPT_fprofile_instr_generate) || + (ProfileGenerateArg->getOption().matches( + options::OPT_fprofile_instr_generate_EQ) && + strlen(ProfileGenerateArg->getValue()) == 0))) + CmdArgs.push_back("-fprofile-instrument-path=default.profraw"); + } + } int FunctionGroups = 1; int SelectedFunctionGroup = 0; diff --git a/clang/test/CodeGen/profile-continuous.c b/clang/test/CodeGen/profile-continuous.c new file mode 100644 index 0000000000000..86fa1d149b971 --- /dev/null +++ b/clang/test/CodeGen/profile-continuous.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -emit-llvm -fprofile-instrument=llvm -fprofile-continuous %s -o - | FileCheck %s --check-prefix=IRPGO +// RUN: %clang_cc1 -emit-llvm -fprofile-instrument=llvm -fprofile-continuous -fprofile-instrument-path=mydir/default_%m.profraw -mllvm -runtime-counter-relocation %s -o - \ +// RUN: | FileCheck %s --check-prefix=IRPGO_EQ +// RUN: %clang_cc1 -emit-llvm -O2 -fprofile-instrument=csllvm -fprofile-continuous %s -o - | FileCheck %s --check-prefix=CSIRPGO +// RUN: %clang_cc1 -emit-llvm -fprofile-instrument=clang -fprofile-continuous -fprofile-instrument-path=default.profraw %s -o - | FileCheck %s --check-prefix=CLANG_PGO + +// IRPGO: @__llvm_profile_filename = {{.*}} c"%cdefault_%m.profraw\00" +// IRPGO_EQ: @__llvm_profile_filename = {{.*}} c"%cmydir/default_%m.profraw\00" +// CSIRPGO: @__llvm_profile_filename = {{.*}} c"%cdefault_%m.profraw\00" +// CLANG_PGO: @__llvm_profile_filename = {{.*}} c"%cdefault.profraw\00" +void foo(){} diff --git a/clang/test/Driver/fprofile-continuous.c b/clang/test/Driver/fprofile-continuous.c new file mode 100644 index 0000000000000..81719fb70cb1e --- /dev/null +++ b/clang/test/Driver/fprofile-continuous.c @@ -0,0 +1,21 @@ +// 1) test on platforms that (do or do not) require runtime relocation + +// RUN: %clang --target=x86_64-darwin -fprofile-generate -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=NO_RELOC +// NO_RELOC: "-cc1" {{.*}} "-fprofile-continuous" +// NO_RELOC-NOT: "-mllvm" "-runtime-counter-relocation" + +// RUN: %clang --target=powerpc64-ibm-aix -fprofile-generate -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=RELOC +// RUN: %clang --target=x86_64-unknown-fuchsia -fprofile-generate -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=RELOC +// RELOC: "-cc1" {{.*}} "-fprofile-continuous" "-mllvm" "-runtime-counter-relocation" + +// 2) test -fprofile-continuous with cs-profile-generate and -fprofile-instr-generate + +// RUN: %clang --target=powerpc-ibm-aix -fprofile-instr-generate -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=CLANG_PGO +// RUN: %clang --target=powerpc64le-unknown-linux -fprofile-instr-generate= -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=CLANG_PGO +// CLANG_PGO: "-cc1" {{.*}} "-fprofile-continuous" "-mllvm" "-runtime-counter-relocation" "-fprofile-instrument-path=default.profraw" + +// RUN: %clang --target=x86_64-unknown-fuchsia -fcs-profile-generate -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=RELOC + +// RUN: not %clang -fprofile-continuous -### -c %s 2>&1 | FileCheck %s --check-prefix=ERROR +// ERROR: error: invalid argument '-fprofile-continuous' only allowed with '-fprofile-generate, -fprofile-instr-generate, or -fcs-profile-generate' +void foo(){}