-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[PGO] Exposing PGO's Counter Reset and File Dumping APIs #76471
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
@llvm/pr-subscribers-pgo @llvm/pr-subscribers-clang Author: Qiongsi Wu (qiongsiwu) ChangesThis PR exposes three PGO functions Additionally, this PR defines macro Full diff: https://github.com/llvm/llvm-project/pull/76471.diff 10 Files Affected:
diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
index e414ac8c770508..5ecd4fb19131e4 100644
--- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
@@ -100,7 +100,7 @@ ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
/*OwnsHeaderSearch=*/false);
PP->Initialize(Compiler.getTarget(), Compiler.getAuxTarget());
InitializePreprocessor(*PP, *PO, Compiler.getPCHContainerReader(),
- Compiler.getFrontendOpts());
+ Compiler.getFrontendOpts(), Compiler.getCodeGenOpts());
ApplyHeaderSearchOptions(*HeaderInfo, *HSO, LangOpts,
Compiler.getTarget().getTriple());
}
diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h
index 6952b48e898a81..e06f1094784caf 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -494,6 +494,12 @@ class CodeGenOptions : public CodeGenOptionsBase {
return getProfileInstr() == ProfileCSIRInstr;
}
+ /// Check if any form of instrumentation is on.
+ bool hasProfileInstr() const {
+ return hasProfileClangInstr() || hasProfileIRInstr() ||
+ hasProfileCSIRInstr();
+ }
+
/// Check if Clang profile use is on.
bool hasProfileClangUse() const {
return getProfileUse() == ProfileClangInstr;
diff --git a/clang/include/clang/Frontend/Utils.h b/clang/include/clang/Frontend/Utils.h
index 143cf4359f00b5..604e42067a3f1e 100644
--- a/clang/include/clang/Frontend/Utils.h
+++ b/clang/include/clang/Frontend/Utils.h
@@ -43,12 +43,14 @@ class PCHContainerReader;
class Preprocessor;
class PreprocessorOptions;
class PreprocessorOutputOptions;
+class CodeGenOptions;
/// InitializePreprocessor - Initialize the preprocessor getting it and the
/// environment ready to process a single file.
void InitializePreprocessor(Preprocessor &PP, const PreprocessorOptions &PPOpts,
const PCHContainerReader &PCHContainerRdr,
- const FrontendOptions &FEOpts);
+ const FrontendOptions &FEOpts,
+ const CodeGenOptions &CodeGenOpts);
/// DoPrintPreprocessedInput - Implement -E mode.
void DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 56bbef9697b650..ea44a26b6db7da 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -470,7 +470,7 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) {
// Predefine macros and configure the preprocessor.
InitializePreprocessor(*PP, PPOpts, getPCHContainerReader(),
- getFrontendOpts());
+ getFrontendOpts(), getCodeGenOpts());
// Initialize the header search object. In CUDA compilations, we use the aux
// triple (the host triple) to initialize our header search, since we need to
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index d83128adb511ef..fe0fd3614113c4 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -1364,12 +1364,22 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
TI.getTargetDefines(LangOpts, Builder);
}
+static void InitializePGOProfileMacros(const CodeGenOptions &CodeGenOpts,
+ MacroBuilder &Builder) {
+ if (CodeGenOpts.hasProfileInstr())
+ Builder.defineMacro("__LLVM_INSTR_PROFILE_GENERATE");
+
+ if (CodeGenOpts.hasProfileIRUse() || CodeGenOpts.hasProfileClangUse())
+ Builder.defineMacro("__LLVM_INSTR_PROFILE_USE");
+}
+
/// InitializePreprocessor - Initialize the preprocessor getting it and the
/// environment ready to process a single file.
-void clang::InitializePreprocessor(
- Preprocessor &PP, const PreprocessorOptions &InitOpts,
- const PCHContainerReader &PCHContainerRdr,
- const FrontendOptions &FEOpts) {
+void clang::InitializePreprocessor(Preprocessor &PP,
+ const PreprocessorOptions &InitOpts,
+ const PCHContainerReader &PCHContainerRdr,
+ const FrontendOptions &FEOpts,
+ const CodeGenOptions &CodeGenOpts) {
const LangOptions &LangOpts = PP.getLangOpts();
std::string PredefineBuffer;
PredefineBuffer.reserve(4080);
@@ -1416,6 +1426,11 @@ void clang::InitializePreprocessor(
InitializeStandardPredefinedMacros(PP.getTargetInfo(), PP.getLangOpts(),
FEOpts, Builder);
+ // The PGO instrumentation profile macros are driven by options
+ // -fprofile[-instr]-generate/-fcs-profile-generate/-fprofile[-instr]-use,
+ // hence they are not guarded by InitOpts.UsePredefines.
+ InitializePGOProfileMacros(CodeGenOpts, Builder);
+
// Add on the predefines from the driver. Wrap in a #line directive to report
// that they come from the command line.
Builder.append("# 1 \"<command line>\" 1");
diff --git a/clang/test/Profile/c-general.c b/clang/test/Profile/c-general.c
index b841f9c3d2a1d1..fa9eb7ebc78274 100644
--- a/clang/test/Profile/c-general.c
+++ b/clang/test/Profile/c-general.c
@@ -9,6 +9,15 @@
// Also check compatibility with older profiles.
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instrument-use-path=%S/Inputs/c-general.profdata.v1 | FileCheck -allow-deprecated-dag-overlap -check-prefix=PGOUSE %s
+// RUN: %clang -fprofile-generate -E -dM %s | FileCheck -match-full-lines -check-prefix=PROFGENMACRO %s
+// RUN: %clang -fprofile-instr-generate -E -dM %s | FileCheck -match-full-lines -check-prefix=PROFGENMACRO %s
+// RUN: %clang -fcs-profile-generate -E -dM %s | FileCheck -match-full-lines -check-prefix=PROFGENMACRO %s
+//
+// RUN: %clang -fprofile-use=%t.profdata -E -dM %s | FileCheck -match-full-lines -check-prefix=PROFUSEMACRO %s
+
+// PROFGENMACRO:#define __LLVM_INSTR_PROFILE_GENERATE 1
+// PROFUSEMACRO:#define __LLVM_INSTR_PROFILE_USE 1
+
// PGOGEN: @[[SLC:__profc_simple_loops]] = private global [4 x i64] zeroinitializer
// PGOGEN: @[[IFC:__profc_conditionals]] = private global [13 x i64] zeroinitializer
// PGOGEN: @[[EEC:__profc_early_exits]] = private global [9 x i64] zeroinitializer
diff --git a/compiler-rt/include/CMakeLists.txt b/compiler-rt/include/CMakeLists.txt
index 78427beedb3cc4..7a100c66bbcfda 100644
--- a/compiler-rt/include/CMakeLists.txt
+++ b/compiler-rt/include/CMakeLists.txt
@@ -44,6 +44,7 @@ endif(COMPILER_RT_BUILD_ORC)
if (COMPILER_RT_BUILD_PROFILE)
set(PROFILE_HEADERS
profile/InstrProfData.inc
+ profile/instr_prof_interface.h
)
endif(COMPILER_RT_BUILD_PROFILE)
diff --git a/compiler-rt/include/profile/instr_prof_interface.h b/compiler-rt/include/profile/instr_prof_interface.h
new file mode 100644
index 00000000000000..7d0516e5f6eaec
--- /dev/null
+++ b/compiler-rt/include/profile/instr_prof_interface.h
@@ -0,0 +1,66 @@
+/*===---- instr_prof_interface.h - Instrumentation PGO User Program API ----===
+ *
+ * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+ * See https://llvm.org/LICENSE.txt for license information.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ *
+ *===-----------------------------------------------------------------------===
+ *
+ * This header provides a public interface for user programs to provide
+ * fine-grained control of counter reset and profile dumping.
+ *
+\*===---------------------------------------------------------------------===*/
+
+#ifndef COMPILER_RT_INSTR_PROFILING
+#define COMPILER_RT_INSTR_PROFILING
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __LLVM_INSTR_PROFILE_GENERATE
+// Profile file reset and dump interfaces.
+// Only defined when `-fprofile-generate` is in effect.
+
+/*!
+ * \brief Interface to set all PGO counters to zero for the current process.
+ *
+ */
+void __llvm_profile_reset_counters(void);
+
+/*!
+ * \brief this is a wrapper interface to \c __llvm_profile_write_file.
+ * After this interface is invoked, an already dumped flag will be set
+ * so that profile won't be dumped again during program exit.
+ * Invocation of interface __llvm_profile_reset_counters will clear
+ * the flag. This interface is designed to be used to collect profile
+ * data from user selected hot regions. The use model is
+ * __llvm_profile_reset_counters();
+ * ... hot region 1
+ * __llvm_profile_dump();
+ * .. some other code
+ * __llvm_profile_reset_counters();
+ * ... hot region 2
+ * __llvm_profile_dump();
+ *
+ * It is expected that on-line profile merging is on with \c %m specifier
+ * used in profile filename . If merging is not turned on, user is expected
+ * to invoke __llvm_profile_set_filename to specify different profile names
+ * for different regions before dumping to avoid profile write clobbering.
+ */
+int __llvm_profile_dump(void);
+
+// Interface to dump the current process' order file to disk.
+int __llvm_orderfile_dump(void);
+
+#else
+#define __llvm_profile_reset_counters()
+#define __llvm_profile_dump()
+#define __llvm_orderfile_dump()
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif
diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h
index 137115996748ce..3f2c75b5df9064 100644
--- a/compiler-rt/lib/profile/InstrProfiling.h
+++ b/compiler-rt/lib/profile/InstrProfiling.h
@@ -12,6 +12,9 @@
#include "InstrProfilingPort.h"
#include <stdio.h>
+#define __LLVM_INSTR_PROFILE_GENERATE
+#include "profile/instr_prof_interface.h"
+
#define INSTR_PROF_VISIBILITY COMPILER_RT_VISIBILITY
#include "profile/InstrProfData.inc"
@@ -100,12 +103,6 @@ ValueProfNode *__llvm_profile_begin_vnodes();
ValueProfNode *__llvm_profile_end_vnodes();
uint32_t *__llvm_profile_begin_orderfile();
-/*!
- * \brief Clear profile counters to zero.
- *
- */
-void __llvm_profile_reset_counters(void);
-
/*!
* \brief Merge profile data from buffer.
*
@@ -156,29 +153,6 @@ void __llvm_profile_instrument_target_value(uint64_t TargetValue, void *Data,
int __llvm_profile_write_file(void);
int __llvm_orderfile_write_file(void);
-/*!
- * \brief this is a wrapper interface to \c __llvm_profile_write_file.
- * After this interface is invoked, an already dumped flag will be set
- * so that profile won't be dumped again during program exit.
- * Invocation of interface __llvm_profile_reset_counters will clear
- * the flag. This interface is designed to be used to collect profile
- * data from user selected hot regions. The use model is
- * __llvm_profile_reset_counters();
- * ... hot region 1
- * __llvm_profile_dump();
- * .. some other code
- * __llvm_profile_reset_counters();
- * ... hot region 2
- * __llvm_profile_dump();
- *
- * It is expected that on-line profile merging is on with \c %m specifier
- * used in profile filename . If merging is not turned on, user is expected
- * to invoke __llvm_profile_set_filename to specify different profile names
- * for different regions before dumping to avoid profile write clobbering.
- */
-int __llvm_profile_dump(void);
-
-int __llvm_orderfile_dump(void);
/*!
* \brief Set the filename for writing instrumentation data.
diff --git a/compiler-rt/test/profile/instrprof-api.c b/compiler-rt/test/profile/instrprof-api.c
new file mode 100644
index 00000000000000..600fbb575feea3
--- /dev/null
+++ b/compiler-rt/test/profile/instrprof-api.c
@@ -0,0 +1,26 @@
+// RUN: %clang_profgen %s -S -emit-llvm -o - | FileCheck %s --check-prefix=PROFGEN
+// RUN: %clang_profgen -o %t %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata merge -o %t.profdata %t.profraw
+// RUN: %clang_profuse=%t.profdata %s -S -emit-llvm -o - | FileCheck %s --check-prefix=PROFUSE
+#include "profile/instr_profiling.h"
+
+__attribute__((noinline)) int bar() { return 4; }
+
+int foo() {
+ __llvm_profile_reset_counters();
+ // PROFGEN: call void @__llvm_profile_reset_counters()
+ // PROFUSE-NOT: call void @__llvm_profile_reset_counters()
+ return bar();
+}
+
+int main() {
+ int z = foo() + 3;
+ __llvm_profile_dump();
+ // PROFGEN: %call1 = call signext i32 @__llvm_profile_dump()
+ // PROFUSE-NOT: %call1 = call signext i32 @__llvm_profile_dump()
+ __llvm_orderfile_dump();
+ // PROFGEN: %call2 = call signext i32 @__llvm_orderfile_dump()
+ // PROFUSE-NOT: %call2 = call signext i32 @__llvm_orderfile_dump()
+ return z + bar() - 11;
+}
|
Note to reviewers: I am only adding these four PGO functions because I am not sure if more should be added. Please let me know, and I will revise the PR. |
The way we have done this in the past is to declare these as weak symbols and check if they exist before calling. E.g.:
Not necessarily opposed to adding the macros etc, but the advantage of the weak symbol approach vs what you have here is that the user code can check the return values. |
@teresajohnson I mentioned the same thing on discourse but it seems like linking on AIX does not support this model. |
I see. Perhaps instead of defining these away completely, they should be defined to a dummy function with the same signature that always returns success (0 I think)? Alternatively, not define them at all when __LLVM_INSTR_PROFILE_GENERATE not defined and have the user guard calls by |
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.
Thanks so much @snehasish for the fast review! I have two questions regarding your comments. I will address the remaining comments soon as well!
Ah good catch! Thanks so much! The definitions of |
…ion to support setting profile file name.
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.
Thanks for your patience with my comments!
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.
@snehasish I appreciate your timely feedback! The latest commit aims at addressing all the comments.
That's probably ok, as it doesn't make sense to do dumping etc in a hot region of code anyway. An alternate suggestion is to make these functions real functions that simply return 0 instead of #defined to 0. But that may not avoid the issue described above because early inlining will likely inline and simplify the code before IR PGO matching anyway. |
Landing this PR. It seems that the format error is not caused by any changes in this PR. |
Breaks https://lab.llvm.org/buildbot/#/builders/127/builds/60635 |
Thanks for reporting the problem @vitalybuka ! I don't have a Windows machine to reproduce the issue. It is not clear to me how the IR can contain names like I will modify the test to check for a more general pattern, but I will not know the result till the fix lands. |
Sometimes godbolt output (like https://godbolt.org/z/MxbjcnanW) could be faster and more convenient (e.g., there is no need to get windows executable to for debugging, only LLVM IR is needed). |
Thanks for the pointer! Yup godbolt can indeed reproduce IR quite well. https://godbolt.org/z/b7G1PnxME Working on a fix. Update: sorry I missed the link in the quoted comment. Thanks for the example! |
#76471 introduced a new test but the check lines have over-restrictive patterns for a string variable name that cause test failures on Windows (e.g. https://lab.llvm.org/buildbot/#/builders/127/builds/60637/steps/4/logs/stdio). This PR fixes the test.
This PR exposes four PGO functions - `__llvm_profile_set_filename` - `__llvm_profile_reset_counters`, - `__llvm_profile_dump` - `__llvm_orderfile_dump` to user programs through the new header `instr_prof_interface.h` under `compiler-rt/include/profile`. This way, the user can include the header `profile/instr_prof_interface.h` to introduce these four names to their programs. Additionally, this PR defines macro `__LLVM_INSTR_PROFILE_GENERATE` when the program is compiled with profile generation, and defines macro `__LLVM_INSTR_PROFILE_USE` when the program is compiled with profile use. `__LLVM_INSTR_PROFILE_GENERATE` together with `instr_prof_interface.h` define the PGO functions only when the program is compiled with profile generation. When profile generation is off, these PGO functions are defined away and leave no trace in the user's program. Background: https://discourse.llvm.org/t/pgo-are-the-llvm-profile-functions-stable-c-apis-across-llvm-releases/75832
llvm#76471 introduced a new test but the check lines have over-restrictive patterns for a string variable name that cause test failures on Windows (e.g. https://lab.llvm.org/buildbot/#/builders/127/builds/60637/steps/4/logs/stdio). This PR fixes the test.
…m#76471)" Issue llvm#77546 This reverts commit 07c9189.
This PR exposes four PGO functions
__llvm_profile_set_filename
__llvm_profile_reset_counters
,__llvm_profile_dump
__llvm_orderfile_dump
to user programs through the new header
instr_prof_interface.h
undercompiler-rt/include/profile
. This way, the user can include the headerprofile/instr_prof_interface.h
to introduce these four names to their programs.Additionally, this PR defines macro
__LLVM_INSTR_PROFILE_GENERATE
when the program is compiled with profile generation, and defines macro__LLVM_INSTR_PROFILE_USE
when the program is compiled with profile use.__LLVM_INSTR_PROFILE_GENERATE
together withinstr_prof_interface.h
define the PGO functions only when the program is compiled with profile generation. When profile generation is off, these PGO functions are defined away and leave no trace in the user's program.Background: https://discourse.llvm.org/t/pgo-are-the-llvm-profile-functions-stable-c-apis-across-llvm-releases/75832