[compiler-rt] 176a246 - [docs][clang] Document additional public profile runtime APIs (#224424)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 25 06:23:54 PDT 2026
Author: George Burgess IV
Date: 2026-09-25T07:23:45-06:00
New Revision: 176a24691b1b315cfd0f15ee8bb8adcc086683be
URL: https://github.com/llvm/llvm-project/commit/176a24691b1b315cfd0f15ee8bb8adcc086683be
DIFF: https://github.com/llvm/llvm-project/commit/176a24691b1b315cfd0f15ee8bb8adcc086683be.diff
LOG: [docs][clang] Document additional public profile runtime APIs (#224424)
Android's code coverage runtime started using these functions recently,
and I noticed they were undocumented (and the reviewer highlighted
that `instr_prof_interface.h` exists).
So this commit:
- Moves their declarations to that header
- Updates `SourceBasedCodeCoverage.md` to highlight that header
- Adds quips to said `.md` file for these functions
An LLM was used to take a first pass at this; I reviewed and refined.
Added:
Modified:
clang/docs/SourceBasedCodeCoverage.md
compiler-rt/include/profile/instr_prof_interface.h
compiler-rt/lib/profile/InstrProfiling.h
compiler-rt/test/profile/instrprof-api.c
Removed:
################################################################################
diff --git a/clang/docs/SourceBasedCodeCoverage.md b/clang/docs/SourceBasedCodeCoverage.md
index 8d43c5cfa360c3..91fa5485ce78e2 100644
--- a/clang/docs/SourceBasedCodeCoverage.md
+++ b/clang/docs/SourceBasedCodeCoverage.md
@@ -344,19 +344,23 @@ without using static initializers, do this manually:
library and executable. When the linker finds a definition of this symbol, it
knows to skip loading the object which contains the profiling runtime's
static initializer.
-- Forward-declare `void __llvm_profile_initialize_file(void)` and call it
- once from each instrumented executable. This function parses
- `LLVM_PROFILE_FILE`, sets the output path, and truncates any existing files
- at that path. To get the same behavior without truncating existing files,
- pass a filename pattern string to `void __llvm_profile_set_filename(char
- *)`. These calls can be placed anywhere so long as they precede all calls
- to `__llvm_profile_write_file`.
-- Forward-declare `int __llvm_profile_write_file(void)` and call it to write
- out a profile. This function returns 0 on success, and a non-zero value
- otherwise. Calling this function multiple times appends profile data to an
- existing on-disk raw profile.
-
-In C++ files, declare these as `extern "C"`.
+- Include `<profile/instr_prof_interface.h>` to declare the profiling runtime
+ APIs. (If including compiler interface headers is challenging in your build
+ environment, all of the functions below can instead be forward-declared
+ directly, using `extern "C"` in C++ files.)
+- Call `void __llvm_profile_initialize_file(void)` once from each instrumented
+ executable. This function parses `LLVM_PROFILE_FILE`, sets the output path,
+ and truncates any existing files at that path. To get the same behavior
+ without truncating existing files, pass a filename pattern string to `void
+ __llvm_profile_set_filename(const char *)`. These calls can be placed
+ anywhere so long as they precede all calls to `__llvm_profile_write_file`.
+ - Note: You can call `const char *__llvm_profile_get_filename(void)` to get
+ the currently configured filename. This returns a `malloc`-allocated string
+ that must be passed to `free()` (or a *static* `""` on allocation failure).
+- Call `int __llvm_profile_write_file(void)` to write out a profile. This
+ function returns 0 on success, and a non-zero value otherwise. Calling this
+ function multiple times appends profile data to an existing on-disk raw
+ profile.
### Using the profiling runtime without a filesystem
@@ -367,21 +371,32 @@ the client application uses.
The first step is to export `__llvm_profile_runtime`, as above, to disable
the default static initializers. Instead of calling the `*_file()` APIs
-described above, use the following to save the profile directly to a buffer
+described above, use the following functions from
+`<profile/instr_prof_interface.h>` to save the profile directly to a buffer
under your control:
-- Forward-declare `uint64_t __llvm_profile_get_size_for_buffer(void)` and
- call it to determine the size of the profile. You'll need to allocate a
- buffer of this size.
-- Forward-declare `int __llvm_profile_write_buffer(char *Buffer)` and call it
- to copy the current counters to `Buffer`, which is expected to already be
- allocated and big enough for the profile.
-- Optionally, forward-declare `void __llvm_profile_reset_counters(void)` and
- call it to reset the counters before entering a specific section to be
- profiled. This is only useful if there is some setup that should be excluded
- from the profile.
-
-In C++ files, declare these as `extern "C"`.
+- Call `uint64_t __llvm_profile_get_size_for_buffer(void)` to determine the
+ size of the profile. You'll need to allocate a buffer of this size.
+- Call `int __llvm_profile_write_buffer(char *Buffer)` to copy the current
+ counters to `Buffer`, which is expected to already be allocated and big
+ enough for the profile.
+- Optionally, call `void __llvm_profile_reset_counters(void)` to reset the
+ counters before entering a specific section to be profiled. This is only
+ useful if there is some setup that should be excluded from the profile.
+
+You can also merge raw profile data from an existing buffer into the current
+process's in-memory counters:
+
+- Call `int __llvm_profile_check_compatibility(const char *ProfileData,
+ uint64_t ProfileSize)` to verify that the raw profile in `ProfileData` (of
+ size `ProfileSize` bytes) was generated by the same binary and structurally
+ matches the in-process counters and bitmaps. This function returns 0 on
+ success, and a non-zero value otherwise.
+- Call `int __llvm_profile_merge_from_buffer(const char *ProfileData, uint64_t
+ ProfileSize)` to merge the raw profile in `ProfileData` into the in-process
+ counters and bitmaps. **The caller is expected to have verified compatibility
+ beforehand.** This function returns 0 on success, and a non-zero value if the
+ profile data is invalid or corrupted.
## Collecting coverage reports for the llvm project
diff --git a/compiler-rt/include/profile/instr_prof_interface.h b/compiler-rt/include/profile/instr_prof_interface.h
index 678cea094a7f3f..1efaa3b8ebf839 100644
--- a/compiler-rt/include/profile/instr_prof_interface.h
+++ b/compiler-rt/include/profile/instr_prof_interface.h
@@ -15,6 +15,8 @@
#ifndef COMPILER_RT_INSTR_PROFILING
#define COMPILER_RT_INSTR_PROFILING
+#include <stdint.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -24,6 +26,20 @@ extern "C" {
// When `-fprofile[-instr]-generate`/`-fcs-profile-generate` is in effect,
// clang defines __LLVM_INSTR_PROFILE_GENERATE to pick up the API calls.
+/*! \brief Initialize file handling. */
+void __llvm_profile_initialize_file(void);
+
+/*!
+ * \brief Write instrumentation data to the current file.
+ *
+ * Writes to the file with the last name given to \a
+ * __llvm_profile_set_filename(),
+ * or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable,
+ * or if that's not set, the last name set to INSTR_PROF_PROFILE_NAME_VAR,
+ * or if that's not set, \c "default.profraw".
+ */
+int __llvm_profile_write_file(void);
+
/*!
* \brief Set the filename for writing instrumentation data.
*
@@ -45,6 +61,20 @@ extern "C" {
*/
void __llvm_profile_set_filename(const char *Name);
+/*!
+ * \brief Return filename (including path) of the profile data. Note that if the
+ * user calls __llvm_profile_set_filename later after invoking this interface,
+ * the actual file name may
diff er from what is returned here.
+ * Side-effect: this API call will invoke malloc with dynamic memory allocation
+ * (the returned pointer must be passed to `free` to avoid a leak, unless
+ * allocation fails, in which case a static `""` is returned).
+ *
+ * Note: There may be multiple copies of the profile runtime (one for each
+ * instrumented image/DSO). This API only retrieves the filename from the copy
+ * of the runtime available to the calling image.
+ */
+const char *__llvm_profile_get_filename(void);
+
/*!
* \brief Interface to set all PGO counters to zero for the current process.
*
@@ -73,11 +103,51 @@ void __llvm_profile_reset_counters(void);
*/
int __llvm_profile_dump(void);
+/*!
+ * \brief Get required size for profile buffer.
+ */
+uint64_t __llvm_profile_get_size_for_buffer(void);
+
+/*!
+ * \brief Write instrumentation data to the given buffer.
+ *
+ * \pre \c Buffer is the start of a buffer at least as big as \a
+ * __llvm_profile_get_size_for_buffer().
+ */
+int __llvm_profile_write_buffer(char *Buffer);
+
+/*!
+ * \brief Merge profile data from buffer.
+ *
+ * Read profile data from buffer \p Profile and merge with in-process profile
+ * counters and bitmaps. The client is expected to have checked or already
+ * know the profile data in the buffer matches the in-process counter
+ * structure before calling it. Returns 0 (success) if the profile data is
+ * valid. Upon reading invalid/corrupted profile data, returns 1 (failure).
+ */
+int __llvm_profile_merge_from_buffer(const char *Profile, uint64_t Size);
+
+/*! \brief Check if profile in buffer matches the current binary.
+ *
+ * Returns 0 (success) if the profile data in buffer \p Profile with size
+ * \p Size was generated by the same binary and therefore matches
+ * structurally the in-process counters and bitmaps. If the profile data in
+ * buffer is not compatible, the interface returns 1 (failure).
+ */
+int __llvm_profile_check_compatibility(const char *Profile, uint64_t Size);
+
#else
+#define __llvm_profile_initialize_file()
+#define __llvm_profile_write_file() (0)
#define __llvm_profile_set_filename(Name)
+#define __llvm_profile_get_filename() ((const char *)0)
#define __llvm_profile_reset_counters()
#define __llvm_profile_dump() (0)
+#define __llvm_profile_get_size_for_buffer() ((uint64_t)0)
+#define __llvm_profile_write_buffer(Buffer) (0)
+#define __llvm_profile_merge_from_buffer(Profile, Size) (0)
+#define __llvm_profile_check_compatibility(Profile, Size) (0)
#endif
diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h
index 2c40476e02702e..928b045ab87afc 100644
--- a/compiler-rt/lib/profile/InstrProfiling.h
+++ b/compiler-rt/lib/profile/InstrProfiling.h
@@ -108,19 +108,6 @@ void __llvm_profile_set_page_size(unsigned PageSize);
*/
uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes);
-/*!
- * \brief Get required size for profile buffer.
- */
-uint64_t __llvm_profile_get_size_for_buffer(void);
-
-/*!
- * \brief Write instrumentation data to the given buffer.
- *
- * \pre \c Buffer is the start of a buffer at least as big as \a
- * __llvm_profile_get_size_for_buffer().
- */
-int __llvm_profile_write_buffer(char *Buffer);
-
const __llvm_profile_data *__llvm_profile_begin_data(void);
const __llvm_profile_data *__llvm_profile_end_data(void);
const char *__llvm_profile_begin_names(void);
@@ -136,27 +123,6 @@ ValueProfNode *__llvm_profile_end_vnodes(void);
const VTableProfData *__llvm_profile_begin_vtables(void);
const VTableProfData *__llvm_profile_end_vtables(void);
-/*!
- * \brief Merge profile data from buffer.
- *
- * Read profile data from buffer \p Profile and merge with in-process profile
- * counters and bitmaps. The client is expected to have checked or already
- * know the profile data in the buffer matches the in-process counter
- * structure before calling it. Returns 0 (success) if the profile data is
- * valid. Upon reading invalid/corrupted profile data, returns 1 (failure).
- */
-int __llvm_profile_merge_from_buffer(const char *Profile, uint64_t Size);
-
-/*! \brief Check if profile in buffer matches the current binary.
- *
- * Returns 0 (success) if the profile data in buffer \p Profile with size
- * \p Size was generated by the same binary and therefore matches
- * structurally the in-process counters and bitmaps. If the profile data in
- * buffer is not compatible, the interface returns 1 (failure).
- */
-int __llvm_profile_check_compatibility(const char *Profile,
- uint64_t Size);
-
/*!
* \brief Counts the number of times a target value is seen.
*
@@ -184,17 +150,6 @@ void __llvm_profile_instrument_target_value(uint64_t TargetValue, void *Data,
void INSTR_PROF_INSTRUMENT_GPU_FUNC(uint64_t *Counter, uint64_t *Uniform,
uint64_t Step);
-/*!
- * \brief Write instrumentation data to the current file.
- *
- * Writes to the file with the last name given to \a *
- * __llvm_profile_set_filename(),
- * or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable,
- * or if that's not set, the last name set to INSTR_PROF_PROFILE_NAME_VAR,
- * or if that's not set, \c "default.profraw".
- */
-int __llvm_profile_write_file(void);
-
/*!
* \brief Set the FILE object for writing instrumentation data. Return 0 if set
* successfully or return 1 if failed.
@@ -228,9 +183,6 @@ int __llvm_profile_set_file_object(FILE *File, int EnableMerge);
/*! \brief Register to write instrumentation data to file at exit. */
int __llvm_profile_register_write_file_atexit(void);
-/*! \brief Initialize file handling. */
-void __llvm_profile_initialize_file(void);
-
/*! \brief Initialize the profile runtime. */
void __llvm_profile_initialize(void);
@@ -247,19 +199,6 @@ void __llvm_profile_gcov_initialize(void);
*/
const char *__llvm_profile_get_path_prefix(void);
-/*!
- * \brief Return filename (including path) of the profile data. Note that if the
- * user calls __llvm_profile_set_filename later after invoking this interface,
- * the actual file name may
diff er from what is returned here.
- * Side-effect: this API call will invoke malloc with dynamic memory allocation
- * (the returned pointer must be passed to `free` to avoid a leak).
- *
- * Note: There may be multiple copies of the profile runtime (one for each
- * instrumented image/DSO). This API only retrieves the filename from the copy
- * of the runtime available to the calling image.
- */
-const char *__llvm_profile_get_filename(void);
-
/*! \brief Get the magic token for the file format. */
uint64_t __llvm_profile_get_magic(void);
diff --git a/compiler-rt/test/profile/instrprof-api.c b/compiler-rt/test/profile/instrprof-api.c
index a07b47e9cf9bc6..b4d2a413c35829 100644
--- a/compiler-rt/test/profile/instrprof-api.c
+++ b/compiler-rt/test/profile/instrprof-api.c
@@ -26,6 +26,35 @@ int foo() {
// PROFUSE-NOT: declare {{(arm_aapcs_vfpcc )?}}void @__llvm_profile_reset_counters()
+int other_apis(char *buf, uint64_t size) {
+ __llvm_profile_initialize_file();
+ // PROFGEN: call {{(arm_aapcs_vfpcc )?}}void @__llvm_profile_initialize_file()
+ // PROFUSE-NOT: call {{(arm_aapcs_vfpcc )?}}void @__llvm_profile_initialize_file()
+ if (__llvm_profile_write_file())
+ return 1;
+ // PROFGEN: call {{(arm_aapcs_vfpcc )?}}{{(signext )*}}i32 @__llvm_profile_write_file()
+ // PROFUSE-NOT: call {{(arm_aapcs_vfpcc )?}}{{(signext )*}}i32 @__llvm_profile_write_file()
+ const char *filename = __llvm_profile_get_filename();
+ // PROFGEN: call {{(arm_aapcs_vfpcc )?}}ptr @__llvm_profile_get_filename()
+ // PROFUSE-NOT: call {{(arm_aapcs_vfpcc )?}}ptr @__llvm_profile_get_filename()
+ uint64_t buf_size = __llvm_profile_get_size_for_buffer();
+ // PROFGEN: call {{(arm_aapcs_vfpcc )?}}i64 @__llvm_profile_get_size_for_buffer()
+ // PROFUSE-NOT: call {{(arm_aapcs_vfpcc )?}}i64 @__llvm_profile_get_size_for_buffer()
+ if (__llvm_profile_write_buffer(buf))
+ return 2;
+ // PROFGEN: call {{(arm_aapcs_vfpcc )?}}{{(signext )*}}i32 @__llvm_profile_write_buffer(ptr noundef %{{.*}})
+ // PROFUSE-NOT: call {{(arm_aapcs_vfpcc )?}}{{(signext )*}}i32 @__llvm_profile_write_buffer(ptr noundef %{{.*}})
+ if (__llvm_profile_check_compatibility(buf, size))
+ return 3;
+ // PROFGEN: call {{(arm_aapcs_vfpcc )?}}{{(signext )*}}i32 @__llvm_profile_check_compatibility(ptr noundef %{{.*}}, i64 noundef %{{.*}})
+ // PROFUSE-NOT: call {{(arm_aapcs_vfpcc )?}}{{(signext )*}}i32 @__llvm_profile_check_compatibility(ptr noundef %{{.*}}, i64 noundef %{{.*}})
+ if (__llvm_profile_merge_from_buffer(buf, size))
+ return 4;
+ // PROFGEN: call {{(arm_aapcs_vfpcc )?}}{{(signext )*}}i32 @__llvm_profile_merge_from_buffer(ptr noundef %{{.*}}, i64 noundef %{{.*}})
+ // PROFUSE-NOT: call {{(arm_aapcs_vfpcc )?}}{{(signext )*}}i32 @__llvm_profile_merge_from_buffer(ptr noundef %{{.*}}, i64 noundef %{{.*}})
+ return filename != 0 || buf_size != 0;
+}
+
int main() {
int z = foo() + 3;
__llvm_profile_set_filename("rawprof.profraw");
@@ -38,5 +67,12 @@ int main() {
return z + bar() - 11;
}
+// PROFUSE-NOT: declare void @__llvm_profile_initialize_file()
+// PROFUSE-NOT: declare signext i32 @__llvm_profile_write_file()
+// PROFUSE-NOT: declare ptr @__llvm_profile_get_filename()
+// PROFUSE-NOT: declare i64 @__llvm_profile_get_size_for_buffer()
+// PROFUSE-NOT: declare signext i32 @__llvm_profile_write_buffer(ptr noundef)
+// PROFUSE-NOT: declare signext i32 @__llvm_profile_check_compatibility(ptr noundef, i64 noundef)
+// PROFUSE-NOT: declare signext i32 @__llvm_profile_merge_from_buffer(ptr noundef, i64 noundef)
// PROFUSE-NOT: declare void @__llvm_profile_set_filename(ptr noundef)
// PROFUSE-NOT: declare signext i32 @__llvm_profile_dump()
More information about the llvm-commits
mailing list