forked from OSchip/llvm-project
[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
This commit is contained in:
parent
8f859cc349
commit
1b05245119
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
#include <spawn.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
const int num_child_procs_to_spawn = 32;
|
||||
|
||||
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);
|
||||
extern int __llvm_profile_set_file_object(FILE *, int);
|
||||
|
||||
int coverage_test() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (!__llvm_profile_is_continuous_mode_enabled())
|
||||
return 1;
|
||||
|
||||
FILE *f = fopen(argv[1], "a+b");
|
||||
if (!f)
|
||||
return 1;
|
||||
|
||||
__llvm_profile_set_file_object(f, 0); // Try to set the file to "%t.bad".
|
||||
|
||||
if (__llvm_profile_write_file() != 0)
|
||||
return 1;
|
||||
|
||||
f = fopen(argv[1], "r");
|
||||
if (!f)
|
||||
return 1;
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
return ftell(f); // Check that the "%t.bad" is empty.
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue