Commit 8c4208d5 authored by Zequan Wu's avatar Zequan Wu
Browse files

[Profile][NFC] Clean up initializeProfileForContinuousMode

Merge two versions of `initializeProfileForContinuousMode` function into one.

Differential Revision: https://reviews.llvm.org/D107591
parent d238b602
Loading
Loading
Loading
Loading
+153 −219
Original line number Diff line number Diff line
@@ -92,6 +92,56 @@ static lprofFilename lprofCurFilename = {0, 0, 0, {0}, NULL,
                                         {0}, 0, 0, 0,   PNS_unknown};

static int ProfileMergeRequested = 0;

#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;
#elif defined(__ELF__) || defined(_WIN32)

#define INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR                            \
  INSTR_PROF_CONCAT(INSTR_PROF_PROFILE_COUNTER_BIAS_VAR, _default)
intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR = 0;

/* This variable is a weak external reference which could be used to detect
 * whether or not the compiler defined this symbol. */
#if defined(_WIN32)
COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;
#if defined(_M_IX86) || defined(__i386__)
#define WIN_SYM_PREFIX "_"
#else
#define WIN_SYM_PREFIX
#endif
#pragma comment(                                                               \
    linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE(                 \
                INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" WIN_SYM_PREFIX        \
                INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR))
#else
COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR
    __attribute__((weak, alias(INSTR_PROF_QUOTE(
                             INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR))));
#endif
static const int ContinuousModeSupported = 1;
static const int UseBiasVar = 1;
/* TODO: If there are two DSOs, the second DSO initilization will truncate the
 * first profile file. */
static const char *FileOpenMode = "w+b";
/* This symbol is defined by the compiler when runtime counter relocation is
 * 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;
#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;
#endif

static int isProfileMergeRequested() { return ProfileMergeRequested; }
static void setProfileMergeRequested(int EnableMerge) {
  ProfileMergeRequested = EnableMerge;
@@ -426,8 +476,6 @@ static void truncateCurrentFile(void) {
  fclose(File);
}

// TODO: Move these functions into InstrProfilingPlatform* files.
#if defined(__APPLE__)
/* Write a partial profile to \p Filename, which is required to be backed by
 * the open file object \p File. */
static int writeProfileWithFileObject(const char *Filename, FILE *File) {
@@ -439,19 +487,17 @@ static int writeProfileWithFileObject(const char *Filename, FILE *File) {
  return rc;
}

/* Unlock the profile \p File and clear the unlock flag. */
static void unlockProfile(int *ProfileRequiresUnlock, FILE *File) {
  if (!*ProfileRequiresUnlock) {
    PROF_WARN("%s", "Expected to require profile unlock\n");
  }

  lprofUnlockFileHandle(File);
  *ProfileRequiresUnlock = 0;
}

static void initializeProfileForContinuousMode(void) {
  if (!__llvm_profile_is_continuous_mode_enabled())
    return;
  if (!ContinuousModeSupported) {
    PROF_ERR("%s\n", "continuous mode is unsupported on this platform");
    return;
  }
  if (UseBiasVar && BiasAddr == BiasDefaultAddr) {
    PROF_ERR("%s\n", "__llvm_profile_counter_bias is undefined");
    return;
  }

  /* Get the sizes of various profile data sections. Taken from
   * __llvm_profile_get_size_for_buffer(). */
@@ -465,19 +511,6 @@ static void initializeProfileForContinuousMode(void) {
  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;
  }
  if ((intptr_t)DataBegin % PageSize != 0) {
    PROF_ERR("Data section not page-aligned (start = %p, pagesz = %u).\n",
             DataBegin, PageSize);
    return;
  }

  int Length = getCurFilenameLength();
  char *FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
  const char *Filename = getCurFilename(FilenameBuf, 0);
@@ -486,33 +519,7 @@ static void initializeProfileForContinuousMode(void) {

  FILE *File = NULL;
  off_t CurrentFileOffset = 0;
  off_t OffsetModPage = 0;

  /* Whether an exclusive lock on the profile must be dropped after init.
   * Use a cleanup to warn if the unlock does not occur. */
  COMPILER_RT_CLEANUP(warnIfNonZero) int ProfileRequiresUnlock = 0;

  if (!doMerging()) {
    /* We are not merging profiles, so open the raw profile in append mode. */
    File = fopen(Filename, "a+b");
    if (!File)
      return;

    /* Check that the offset within the file is page-aligned. */
    CurrentFileOffset = ftello(File);
    OffsetModPage = CurrentFileOffset % PageSize;
    if (OffsetModPage != 0) {
      PROF_ERR("Continuous counter sync mode is enabled, but raw profile is not"
               "page-aligned. CurrentFileOffset = %" PRIu64 ", pagesz = %u.\n",
               (uint64_t)CurrentFileOffset, PageSize);
      return;
    }

    /* Grow the profile so that mmap() can succeed.  Leak the file handle, as
     * the file should stay open. */
    if (writeProfileWithFileObject(Filename, File) != 0)
      return;
  } else {
  if (doMerging()) {
    /* We are merging profiles. Map the counter section as shared memory into
     * the profile, i.e. into each participating process. An increment in one
     * process should be visible to every other process with the same counter
@@ -521,24 +528,47 @@ static void initializeProfileForContinuousMode(void) {
    if (!File)
      return;

    ProfileRequiresUnlock = 1;

    uint64_t ProfileFileSize;
    if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1)
      return unlockProfile(&ProfileRequiresUnlock, File);

    uint64_t ProfileFileSize = 0;
    if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) {
      lprofUnlockFileHandle(File);
      fclose(File);
      return;
    }
    if (ProfileFileSize == 0) {
      /* Grow the profile so that mmap() can succeed.  Leak the file handle, as
       * the file should stay open. */
      if (writeProfileWithFileObject(Filename, File) != 0)
        return unlockProfile(&ProfileRequiresUnlock, File);
      if (writeProfileWithFileObject(Filename, File) != 0) {
        lprofUnlockFileHandle(File);
        fclose(File);
        return;
      }
    } 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 ||
          munmap(ProfileBuffer, ProfileFileSize) == -1)
        return unlockProfile(&ProfileRequiresUnlock, File);
          munmap(ProfileBuffer, ProfileFileSize)) {
        lprofUnlockFileHandle(File);
        fclose(File);
        return;
      }
    }
  } else {
    File = fopen(Filename, FileOpenMode);
    if (!File)
      return;
    /* Check that the offset within the file is page-aligned. */
    CurrentFileOffset = ftello(File);
    unsigned PageSize = getpagesize();
    if (CurrentFileOffset % PageSize != 0) {
      PROF_ERR("Continuous counter sync mode is enabled, but raw profile is not"
               "page-aligned. CurrentFileOffset = %" PRIu64 ", pagesz = %u.\n",
               (uint64_t)CurrentFileOffset, PageSize);
      return;
    }
    if (writeProfileWithFileObject(Filename, File) != 0) {
      fclose(File);
      return;
    }
  }

@@ -546,9 +576,45 @@ static void initializeProfileForContinuousMode(void) {
   * 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,
                                   MAP_SHARED, 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) +
          (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;

    /* Determine how much padding is needed before/after the counters and after
     * the names. */
      /* 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(
@@ -561,9 +627,10 @@ static void initializeProfileForContinuousMode(void) {
          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);
      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"
@@ -575,146 +642,13 @@ static void initializeProfileForContinuousMode(void) {
            FileOffsetToCounters);
      }
    }

  if (ProfileRequiresUnlock)
    unlockProfile(&ProfileRequiresUnlock, File);
}
#elif defined(__ELF__) || defined(_WIN32)

#define INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR                            \
  INSTR_PROF_CONCAT(INSTR_PROF_PROFILE_COUNTER_BIAS_VAR, _default)
intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR = 0;

/* This variable is a weak external reference which could be used to detect
 * whether or not the compiler defined this symbol. */
#if defined(_WIN32)
COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;
#if defined(_M_IX86) || defined(__i386__)
#define WIN_SYM_PREFIX "_"
#else
#define WIN_SYM_PREFIX
#endif
#pragma comment(                                                               \
    linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE(                 \
                INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" WIN_SYM_PREFIX        \
                INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR))
#else
COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR
    __attribute__((weak, alias(INSTR_PROF_QUOTE(
                             INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR))));
#endif

static int writeMMappedFile(FILE *OutputFile, char **Profile) {
  if (!OutputFile)
    return -1;

  /* Write the data into a file. */
  setupIOBuffer();
  ProfDataWriter fileWriter;
  initFileWriter(&fileWriter, OutputFile);
  if (lprofWriteData(&fileWriter, NULL, 0)) {
    PROF_ERR("Failed to write profile: %s\n", strerror(errno));
    return -1;
  }
  fflush(OutputFile);

  /* Get the file size. */
  uint64_t FileSize = ftell(OutputFile);

  /* Map the profile. */
  *Profile = (char *)mmap(
      NULL, FileSize, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(OutputFile), 0);
  if (*Profile == MAP_FAILED) {
    PROF_ERR("Unable to mmap profile: %s\n", strerror(errno));
    return -1;
  }

  return 0;
}

static void initializeProfileForContinuousMode(void) {
  if (!__llvm_profile_is_continuous_mode_enabled())
    return;

  /* This symbol is defined by the compiler when runtime counter relocation is
   * used and runtime provides a weak alias so we can check if it's defined. */
  void *BiasAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;
  void *BiasDefaultAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR;
  if (BiasAddr == BiasDefaultAddr) {
    PROF_ERR("%s\n", "__llvm_profile_counter_bias is undefined");
    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();
  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);
  const uint64_t CountersOffset =
      sizeof(__llvm_profile_header) + (DataSize * sizeof(__llvm_profile_data));

  int Length = getCurFilenameLength();
  char *FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
  const char *Filename = getCurFilename(FilenameBuf, 0);
  if (!Filename)
    return;

  FILE *File = NULL;
  char *Profile = NULL;

  if (!doMerging()) {
    File = fopen(Filename, "w+b");
    if (!File)
      return;

    if (writeMMappedFile(File, &Profile) == -1) {
      fclose(File);
      return;
  }
  } else {
    File = lprofOpenFileEx(Filename);
    if (!File)
      return;

    uint64_t ProfileFileSize = 0;
    if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) {
  if (doMerging()) {
    lprofUnlockFileHandle(File);
    fclose(File);
      return;
  }

    if (!ProfileFileSize) {
      if (writeMMappedFile(File, &Profile) == -1) {
        fclose(File);
        return;
      }
    } else {
      /* The merged profile has a non-zero length. Check that it is compatible
       * with the data in this process. */
      if (mmapProfileForMerging(File, ProfileFileSize, &Profile) == -1) {
        fclose(File);
        return;
}
    }

    lprofUnlockFileHandle(File);
  }

  /* Update the profile fields based on the current mapping. */
  INSTR_PROF_PROFILE_COUNTER_BIAS_VAR =
      (intptr_t)Profile - (uintptr_t)CountersBegin +
      CountersOffset;

  /* Return the memory allocated for counters to OS. */
  lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin, (uintptr_t)CountersEnd);
}
#else
static void initializeProfileForContinuousMode(void) {
  PROF_ERR("%s\n", "continuous mode is unsupported on this platform");
}
#endif

static const char *DefaultProfileName = "default.profraw";
static void resetFilenameToDefault(void) {
+0 −5
Original line number Diff line number Diff line
@@ -353,8 +353,3 @@ COMPILER_RT_VISIBILITY int lprofReleaseMemoryPagesToOS(uintptr_t Begin,
  }
  return 0;
}

COMPILER_RT_VISIBILITY void warnIfNonZero(int *i) {
  if (*i)
    PROF_WARN("Expected flag to be 0, but got: %d\n", *i);
}
+0 −3
Original line number Diff line number Diff line
@@ -84,7 +84,4 @@ static inline size_t lprofRoundDownTo(size_t x, size_t boundary) {

int lprofReleaseMemoryPagesToOS(uintptr_t Begin, uintptr_t End);

/// Noisly warn if *i is non-zero. Intended for use with COMPILER_RT_CLEANUP.
void warnIfNonZero(int *i);

#endif /* PROFILE_INSTRPROFILINGUTIL_H */