diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c index 1c58584d2d4f73c137f8765b6581311e53ef3106..13ce7ee2cce145f392284ff91514c882ab5a3a30 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); @@ -322,8 +324,8 @@ static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs, return 0; } -/* TODO: make buffer size controllable by an internal option, and compiler can pass the size - to runtime via a variable. */ +/* TODO: make buffer size controllable by an internal option, and compiler can + pass the size to runtime via a variable. */ static uint32_t orderFileWriter(FILE *File, const uint32_t *DataStart) { if (fwrite(DataStart, sizeof(uint32_t), INSTR_ORDER_FILE_BUFFER_SIZE, File) != INSTR_ORDER_FILE_BUFFER_SIZE) @@ -468,7 +470,7 @@ static void createProfileDir(const char *Filename) { * the original profile data is truncated and gets ready for the profile * dumper. With profile merging enabled, each executable as well as any of * its instrumented shared libraries dump profile data into their own data file. -*/ + */ static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) { FILE *ProfileFile = getProfileFile(); int rc; @@ -1064,14 +1066,75 @@ void __llvm_profile_initialize_file(void) { parseAndSetFilename(SelectedPat, PNS, 0); } +/* A tesfunction for sigaction in llvm-runtime. + * See __llvm_profile_initialize. + */ +COMPILER_RT_VISIBILITY +void __llvm_profile_reset_signal_handler(int sig, siginfo_t *info, + 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(sig, info, context); + } + } + + __llvm_profile_reset_counters(); +} + +COMPILER_RT_VISIBILITY +int __llvm_profile_get_reset_signal_num() { + + const char *env_name = "LLVM_PROFILE_RESET_SIGNUM"; + char *env_value_str = getenv(env_name); + + if (env_value_str == NULL || strlen(env_value_str)==0) { + return 0; + } + + char *endptr; // Check if converted successfully + long value = strtol(env_value_str, &endptr, 10); + + // LLVM_PROFILE_RESET_SIGNUM not a number + if (endptr == env_value_str || *endptr != '\0') { + return 0; + } + + // Valid values between 40 and 64 + if (value >= 40 && value <= 64) { + return value; + } + return 0; +} + +/* This method is invoked by `__llvm_profile_initialize` + * Used to register signal handler function. + */ +COMPILER_RT_VISIBILITY +void __llvm_profile_initialize_sighandler(int signum) { + struct sigaction reset; + sigemptyset(&reset.sa_mask); + reset.sa_sigaction = __llvm_profile_reset_signal_handler; + reset.sa_flags = SA_SIGINFO; + sigaction(signum, &reset, &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 signum; + __llvm_profile_initialize_file(); if (!__llvm_profile_is_continuous_mode_enabled()) __llvm_profile_register_write_file_atexit(); + signum=__llvm_profile_get_reset_signal_num(); + if (signum) + __llvm_profile_initialize_sighandler(signum); } /* 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..f02c3e5f26db434b18cf11cd8a35d1c676ba32f3 --- /dev/null +++ b/compiler-rt/test/profile/instrprof-counter-signal-reset.c @@ -0,0 +1,23 @@ +// 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 //CHECK: [[# @LINE]]| | +#include //CHECK-NEXT: [[# @LINE]]| | + //CHECK-NEXT: [[# @LINE]]| | +int main(){ //CHECK-NEXT: [[# @LINE]]| 0| + int j=1; //CHECK-NEXT: [[# @LINE]]| 0| + for(int i=0;i<100;++i){ //CHECK-NEXT: [[# @LINE]]| 79| + if(i==20){ //CHECK-NEXT: [[# @LINE]]| 79| + kill(getpid(), 40); //CHECK-NEXT: [[# @LINE]]| 0| + } //CHECK-NEXT: [[# @LINE]]| 0| + if(i<20){ //CHECK-NEXT: [[# @LINE]]| 79| + ++j; //CHECK-NEXT: [[# @LINE]]| 0| + } //CHECK-NEXT: [[# @LINE]]| 0| + else{ //CHECK-NEXT: [[# @LINE]]| 79| + j+=2; //CHECK-NEXT: [[# @LINE]]| 79| + } //CHECK-NEXT: [[# @LINE]]| 79| + } //CHECK-NEXT: [[# @LINE]]| 79| + return 0; //CHECK-NEXT: [[# @LINE]]| 0| +} //CHECK-NEXT: [[# @LINE]]| 0|