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()


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to