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
