From 4c21dc16a23d10d0be562d659510d9cfa7e835e0 Mon Sep 17 00:00:00 2001 From: Zimo Ji Date: Sat, 27 Sep 2025 10:14:03 +0800 Subject: [PATCH] [InstrProf] Add reset counter by signal feature in instrumented program We implmented a feature that enables instrumented program to reset its counter by calling `__llvm_profile_reset_signal handler` when receiving a user-defined signal --- compiler-rt/lib/profile/InstrProfilingFile.c | 52 +++++++++++++++++++ .../instrprof-counter-signal-not-reset.c | 31 +++++++++++ .../profile/instrprof-counter-signal-reset.c | 30 +++++++++++ 3 files changed, 113 insertions(+) create mode 100644 compiler-rt/test/profile/instrprof-counter-signal-not-reset.c create mode 100644 compiler-rt/test/profile/instrprof-counter-signal-reset.c diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c index 1c58584d2d4f..99026a792ae8 100644 --- a/compiler-rt/lib/profile/InstrProfilingFile.c +++ b/compiler-rt/lib/profile/InstrProfilingFile.c @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef _MSC_VER /* For _alloca. */ #include @@ -92,6 +93,7 @@ static lprofFilename lprofCurFilename = {0, 0, 0, {0}, NULL, {0}, 0, 0, 0, PNS_unknown}; static int ProfileMergeRequested = 0; +static struct sigaction OldAction; static int getProfileFileSizeForMerging(FILE *ProfileFile, uint64_t *ProfileFileSize); @@ -1064,14 +1066,64 @@ void __llvm_profile_initialize_file(void) { parseAndSetFilename(SelectedPat, PNS, 0); } +COMPILER_RT_VISIBILITY +int __llvm_profile_get_reset_signum() { + const char *EnvName = "LLVM_PROFILE_RESET_SIGNUM"; + char *EnvValueString = getenv(EnvName); + + if (EnvValueString == NULL || strlen(EnvValueString) == 0) { + return 0; + } + + long ResetSignum = atoi(EnvValueString); + return ResetSignum; +} + +/* A tesfunction for sigaction in llvm-runtime. + * See __llvm_profile_initialize. + */ +COMPILER_RT_VISIBILITY +void __llvm_profile_reset_signal_handler(int ResetSignum, siginfo_t *SignalInfo, + void *Context) { + // this method can NOT prevent our reset function from replaced by handlers + // define by user. So the instrumented program shouldn't register a new + // SIG_RST_CNT signal handler function without calling + // `__llvm_profile_reset_signal handler` inside the function. + if (OldAction.sa_handler != SIG_DFL && OldAction.sa_handler != SIG_IGN) { + if (OldAction.sa_flags & SA_SIGINFO) { + OldAction.sa_sigaction(ResetSignum, SignalInfo, Context); + } + } + + if (ResetSignum >= SIGUSR1 && ResetSignum <= SIGRTMAX) + __llvm_profile_reset_counters(); +} + +/* This method is invoked by `__llvm_profile_initialize` + * Used to register signal handler function. + */ +COMPILER_RT_VISIBILITY +void __llvm_profile_initialize_reset_signal_handler(int ResetSignum) { + struct sigaction ResetAction; + sigemptyset(&ResetAction.sa_mask); + ResetAction.sa_sigaction = __llvm_profile_reset_signal_handler; + ResetAction.sa_flags = SA_SIGINFO; + sigaction(ResetSignum, &ResetAction, &OldAction); +} + /* This method is invoked by the runtime initialization hook * InstrProfilingRuntime.o if it is linked in. */ COMPILER_RT_VISIBILITY void __llvm_profile_initialize(void) { + int SignalNumber; + __llvm_profile_initialize_file(); if (!__llvm_profile_is_continuous_mode_enabled()) __llvm_profile_register_write_file_atexit(); + SignalNumber = __llvm_profile_get_reset_signum(); + if (SignalNumber) + __llvm_profile_initialize_reset_signal_handler(SignalNumber); } /* This API is directly called by the user application code. It has the diff --git a/compiler-rt/test/profile/instrprof-counter-signal-not-reset.c b/compiler-rt/test/profile/instrprof-counter-signal-not-reset.c new file mode 100644 index 000000000000..98ae1babb657 --- /dev/null +++ b/compiler-rt/test/profile/instrprof-counter-signal-not-reset.c @@ -0,0 +1,31 @@ +// Testing signal counter not reset +// RUN: %clangxx_profgen -fcoverage-mapping -Wno-comment -o %t %s +// RUN: env LLVM_PROFILE_RESET_SIGNUM=0 LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile %t.profdata 2>&1 | FileCheck %s --check-prefix=NOT-RESET +#include +#include + +int main() { + int j = 1; + for (int i = 0; i < 100; ++i) { + if (i == 20) { + kill(getpid(), 0); + } + if (i < 20) { + ++j; + } + else { + j += 2; + } + } + return 0; +} + + //NOT-RESET: 6| | + //NOT-RESET: 7| | + //NOT-RESET: 8| | + //NOT-RESET: 9| 100| + //NOT-RESET: 10| 100| + //NOT-RESET: 11| 100| + //NOT-RESET: 12| 100| diff --git a/compiler-rt/test/profile/instrprof-counter-signal-reset.c b/compiler-rt/test/profile/instrprof-counter-signal-reset.c new file mode 100644 index 000000000000..a1ccf2d9c3a5 --- /dev/null +++ b/compiler-rt/test/profile/instrprof-counter-signal-reset.c @@ -0,0 +1,30 @@ +// Testing signal counter reset +// RUN: %clangxx_profgen -fcoverage-mapping -Wno-comment -o %t %s +// RUN: env LLVM_PROFILE_RESET_SIGNUM=40 LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile %t.profdata 2>&1 | FileCheck %s +#include +#include + +int main() { + int j = 1; + for (int i = 0; i < 100; ++i) { + if (i == 20) { + kill(getpid(), 40); + } + if (i < 20) { + ++j; + } + else { + j += 2; + } + } + return 0; +} + //CHECK: 6| | + //CHECK-NEXT: 7| | + //CHECK-NEXT: 8| | + //CHECK-NEXT: 9| 0| + //CHECK-NEXT: 10| 0| + //CHECK-NEXT: 11| 79| + //CHECK-NEXT: 12| 79| -- Gitee