[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