[clang] [llvm] [InstrPGO] Instrument sampling profile based cold function (PR #110330)

Lei Wang via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 27 14:31:37 PDT 2024


https://github.com/wlei-llvm created https://github.com/llvm/llvm-project/pull/110330

None

>From d660d3b9a043a3530a735c1b95790116f6366062 Mon Sep 17 00:00:00 2001
From: wlei <wlei at fb.com>
Date: Sun, 22 Sep 2024 20:23:20 -0700
Subject: [PATCH 1/2] [InstrPGO] Instrument sampling profile based cold
 function

---
 clang/include/clang/Driver/Options.td         |  6 +++++
 clang/lib/Driver/ToolChain.cpp                |  4 +++-
 clang/lib/Driver/ToolChains/Clang.cpp         | 13 ++++++++++
 llvm/lib/Passes/PassBuilderPipelines.cpp      | 17 +++++++++++++
 .../Instrumentation/PGOInstrumentation.cpp    | 14 +++++++++++
 .../PGOProfile/instr-gen-cold-function.ll     | 24 +++++++++++++++++++
 6 files changed, 77 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/Transforms/PGOProfile/instr-gen-cold-function.ll

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index aedc4c16d4e9d5..230b9604b8a8aa 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1785,6 +1785,12 @@ defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling",
   PosFlag<SetTrue, [], [ClangOption, CC1Option],
           "Emit extra debug info to make sample profile more accurate">,
   NegFlag<SetFalse>>;
+def fprofile_sample_cold_function : Flag<["-"], "fprofile-sample-cold-function">, 
+    Group<f_Group>, Visibility<[ClangOption, CLOption]>,
+    HelpText<"Generate instrumented code to cold functions guided by sampling-based profile into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
+def fprofile_sample_cold_function_EQ : Joined<["-"], "fprofile-sample-cold-function=">, 
+    Group<f_Group>, Visibility<[ClangOption, CLOption]>, MetaVarName<"<file>">,
+    HelpText<"Generate instrumented code to cold functions guided by sampling-based profile into <file> (overridden by LLVM_PROFILE_FILE env var)">; 
 def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">,
     Group<f_Group>, Visibility<[ClangOption, CLOption]>,
     HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 16f9b629fc538c..5cd821cfe780c4 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -889,7 +889,9 @@ bool ToolChain::needsProfileRT(const ArgList &Args) {
          Args.hasArg(options::OPT_fprofile_instr_generate) ||
          Args.hasArg(options::OPT_fprofile_instr_generate_EQ) ||
          Args.hasArg(options::OPT_fcreate_profile) ||
-         Args.hasArg(options::OPT_forder_file_instrumentation);
+         Args.hasArg(options::OPT_forder_file_instrumentation) ||
+         Args.hasArg(options::OPT_fprofile_sample_cold_function) ||
+         Args.hasArg(options::OPT_fprofile_sample_cold_function_EQ);
 }
 
 bool ToolChain::needsGCovInstrumentation(const llvm::opt::ArgList &Args) {
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index b9987288d82d10..fced94833aaf79 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -649,6 +649,19 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
     }
   }
 
+  if (auto *SampleColdArg =
+          Args.getLastArg(options::OPT_fprofile_sample_cold_function,
+                          options::OPT_fprofile_sample_cold_function_EQ)) {
+    SmallString<128> Path(SampleColdArg->getOption().matches(
+                              options::OPT_fprofile_sample_cold_function_EQ)
+                              ? SampleColdArg->getValue()
+                              : "");
+    llvm::sys::path::append(Path, "default_%m.profraw");
+    CmdArgs.push_back("-mllvm");
+    CmdArgs.push_back(Args.MakeArgString(
+        Twine("--instrument-sample-cold-function-path=") + Path));
+  }
+
   Arg *PGOGenArg = nullptr;
   if (PGOGenerateArg) {
     assert(!CSPGOGenerateArg);
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index 8f151a99b11709..0514d17db20721 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -296,7 +296,13 @@ static cl::opt<bool> UseLoopVersioningLICM(
     "enable-loop-versioning-licm", cl::init(false), cl::Hidden,
     cl::desc("Enable the experimental Loop Versioning LICM pass"));
 
+static cl::opt<std::string> InstrumentSampleColdFuncPath(
+    "instrument-sample-cold-function-path", cl::init(""),
+    cl::desc("File path for instrumenting sampling PGO guided cold functions"),
+    cl::Hidden);
+
 extern cl::opt<std::string> UseCtxProfile;
+extern cl::opt<bool> InstrumentColdFunction;
 
 namespace llvm {
 extern cl::opt<bool> EnableMemProfContextDisambiguation;
@@ -1119,6 +1125,17 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
       // removed.
       MPM.addPass(
           PGOIndirectCallPromotion(true /* IsInLTO */, true /* SamplePGO */));
+
+    if (InstrumentSampleColdFuncPath.getNumOccurrences() &&
+        Phase != ThinOrFullLTOPhase::ThinLTOPostLink) {
+      assert(!InstrumentSampleColdFuncPath.empty() &&
+             "File path is requeired for instrumentation generation");
+      InstrumentColdFunction = true;
+      addPreInlinerPasses(MPM, Level, Phase);
+      addPGOInstrPasses(MPM, Level, /* RunProfileGen */ true,
+                        /* IsCS */ false, /* AtomicCounterUpdate */ false,
+                        InstrumentSampleColdFuncPath, "", PGOOpt->FS);
+    }
   }
 
   // Try to perform OpenMP specific optimizations on the module. This is a
diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
index 10442fa0bb9003..cbd14567d97c95 100644
--- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
+++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp
@@ -319,6 +319,16 @@ static cl::opt<unsigned> PGOFunctionCriticalEdgeThreshold(
     cl::desc("Do not instrument functions with the number of critical edges "
              " greater than this threshold."));
 
+cl::opt<bool> InstrumentColdFunction(
+    "instrument-cold-function", cl::init(false), cl::Hidden,
+    cl::desc("Instrument cold functions (currently only used under sampling "
+             " PGO pipeline))"));
+
+static cl::opt<uint64_t> InstrumentColdFuncMaxEntryCount(
+    "instrument-cold-function-max-entry-count", cl::init(0), cl::Hidden,
+    cl::desc("When using --instrument-cold-function, skip instrumenting the "
+             "function whose entry count is above the given value"));
+
 extern cl::opt<unsigned> MaxNumVTableAnnotations;
 
 namespace llvm {
@@ -1891,6 +1901,10 @@ static bool skipPGOGen(const Function &F) {
     return true;
   if (F.getInstructionCount() < PGOFunctionSizeThreshold)
     return true;
+  if (InstrumentColdFunction &&
+      (!F.getEntryCount() ||
+       F.getEntryCount()->getCount() > InstrumentColdFuncMaxEntryCount))
+    return true;
   return false;
 }
 
diff --git a/llvm/test/Transforms/PGOProfile/instr-gen-cold-function.ll b/llvm/test/Transforms/PGOProfile/instr-gen-cold-function.ll
new file mode 100644
index 00000000000000..14d3b3c7e9b6fa
--- /dev/null
+++ b/llvm/test/Transforms/PGOProfile/instr-gen-cold-function.ll
@@ -0,0 +1,24 @@
+; RUN: opt < %s  --passes=pgo-instr-gen -instrument-cold-function -S  | FileCheck --check-prefixes=COLD %s
+; RUN: opt < %s  --passes=pgo-instr-gen -instrument-cold-function -instrument-cold-function-max-entry-count=1 -S  | FileCheck --check-prefixes=ENTRY-COUNT %s
+
+; COLD: call void @llvm.instrprof.increment(ptr @__profn_foo, i64  [[#]], i32 1, i32 0)
+; COLD-NOT: __profn_main
+
+; ENTRY-COUNT: call void @llvm.instrprof.increment(ptr @__profn_foo, i64  [[#]], i32 1, i32 0)
+; ENTRY-COUNT: call void @llvm.instrprof.increment(ptr @__profn_main, i64 [[#]], i32 1, i32 0)
+
+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"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @foo() !prof !0 {
+entry:
+  ret void
+}
+
+define i32 @main() !prof !1 {
+entry:
+  ret i32 0
+}
+
+!0 = !{!"function_entry_count", i64 0}
+!1 = !{!"function_entry_count", i64 1}

>From e3bbabf759b6b38ebcdd1512d845aa6a1c4d6f90 Mon Sep 17 00:00:00 2001
From: wlei <wlei at fb.com>
Date: Fri, 27 Sep 2024 14:27:18 -0700
Subject: [PATCH 2/2] use -fprofile-generate to specify the profile path

---
 clang/include/clang/Driver/Options.td |  5 +----
 clang/lib/Driver/ToolChain.cpp        |  4 +---
 clang/lib/Driver/ToolChains/Clang.cpp | 30 +++++++++++++--------------
 3 files changed, 17 insertions(+), 22 deletions(-)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 230b9604b8a8aa..b7ad1c6a008087 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1787,10 +1787,7 @@ defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling",
   NegFlag<SetFalse>>;
 def fprofile_sample_cold_function : Flag<["-"], "fprofile-sample-cold-function">, 
     Group<f_Group>, Visibility<[ClangOption, CLOption]>,
-    HelpText<"Generate instrumented code to cold functions guided by sampling-based profile into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
-def fprofile_sample_cold_function_EQ : Joined<["-"], "fprofile-sample-cold-function=">, 
-    Group<f_Group>, Visibility<[ClangOption, CLOption]>, MetaVarName<"<file>">,
-    HelpText<"Generate instrumented code to cold functions guided by sampling-based profile into <file> (overridden by LLVM_PROFILE_FILE env var)">; 
+    HelpText<"Generate instrumented code to cold functions guided by sampling-based profile">;
 def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">,
     Group<f_Group>, Visibility<[ClangOption, CLOption]>,
     HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 5cd821cfe780c4..16f9b629fc538c 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -889,9 +889,7 @@ bool ToolChain::needsProfileRT(const ArgList &Args) {
          Args.hasArg(options::OPT_fprofile_instr_generate) ||
          Args.hasArg(options::OPT_fprofile_instr_generate_EQ) ||
          Args.hasArg(options::OPT_fcreate_profile) ||
-         Args.hasArg(options::OPT_forder_file_instrumentation) ||
-         Args.hasArg(options::OPT_fprofile_sample_cold_function) ||
-         Args.hasArg(options::OPT_fprofile_sample_cold_function_EQ);
+         Args.hasArg(options::OPT_forder_file_instrumentation);
 }
 
 bool ToolChain::needsGCovInstrumentation(const llvm::opt::ArgList &Args) {
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index fced94833aaf79..254e7c952b8398 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -649,26 +649,24 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
     }
   }
 
-  if (auto *SampleColdArg =
-          Args.getLastArg(options::OPT_fprofile_sample_cold_function,
-                          options::OPT_fprofile_sample_cold_function_EQ)) {
-    SmallString<128> Path(SampleColdArg->getOption().matches(
-                              options::OPT_fprofile_sample_cold_function_EQ)
-                              ? SampleColdArg->getValue()
-                              : "");
-    llvm::sys::path::append(Path, "default_%m.profraw");
+  auto *SampleColdArg =
+      Args.getLastArg(options::OPT_fprofile_sample_cold_function);
+
+  Arg *PGOGenArg = nullptr;
+  if (SampleColdArg) {
+    SmallString<128> Path(
+        PGOGenerateArg->getOption().matches(options::OPT_fprofile_generate_EQ)
+            ? PGOGenerateArg->getValue()
+            : "");
+    Path.append("default_%m.profraw");
     CmdArgs.push_back("-mllvm");
     CmdArgs.push_back(Args.MakeArgString(
         Twine("--instrument-sample-cold-function-path=") + Path));
-  }
-
-  Arg *PGOGenArg = nullptr;
-  if (PGOGenerateArg) {
+  } else if (PGOGenerateArg) {
     assert(!CSPGOGenerateArg);
     PGOGenArg = PGOGenerateArg;
     CmdArgs.push_back("-fprofile-instrument=llvm");
-  }
-  if (CSPGOGenerateArg) {
+  } else if (CSPGOGenerateArg) {
     assert(!PGOGenerateArg);
     PGOGenArg = CSPGOGenerateArg;
     CmdArgs.push_back("-fprofile-instrument=csllvm");
@@ -7037,7 +7035,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
           options::OPT_fcs_profile_generate,
           options::OPT_fcs_profile_generate_EQ, options::OPT_fprofile_use,
           options::OPT_fprofile_use_EQ);
-      if (PGOArg)
+      auto *SampleColdArg =
+          Args.getLastArg(options::OPT_fprofile_sample_cold_function);
+      if (PGOArg && !SampleColdArg)
         D.Diag(diag::err_drv_argument_not_allowed_with)
             << "SampleUse with PGO options";
 



More information about the cfe-commits mailing list