[compiler-rt] 1b05245 - [Profile] Support __llvm_profile_set_file_object in continuous mode.
Zequan Wu via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 27 13:09:08 PDT 2021
Author: Zequan Wu
Date: 2021-08-27T13:06:46-07:00
New Revision: 1b05245119ddb7279a2ae55319b2ae82aac306db
URL: https://github.com/llvm/llvm-project/commit/1b05245119ddb7279a2ae55319b2ae82aac306db
DIFF: https://github.com/llvm/llvm-project/commit/1b05245119ddb7279a2ae55319b2ae82aac306db.diff
LOG: [Profile] Support __llvm_profile_set_file_object in continuous mode.
Replace D107203, because __llvm_profile_set_file_object is usually used when the
process doesn't have permission to open/create file. That patch trying to copy
from old profile to new profile contradicts with the usage.
Differential Revision: https://reviews.llvm.org/D108242
Added:
Modified:
compiler-rt/lib/profile/InstrProfiling.h
compiler-rt/lib/profile/InstrProfilingFile.c
compiler-rt/test/profile/ContinuousSyncMode/set-file-object.c
Removed:
################################################################################
diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h
index 237acb33ffa1f..2e601b8ccb52e 100644
--- a/compiler-rt/lib/profile/InstrProfiling.h
+++ b/compiler-rt/lib/profile/InstrProfiling.h
@@ -194,7 +194,8 @@ int __llvm_orderfile_dump(void);
void __llvm_profile_set_filename(const char *Name);
/*!
- * \brief Set the FILE object for writing instrumentation data.
+ * \brief Set the FILE object for writing instrumentation data. Return 0 if set
+ * successfully or return 1 if failed.
*
* Sets the FILE object to be used for subsequent calls to
* \a __llvm_profile_write_file(). The profile file name set by environment
@@ -213,13 +214,12 @@ void __llvm_profile_set_filename(const char *Name);
* instrumented image/DSO). This API only modifies the file object 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.
+ * Warning: This is a no-op if EnableMerge is 0 in continuous mode (\ref
+ * __llvm_profile_is_continuous_mode_enabled), because disable merging requires
+ * copying the old profile file to new profile file and this function is usually
+ * used when the proess doesn't have permission to open file.
*/
-void __llvm_profile_set_file_object(FILE *File, int EnableMerge);
+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);
diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c
index 1c53a3f172f71..2070f93e39d67 100644
--- a/compiler-rt/lib/profile/InstrProfilingFile.c
+++ b/compiler-rt/lib/profile/InstrProfilingFile.c
@@ -92,15 +92,71 @@ static lprofFilename lprofCurFilename = {0, 0, 0, {0}, NULL,
{0}, 0, 0, 0, PNS_unknown};
static int ProfileMergeRequested = 0;
+static int getProfileFileSizeForMerging(FILE *ProfileFile,
+ uint64_t *ProfileFileSize);
#if defined(__APPLE__)
static const int ContinuousModeSupported = 1;
static const int UseBiasVar = 0;
static const char *FileOpenMode = "a+b";
-static intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;
static void *BiasAddr = NULL;
static void *BiasDefaultAddr = NULL;
-static int MmapFlags = MAP_FIXED | MAP_SHARED;
+static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
+ /* Get the sizes of various profile data sections. Taken from
+ * __llvm_profile_get_size_for_buffer(). */
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const uint64_t *CountersBegin = __llvm_profile_begin_counters();
+ const uint64_t *CountersEnd = __llvm_profile_end_counters();
+ const char *NamesBegin = __llvm_profile_begin_names();
+ const char *NamesEnd = __llvm_profile_end_names();
+ const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
+ uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
+ uint64_t CountersSize = CountersEnd - CountersBegin;
+
+ /* Check that the counter and data sections in this image are
+ * page-aligned. */
+ unsigned PageSize = getpagesize();
+ if ((intptr_t)CountersBegin % PageSize != 0) {
+ PROF_ERR("Counters section not page-aligned (start = %p, pagesz = %u).\n",
+ CountersBegin, PageSize);
+ return 1;
+ }
+ if ((intptr_t)DataBegin % PageSize != 0) {
+ PROF_ERR("Data section not page-aligned (start = %p, pagesz = %u).\n",
+ DataBegin, PageSize);
+ return 1;
+ }
+ int Fileno = fileno(File);
+ /* Determine how much padding is needed before/after the counters and
+ * after the names. */
+ uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
+ PaddingBytesAfterNames;
+ __llvm_profile_get_padding_sizes_for_counters(
+ DataSize, CountersSize, NamesSize, &PaddingBytesBeforeCounters,
+ &PaddingBytesAfterCounters, &PaddingBytesAfterNames);
+
+ uint64_t PageAlignedCountersLength =
+ (CountersSize * sizeof(uint64_t)) + PaddingBytesAfterCounters;
+ uint64_t FileOffsetToCounters =
+ CurrentFileOffset + sizeof(__llvm_profile_header) +
+ (DataSize * sizeof(__llvm_profile_data)) + PaddingBytesBeforeCounters;
+ uint64_t *CounterMmap = (uint64_t *)mmap(
+ (void *)CountersBegin, PageAlignedCountersLength, PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_SHARED, Fileno, FileOffsetToCounters);
+ if (CounterMmap != CountersBegin) {
+ PROF_ERR(
+ "Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
+ " - CountersBegin: %p\n"
+ " - PageAlignedCountersLength: %" PRIu64 "\n"
+ " - Fileno: %d\n"
+ " - FileOffsetToCounters: %" PRIu64 "\n",
+ strerror(errno), CountersBegin, PageAlignedCountersLength, Fileno,
+ FileOffsetToCounters);
+ return 1;
+ }
+ return 0;
+}
#elif defined(__ELF__) || defined(_WIN32)
#define INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR \
@@ -134,15 +190,46 @@ static const char *FileOpenMode = "w+b";
* used and runtime provides a weak alias so we can check if it's defined. */
static void *BiasAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;
static void *BiasDefaultAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR;
-static int MmapFlags = MAP_SHARED;
+static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
+ /* Get the sizes of various profile data sections. Taken from
+ * __llvm_profile_get_size_for_buffer(). */
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const uint64_t *CountersBegin = __llvm_profile_begin_counters();
+ const uint64_t *CountersEnd = __llvm_profile_end_counters();
+ uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
+ /* Get the file size. */
+ uint64_t FileSize = 0;
+ if (getProfileFileSizeForMerging(File, &FileSize))
+ return 1;
+
+ /* Map the profile. */
+ char *Profile = (char *)mmap(NULL, FileSize, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fileno(File), 0);
+ if (Profile == MAP_FAILED) {
+ PROF_ERR("Unable to mmap profile: %s\n", strerror(errno));
+ return 1;
+ }
+ const uint64_t CountersOffsetInBiasMode =
+ sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) +
+ (DataSize * sizeof(__llvm_profile_data));
+ /* Update the profile fields based on the current mapping. */
+ INSTR_PROF_PROFILE_COUNTER_BIAS_VAR =
+ (intptr_t)Profile - (uintptr_t)CountersBegin + CountersOffsetInBiasMode;
+
+ /* Return the memory allocated for counters to OS. */
+ lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin, (uintptr_t)CountersEnd);
+ return 0;
+}
#else
static const int ContinuousModeSupported = 0;
static const int UseBiasVar = 0;
static const char *FileOpenMode = "a+b";
-static intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;
static void *BiasAddr = NULL;
static void *BiasDefaultAddr = NULL;
-static int MmapFlags = MAP_SHARED;
+static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
+ return 0;
+}
#endif
static int isProfileMergeRequested() { return ProfileMergeRequested; }
@@ -154,18 +241,6 @@ static FILE *ProfileFile = NULL;
static FILE *getProfileFile() { return ProfileFile; }
static void setProfileFile(FILE *File) { ProfileFile = File; }
-COMPILER_RT_VISIBILITY void __llvm_profile_set_file_object(FILE *File,
- int EnableMerge) {
- if (__llvm_profile_is_continuous_mode_enabled()) {
- PROF_WARN("__llvm_profile_set_file_object(fd=%d) not supported, because "
- "continuous sync mode (%%c) is enabled",
- fileno(File));
- return;
- }
- setProfileFile(File);
- setProfileMergeRequested(EnableMerge);
-}
-
static int getCurFilenameLength();
static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf);
static unsigned doMerging() {
@@ -502,16 +577,9 @@ static void initializeProfileForContinuousMode(void) {
return;
}
- /* Get the sizes of various profile data sections. Taken from
- * __llvm_profile_get_size_for_buffer(). */
- const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
- const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ /* Get the sizes of counter section. */
const uint64_t *CountersBegin = __llvm_profile_begin_counters();
const uint64_t *CountersEnd = __llvm_profile_end_counters();
- const char *NamesBegin = __llvm_profile_begin_names();
- const char *NamesEnd = __llvm_profile_end_names();
- const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
- uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
uint64_t CountersSize = CountersEnd - CountersBegin;
int Length = getCurFilenameLength();
@@ -577,75 +645,8 @@ static void initializeProfileForContinuousMode(void) {
/* mmap() the profile counters so long as there is at least one counter.
* If there aren't any counters, mmap() would fail with EINVAL. */
- if (CountersSize > 0) {
- int Fileno = fileno(File);
- if (UseBiasVar) {
- /* Get the file size. */
- uint64_t FileSize = ftell(File);
-
- /* Map the profile. */
- char *Profile = (char *)mmap(NULL, FileSize, PROT_READ | PROT_WRITE,
- MmapFlags, Fileno, 0);
- if (Profile == MAP_FAILED) {
- PROF_ERR("Unable to mmap profile: %s\n", strerror(errno));
- return;
- }
- const uint64_t CountersOffsetInBiasMode =
- sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) +
- (DataSize * sizeof(__llvm_profile_data));
- /* Update the profile fields based on the current mapping. */
- INSTR_PROF_PROFILE_COUNTER_BIAS_VAR = (intptr_t)Profile -
- (uintptr_t)CountersBegin +
- CountersOffsetInBiasMode;
-
- /* Return the memory allocated for counters to OS. */
- lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin,
- (uintptr_t)CountersEnd);
- } else {
- /* Check that the counter and data sections in this image are
- * page-aligned. */
- unsigned PageSize = getpagesize();
- if ((intptr_t)CountersBegin % PageSize != 0) {
- PROF_ERR(
- "Counters section not page-aligned (start = %p, pagesz = %u).\n",
- CountersBegin, PageSize);
- return;
- }
- if ((intptr_t)DataBegin % PageSize != 0) {
- PROF_ERR("Data section not page-aligned (start = %p, pagesz = %u).\n",
- DataBegin, PageSize);
- return;
- }
- /* Determine how much padding is needed before/after the counters and
- * after the names. */
- uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
- PaddingBytesAfterNames;
- __llvm_profile_get_padding_sizes_for_counters(
- DataSize, CountersSize, NamesSize, &PaddingBytesBeforeCounters,
- &PaddingBytesAfterCounters, &PaddingBytesAfterNames);
-
- uint64_t PageAlignedCountersLength =
- (CountersSize * sizeof(uint64_t)) + PaddingBytesAfterCounters;
- uint64_t FileOffsetToCounters =
- CurrentFileOffset + sizeof(__llvm_profile_header) +
- (DataSize * sizeof(__llvm_profile_data)) + PaddingBytesBeforeCounters;
-
- uint64_t *CounterMmap =
- (uint64_t *)mmap((void *)CountersBegin, PageAlignedCountersLength,
- PROT_READ | PROT_WRITE, MmapFlags,
- Fileno, FileOffsetToCounters);
- if (CounterMmap != CountersBegin) {
- PROF_ERR(
- "Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
- " - CountersBegin: %p\n"
- " - PageAlignedCountersLength: %" PRIu64 "\n"
- " - Fileno: %d\n"
- " - FileOffsetToCounters: %" PRIu64 "\n",
- strerror(errno), CountersBegin, PageAlignedCountersLength, Fileno,
- FileOffsetToCounters);
- }
- }
- }
+ if (CountersSize > 0)
+ mmapForContinuousMode(CurrentFileOffset, File);
if (doMerging()) {
lprofUnlockFileHandle(File);
@@ -1143,4 +1144,49 @@ int __llvm_profile_register_write_file_atexit(void) {
return atexit(writeFileWithoutReturn);
}
+COMPILER_RT_VISIBILITY int __llvm_profile_set_file_object(FILE *File,
+ int EnableMerge) {
+ if (__llvm_profile_is_continuous_mode_enabled()) {
+ if (!EnableMerge) {
+ PROF_WARN("__llvm_profile_set_file_object(fd=%d) not supported in "
+ "continuous sync mode when merging is disabled\n",
+ fileno(File));
+ return 1;
+ }
+ lprofLockFileHandle(File);
+ uint64_t ProfileFileSize = 0;
+ if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) {
+ lprofUnlockFileHandle(File);
+ return 1;
+ }
+ if (ProfileFileSize == 0) {
+ FreeHook = &free;
+ setupIOBuffer();
+ ProfDataWriter fileWriter;
+ initFileWriter(&fileWriter, File);
+ if (lprofWriteData(&fileWriter, 0, 0)) {
+ lprofUnlockFileHandle(File);
+ PROF_ERR("Failed to write file \"%d\": %s\n", fileno(File),
+ strerror(errno));
+ return 1;
+ }
+ } else {
+ /* The merged profile has a non-zero length. Check that it is compatible
+ * with the data in this process. */
+ char *ProfileBuffer;
+ if (mmapProfileForMerging(File, ProfileFileSize, &ProfileBuffer) == -1) {
+ lprofUnlockFileHandle(File);
+ return 1;
+ }
+ (void)munmap(ProfileBuffer, ProfileFileSize);
+ }
+ mmapForContinuousMode(0, File);
+ lprofUnlockFileHandle(File);
+ } else {
+ setProfileFile(File);
+ setProfileMergeRequested(EnableMerge);
+ }
+ return 0;
+}
+
#endif
diff --git a/compiler-rt/test/profile/ContinuousSyncMode/set-file-object.c b/compiler-rt/test/profile/ContinuousSyncMode/set-file-object.c
index 4eea4575313da..72013d2317738 100644
--- a/compiler-rt/test/profile/ContinuousSyncMode/set-file-object.c
+++ b/compiler-rt/test/profile/ContinuousSyncMode/set-file-object.c
@@ -1,34 +1,84 @@
-// REQUIRES: darwin
+// REQUIRES: darwin || linux
-// RUN: %clang_pgogen -o %t.exe %s
-// RUN: env LLVM_PROFILE_FILE="%c%t.profraw" %run %t.exe %t.bad 2>&1 | FileCheck %s
+// Test using __llvm_profile_set_file_object in continuous mode (%c).
+// Create & cd into a temporary directory.
+// RUN: rm -rf %t.dir && mkdir -p %t.dir && cd %t.dir
-// CHECK: __llvm_profile_set_file_object(fd={{[0-9]+}}) not supported
-// CHECK: Profile data not written to file: already written.
+// The -mllvm -runtime-counter-relocation=true flag has effect only on linux.
+// RUN: %clang -fprofile-instr-generate -fcoverage-mapping -mllvm -instrprof-atomic-counter-update-all=1 -mllvm -runtime-counter-relocation=true -o main.exe %s
-#include <stdio.h>
+// Test continuous mode with __llvm_profile_set_file_object with mergin disabled.
+// RUN: env LLVM_PROFILE_FILE="%t.dir/profdir/%c%mprofraw.old" %run %t.dir/main.exe nomerge %t.dir/profdir/profraw.new 2>&1 | FileCheck %s -check-prefix=WARN
+// WARN: LLVM Profile Warning: __llvm_profile_set_file_object(fd={{[0-9]+}}) not supported in continuous sync mode when merging is disabled
-extern int __llvm_profile_is_continuous_mode_enabled(void);
-extern void __llvm_profile_set_file_object(FILE *, int);
-extern int __llvm_profile_write_file(void);
+// Test continuous mode with __llvm_profile_set_file_object with mergin enabled.
+// RUN: rm -rf %t.dir/profdir/
+// RUN: env LLVM_PROFILE_FILE="%t.dir/profdir/%c%mprofraw.old" %run %t.dir/main.exe merge %t.dir/profdir/profraw.new 'LLVM_PROFILE_FILE=%t.dir/profdir/%c%m.profraw'
+// RUN: llvm-profdata merge -o %t.dir/profdir/profdata %t.dir/profdir/profraw.new
+// RUN: llvm-profdata show --counts --all-functions %t.dir/profdir/profdata | FileCheck %s -check-prefix=MERGE
+// RUN: llvm-profdata show --counts --all-functions %t.dir/profdir/*profraw.old | FileCheck %s -check-prefix=ZERO
-int main(int argc, char **argv) {
- if (!__llvm_profile_is_continuous_mode_enabled())
- return 1;
+// MERGE: Counters:
+// MERGE: coverage_test:
+// MERGE: Hash: {{.*}}
+// MERGE: Counters: 1
+// MERGE: Function count: 32
+// MERGE: Block counts: []
+// MERGE: Instrumentation level: Front-end
+
+// ZERO: Counters:
+// ZERO: coverage_test:
+// ZERO: Hash: {{.*}}
+// ZERO: Counters: 1
+// ZERO: Function count: 0
+// ZERO: Block counts: []
+// ZERO: Instrumentation level: Front-end
- FILE *f = fopen(argv[1], "a+b");
- if (!f)
- return 1;
+#include <spawn.h>
+#include <stdio.h>
+#include <string.h>
- __llvm_profile_set_file_object(f, 0); // Try to set the file to "%t.bad".
+const int num_child_procs_to_spawn = 32;
- if (__llvm_profile_write_file() != 0)
- return 1;
+extern int __llvm_profile_is_continuous_mode_enabled(void);
+extern int __llvm_profile_set_file_object(FILE *, int);
- f = fopen(argv[1], "r");
- if (!f)
- return 1;
+int coverage_test() {
+ return 0;
+}
- fseek(f, 0, SEEK_END);
- return ftell(f); // Check that the "%t.bad" is empty.
+int main(int argc, char **argv) {
+ char *file_name = argv[2];
+ FILE *file = fopen(file_name, "a+b");
+ if (strcmp(argv[1], "nomerge") == 0)
+ __llvm_profile_set_file_object(file, 0);
+ else if (strcmp(argv[1], "merge") == 0) {
+ // Parent process.
+ int I;
+ pid_t child_pids[num_child_procs_to_spawn];
+ char *const child_argv[] = {argv[0], "set", file_name, NULL};
+ char *const child_envp[] = {argv[3], NULL};
+ for (I = 0; I < num_child_procs_to_spawn; ++I) {
+ int ret =
+ posix_spawn(&child_pids[I], argv[0], NULL, NULL, child_argv, child_envp);
+ if (ret != 0) {
+ fprintf(stderr, "Child %d could not be spawned: ret = %d, msg = %s\n",
+ I, ret, strerror(ret));
+ return 1;
+ }
+ }
+ } else if (strcmp(argv[1], "set") == 0) {
+ // Child processes.
+ if (!__llvm_profile_is_continuous_mode_enabled()) {
+ fprintf(stderr, "Continuous mode disabled\n");
+ return 1;
+ }
+ if (__llvm_profile_set_file_object(file, 1)) {
+ fprintf(stderr, "Call to __llvm_profile_set_file_object failed\n");
+ return 1;
+ }
+ // After set file object, counter should be written into new file.
+ coverage_test();
+ }
+ return 0;
}
More information about the llvm-commits
mailing list