From 4f21fb84479286ddc781d73f8df152f81a8264e7 Mon Sep 17 00:00:00 2001 From: Qiongsi Wu <274595+qiongsiwu@users.noreply.github.com> Date: Mon, 22 Jan 2024 14:54:58 -0500 Subject: [PGO] Reland PGO's Counter Reset and File Dumping APIs #76471 (#78285) https://github.com/llvm/llvm-project/pull/76471 caused buildbot failures on Windows. For more details, see https://github.com/llvm/llvm-project/issues/77546. This PR revises the test and relands https://github.com/llvm/llvm-project/pull/76471. --- compiler-rt/include/CMakeLists.txt | 1 + compiler-rt/include/profile/instr_prof_interface.h | 92 ++++++++++++++++++++++ compiler-rt/lib/profile/InstrProfiling.h | 61 +++----------- .../test/profile/Linux/instrprof-weak-symbol.c | 16 ++++ compiler-rt/test/profile/instrprof-api.c | 49 ++++++++++++ 5 files changed, 169 insertions(+), 50 deletions(-) create mode 100644 compiler-rt/include/profile/instr_prof_interface.h create mode 100644 compiler-rt/test/profile/Linux/instrprof-weak-symbol.c create mode 100644 compiler-rt/test/profile/instrprof-api.c (limited to 'compiler-rt') diff --git a/compiler-rt/include/CMakeLists.txt b/compiler-rt/include/CMakeLists.txt index 78427be..7a100c6 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 0000000..be40f26 --- /dev/null +++ b/compiler-rt/include/profile/instr_prof_interface.h @@ -0,0 +1,92 @@ +/*===---- 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 fine-grained control of counter + * reset and profile dumping. These interface functions can be directly called + * in user programs. + * +\*===---------------------------------------------------------------------===*/ + +#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. +// When `-fprofile[-instr]-generate`/`-fcs-profile-generate` is in effect, +// clang defines __LLVM_INSTR_PROFILE_GENERATE to pick up the API calls. + +/*! + * \brief Set the filename for writing instrumentation data. + * + * Sets the filename to be used for subsequent calls to + * \a __llvm_profile_write_file(). + * + * \c Name is not copied, so it must remain valid. Passing NULL resets the + * filename logic to the default behaviour. + * + * Note: There may be multiple copies of the profile runtime (one for each + * instrumented image/DSO). This API only modifies the filename within the + * copy of the runtime available to the calling image. + * + * Warning: This is a no-op if continuous mode (\ref + * __llvm_profile_is_continuous_mode_enabled) is on. The reason for this is + * that in continuous mode, profile counters are mmap()'d to the profile at + * program initialization time. Support for transferring the mmap'd profile + * counts to a new file has not been implemented. + */ +void __llvm_profile_set_filename(const char *Name); + +/*! + * \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_set_filename(Name) +#define __llvm_profile_reset_counters() +#define __llvm_profile_dump() (0) +#define __llvm_orderfile_dump() (0) + +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h index 1371159..0123908 100644 --- a/compiler-rt/lib/profile/InstrProfiling.h +++ b/compiler-rt/lib/profile/InstrProfiling.h @@ -12,6 +12,17 @@ #include "InstrProfilingPort.h" #include +// Make sure __LLVM_INSTR_PROFILE_GENERATE is always defined before +// including instr_prof_interface.h so the interface functions are +// declared correctly for the runtime. +// __LLVM_INSTR_PROFILE_GENERATE is always `#undef`ed after the header, +// because compiler-rt does not support profiling the profiling runtime itself. +#ifndef __LLVM_INSTR_PROFILE_GENERATE +#define __LLVM_INSTR_PROFILE_GENERATE +#endif +#include "profile/instr_prof_interface.h" +#undef __LLVM_INSTR_PROFILE_GENERATE + #define INSTR_PROF_VISIBILITY COMPILER_RT_VISIBILITY #include "profile/InstrProfData.inc" @@ -101,12 +112,6 @@ 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. * * Read profile data from buffer \p Profile and merge with in-process profile @@ -156,50 +161,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. - * - * Sets the filename to be used for subsequent calls to - * \a __llvm_profile_write_file(). - * - * \c Name is not copied, so it must remain valid. Passing NULL resets the - * filename logic to the default behaviour. - * - * Note: There may be multiple copies of the profile runtime (one for each - * instrumented image/DSO). This API only modifies the filename within the - * copy of the runtime available to the calling image. - * - * Warning: This is a no-op if continuous mode (\ref - * __llvm_profile_is_continuous_mode_enabled) is on. The reason for this is - * that in continuous mode, profile counters are mmap()'d to the profile at - * program initialization time. Support for transferring the mmap'd profile - * counts to a new file has not been implemented. - */ -void __llvm_profile_set_filename(const char *Name); /*! * \brief Set the FILE object for writing instrumentation data. Return 0 if set diff --git a/compiler-rt/test/profile/Linux/instrprof-weak-symbol.c b/compiler-rt/test/profile/Linux/instrprof-weak-symbol.c new file mode 100644 index 0000000..eda299c --- /dev/null +++ b/compiler-rt/test/profile/Linux/instrprof-weak-symbol.c @@ -0,0 +1,16 @@ +// Test the linker feature that treats undefined weak symbols as null values. + +// RUN: %clang_pgogen -o %t %s +// RUN: not %t +// RUN: %clang -o %t %s +// RUN: %t + +__attribute__((weak)) void __llvm_profile_reset_counters(void); + +int main() { + if (__llvm_profile_reset_counters) { + __llvm_profile_reset_counters(); + return 1; + } + return 0; +} diff --git a/compiler-rt/test/profile/instrprof-api.c b/compiler-rt/test/profile/instrprof-api.c new file mode 100644 index 0000000..fedec2d --- /dev/null +++ b/compiler-rt/test/profile/instrprof-api.c @@ -0,0 +1,49 @@ +// UNSUPPORTED: target={{.*windows.*}} +// __llvm_orderfile_dump() is not supported on Windows. + +// Testing profile generate. +// RUN: %clang_profgen %s -S -emit-llvm -o - | FileCheck %s --check-prefix=PROFGEN +// RUN: %clang_pgogen %s -S -emit-llvm -o - | FileCheck %s --check-prefix=PROFGEN + +// Testing profile use. Generate some profile file first. +// RUN: rm -rf rawprof.profraw +// RUN: %clang_profgen -o %t1 %s +// RUN: %run %t1 +// RUN: llvm-profdata merge -o %t1.profdata rawprof.profraw +// RUN: %clang_profuse=%t1.profdata %s -S -emit-llvm -o - | FileCheck %s --check-prefix=PROFUSE +// RUN: rm -rf rawprof.profraw +// RUN: %clang_pgogen -o %t2 %s +// RUN: %run %t2 +// RUN: llvm-profdata merge -o %t2.profdata rawprof.profraw +// RUN: %clang_pgouse=%t2.profdata %s -S -emit-llvm -o - | FileCheck %s --check-prefix=PROFUSE +#include "profile/instr_prof_interface.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(); +} + +// PROFUSE-NOT: declare void @__llvm_profile_reset_counters() + +int main() { + int z = foo() + 3; + __llvm_profile_set_filename("rawprof.profraw"); + // PROFGEN: call void @__llvm_profile_set_filename(ptr noundef @{{.*}}) + // PROFUSE-NOT: call void @__llvm_profile_set_filename(ptr noundef @{{.*}}) + if (__llvm_profile_dump()) + return 2; + // PROFGEN: %{{.*}} = call {{(signext )*}}i32 @__llvm_profile_dump() + // PROFUSE-NOT: %{{.*}} = call {{(signext )*}}i32 @__llvm_profile_dump() + __llvm_orderfile_dump(); + // PROFGEN: %{{.*}} = call {{(signext )*}}i32 @__llvm_orderfile_dump() + // PROFUSE-NOT: %{{.*}} = call {{(signext )*}}i32 @__llvm_orderfile_dump() + return z + bar() - 11; +} + +// PROFUSE-NOT: declare void @__llvm_profile_set_filename(ptr noundef) +// PROFUSE-NOT: declare signext i32 @__llvm_profile_dump() +// PROFUSE-NOT: declare signext i32 @__llvm_orderfile_dump() -- cgit v1.1