diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c index 1c58584d2d4f73c137f8765b6581311e53ef3106..99026a792ae8625d13d0c9934c49461d98558ee1 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-reset.c b/compiler-rt/test/profile/instrprof-counter-signal-reset.c new file mode 100644 index 0000000000000000000000000000000000000000..813ff5a052e62274f32f7a0f4cca4db06a54cfd4 --- /dev/null +++ b/compiler-rt/test/profile/instrprof-counter-signal-reset.c @@ -0,0 +1,42 @@ +// 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 --check-prefix=RESET +// RUN: (trap '' 40;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(), 40); + } + if (i < 20) { + ++j; + } + else { + j += 2; + } + } + return 0; +} + //RESET: 6| | + //RESET: 7| | + //RESET: 8| | + //RESET: 9| 0| + //RESET: 10| 0| + //RESET: 11| 79| + //RESET: 12| 79| + + //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|