Revert " [profile] Implement a non-mmap path when reading profile files from a non-local filesystem (#131177)"

This reverts commit 14c95e0c8b.

Test fails on mac, e.g. https://green.lab.llvm.org/job/llvm.org/job/clang-stage1-RA/3899/testReport/junit/Profile-x86_64/Profile-x86_64/instrprof_no_mmap_during_merging_c/
This commit is contained in:
Arthur Eubanks
2025-03-19 20:27:57 +00:00
parent 2f7ad891a7
commit 32476b9934
6 changed files with 31 additions and 212 deletions

View File

@@ -419,17 +419,17 @@ static int getProfileFileSizeForMerging(FILE *ProfileFile,
* \p ProfileBuffer. Returns -1 on failure. On success, the caller is
* responsible for unmapping the mmap'd buffer in \p ProfileBuffer. */
static int mmapProfileForMerging(FILE *ProfileFile, uint64_t ProfileFileSize,
ManagedMemory *ProfileBuffer) {
lprofGetFileContentBuffer(ProfileFile, ProfileFileSize, ProfileBuffer);
if (ProfileBuffer->Status == MS_INVALID) {
PROF_ERR("Unable to merge profile data: %s\n", "reading file failed");
char **ProfileBuffer) {
*ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE,
fileno(ProfileFile), 0);
if (*ProfileBuffer == MAP_FAILED) {
PROF_ERR("Unable to merge profile data, mmap failed: %s\n",
strerror(errno));
return -1;
}
if (__llvm_profile_check_compatibility(ProfileBuffer->Addr,
ProfileFileSize)) {
(void)lprofReleaseBuffer(ProfileBuffer, ProfileFileSize);
if (__llvm_profile_check_compatibility(*ProfileBuffer, ProfileFileSize)) {
(void)munmap(*ProfileBuffer, ProfileFileSize);
PROF_WARN("Unable to merge profile data: %s\n",
"source profile file is not compatible.");
return -1;
@@ -444,7 +444,7 @@ static int mmapProfileForMerging(FILE *ProfileFile, uint64_t ProfileFileSize,
*/
static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {
uint64_t ProfileFileSize;
ManagedMemory ProfileBuffer;
char *ProfileBuffer;
/* Get the size of the profile on disk. */
if (getProfileFileSizeForMerging(ProfileFile, &ProfileFileSize) == -1)
@@ -460,9 +460,9 @@ static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {
return -1;
/* Now start merging */
if (__llvm_profile_merge_from_buffer(ProfileBuffer.Addr, ProfileFileSize)) {
if (__llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize)) {
PROF_ERR("%s\n", "Invalid profile data to merge");
(void)lprofReleaseBuffer(&ProfileBuffer, ProfileFileSize);
(void)munmap(ProfileBuffer, ProfileFileSize);
return -1;
}
@@ -471,7 +471,7 @@ static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {
(void)COMPILER_RT_FTRUNCATE(ProfileFile,
__llvm_profile_get_size_for_buffer());
(void)lprofReleaseBuffer(&ProfileBuffer, ProfileFileSize);
(void)munmap(ProfileBuffer, ProfileFileSize);
*MergeDone = 1;
return 0;
@@ -672,13 +672,13 @@ static void initializeProfileForContinuousMode(void) {
} else {
/* The merged profile has a non-zero length. Check that it is compatible
* with the data in this process. */
ManagedMemory ProfileBuffer;
char *ProfileBuffer;
if (mmapProfileForMerging(File, ProfileFileSize, &ProfileBuffer) == -1) {
lprofUnlockFileHandle(File);
fclose(File);
return;
}
(void)lprofReleaseBuffer(&ProfileBuffer, ProfileFileSize);
(void)munmap(ProfileBuffer, ProfileFileSize);
}
} else {
File = fopen(Filename, FileOpenMode);
@@ -1257,12 +1257,12 @@ COMPILER_RT_VISIBILITY int __llvm_profile_set_file_object(FILE *File,
} else {
/* The merged profile has a non-zero length. Check that it is compatible
* with the data in this process. */
ManagedMemory ProfileBuffer;
char *ProfileBuffer;
if (mmapProfileForMerging(File, ProfileFileSize, &ProfileBuffer) == -1) {
lprofUnlockFileHandle(File);
return 1;
}
(void)lprofReleaseBuffer(&ProfileBuffer, ProfileFileSize);
(void)munmap(ProfileBuffer, ProfileFileSize);
}
mmapForContinuousMode(0, File);
lprofUnlockFileHandle(File);

View File

@@ -23,7 +23,6 @@
#define COMPILER_RT_FTRUNCATE(f,l) _chsize(_fileno(f),l)
#define COMPILER_RT_ALWAYS_INLINE __forceinline
#define COMPILER_RT_CLEANUP(x)
#define COMPILER_RT_UNUSED
#define COMPILER_RT_USED
#elif __GNUC__
#ifdef _WIN32
@@ -39,7 +38,6 @@
#define COMPILER_RT_ALLOCA __builtin_alloca
#define COMPILER_RT_ALWAYS_INLINE inline __attribute((always_inline))
#define COMPILER_RT_CLEANUP(x) __attribute__((cleanup(x)))
#define COMPILER_RT_UNUSED __attribute__((unused))
#define COMPILER_RT_USED __attribute__((used))
#endif

View File

@@ -21,15 +21,6 @@
#include <unistd.h>
#endif
#ifdef _AIX
#include <sys/statfs.h>
// <sys/vmount.h> depends on `uint` to be a typedef from <sys/types.h> to
// `uint_t`; however, <sys/types.h> does not always declare `uint`. We provide
// the typedef prior to including <sys/vmount.h> to work around this issue.
typedef uint_t uint;
#include <sys/vmount.h>
#endif
#ifdef COMPILER_RT_HAS_UNAME
#include <sys/utsname.h>
#endif
@@ -267,121 +258,6 @@ COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) {
return f;
}
#if defined(_AIX)
// Return 1 (true) if the file descriptor Fd represents a file that is on a
// local filesystem, otherwise return 0.
static int isLocalFilesystem(int Fd) {
struct statfs Vfs;
if (fstatfs(Fd, &Vfs) != 0) {
PROF_ERR("%s: fstatfs(%d) failed: %s\n", __func__, Fd, strerror(errno));
return 0;
}
int Ret;
size_t BufSize = 2048u;
char *Buf;
int Tries = 3;
while (Tries--) {
Buf = malloc(BufSize);
// mntctl returns -1 if `Buf` is `NULL`.
Ret = mntctl(MCTL_QUERY, BufSize, Buf);
if (Ret != 0)
break;
BufSize = *(unsigned int *)Buf;
free(Buf);
}
if (Ret != -1) {
// Look for the correct vmount entry.
char *CurObjPtr = Buf;
while (Ret--) {
struct vmount *Vp = (struct vmount *)CurObjPtr;
_Static_assert(sizeof(Vfs.f_fsid) == sizeof(Vp->vmt_fsid),
"fsid length mismatch");
if (memcmp(&Vfs.f_fsid, &Vp->vmt_fsid, sizeof Vfs.f_fsid) == 0) {
int Answer = (Vp->vmt_flags & MNT_REMOTE) == 0;
free(Buf);
return Answer;
}
CurObjPtr += Vp->vmt_length;
}
}
free(Buf);
// There was an error in mntctl or vmount entry not found; "remote" is the
// conservative answer.
return 0;
}
#endif
static int isMmapSafe(int Fd) {
if (getenv("LLVM_PROFILE_NO_MMAP")) // For testing purposes.
return 0;
#ifdef _AIX
return isLocalFilesystem(Fd);
#else
return 1;
#endif
}
COMPILER_RT_VISIBILITY void lprofGetFileContentBuffer(FILE *F, uint64_t Length,
ManagedMemory *Buf) {
Buf->Status = MS_INVALID;
if (isMmapSafe(fileno(F))) {
Buf->Addr =
mmap(NULL, Length, PROT_READ, MAP_SHARED | MAP_FILE, fileno(F), 0);
if (Buf->Addr == MAP_FAILED)
PROF_ERR("%s: mmap failed: %s\n", __func__, strerror(errno))
else
Buf->Status = MS_MMAP;
return;
}
if (getenv("LLVM_PROFILE_VERBOSE"))
PROF_NOTE("%s\n", "could not use mmap; using fread instead");
void *Buffer = malloc(Length);
if (!Buffer) {
PROF_ERR("%s: malloc failed: %s\n", __func__, strerror(errno));
return;
}
if (ftell(F) != 0) {
PROF_ERR("%s: expecting ftell to return zero\n", __func__);
free(Buffer);
return;
}
// Read the entire file into memory.
size_t BytesRead = fread(Buffer, 1, Length, F);
if (BytesRead != (size_t)Length) {
PROF_ERR("%s: fread failed%s\n", __func__,
feof(F) ? ": end of file reached" : "");
free(Buffer);
return;
}
// Reading was successful, record the result in the Buf parameter.
Buf->Addr = Buffer;
Buf->Status = MS_MALLOC;
}
COMPILER_RT_VISIBILITY
void lprofReleaseBuffer(ManagedMemory *Buf, size_t Length) {
switch (Buf->Status) {
case MS_MALLOC:
free(Buf->Addr);
break;
case MS_MMAP:
(void)munmap(Buf->Addr, Length);
break;
default:
PROF_ERR("%s: Buffer has invalid state: %d\n", __func__, Buf->Status);
break;
}
Buf->Addr = NULL;
Buf->Status = MS_INVALID;
}
COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip,
size_t *PrefixLen) {
const char *Prefix = getenv("GCOV_PREFIX");

View File

@@ -31,25 +31,6 @@ int lprofUnlockFileHandle(FILE *F);
* lock for exclusive access. The caller will block
* if the lock is already held by another process. */
FILE *lprofOpenFileEx(const char *Filename);
enum MemoryStatus {
MS_INVALID, // Addr is not a valid address
MS_MMAP, // Addr was mmap'ed
MS_MALLOC // Addr was malloc'ed
};
typedef struct {
void *Addr;
enum MemoryStatus Status;
} ManagedMemory;
/* Read the content of a file using mmap or fread into a buffer.
* Certain files (e.g. NFS mounted) cannot be opened reliably with mmap,
* so we use fread in those cases. The corresponding lprofReleaseBuffer
* will free/munmap the buffer.
*/
void lprofGetFileContentBuffer(FILE *F, uint64_t FileSize, ManagedMemory *Buf);
void lprofReleaseBuffer(ManagedMemory *FileBuffer, size_t Length);
/* PS4 doesn't have setenv/getenv/fork. Define a shim. */
#if __ORBIS__
#include <sys/types.h>

View File

@@ -3,15 +3,11 @@
// RUN: %clang_pgogen=%t.profdir -o %t -O2 %s
// RUN: %run %t
// RUN: llvm-profdata show --all-functions --counts %t.profdir/default_*.profraw | FileCheck %s
// RUN: rm -fr %t.profdir
// RUN: env LLVM_PROFILE_NO_MMAP=1 %run %t
// RUN: llvm-profdata show --all-functions --counts %t.profdir/default_*.profraw | FileCheck %s
//
// CHECK: func1:
// CHECK: Block counts: [21]
// CHECK: Block counts: [4]
// CHECK: func2:
// CHECK: Block counts: [10]
// CHECK: Block counts: [1]
#include <sys/wait.h>
#include <unistd.h>
@@ -20,23 +16,17 @@ __attribute__((noinline)) void func1() {}
__attribute__((noinline)) void func2() {}
int main(void) {
// child | parent
// func1 func2 | func1 func2
func1(); // +10 | +1 (*)
int i = 10; // |
while (i-- > 0) { // |
pid_t pid = fork(); // |
if (pid == -1) // |
return 1; // |
if (pid == 0) { // |
func2(); // +10 |
func1(); // +10 |
return 0; // |
} // |
} // ------------+------------
int status; // 20 10 | 1 0
i = 10; // (*) the child inherits counter values prior to fork
while (i-- > 0) // from the parent in non-continuous mode.
wait(&status);
return 0;
// child | parent
int status; // func1 func2 | func1 func2
func1(); // +1 | +1 (*)
pid_t pid = fork(); // |
if (pid == -1) // |
return 1; // |
if (pid == 0) // |
func2(); // +1 |
func1(); // +1 | +1
if (pid) // ------------+------------
wait(&status); // 2 1 | 2 0
return 0; // (*) the child inherits counter values prior to fork
// from the parent in non-continuous mode.
}

View File

@@ -1,26 +0,0 @@
// RUN: mkdir -p %t.d && cd %t.d
// RUN: rm -f *.profraw
// RUN: %clang_pgogen %s -o a.out
// Need to run a.out twice. On the second time, a merge will occur, which will
// trigger an mmap.
// RUN: ./a.out
// RUN: llvm-profdata show default_*.profraw --all-functions --counts --memop-sizes 2>&1 | FileCheck %s -check-prefix=PROFDATA
// RUN: env LLVM_PROFILE_NO_MMAP=1 LLVM_PROFILE_VERBOSE=1 ./a.out 2>&1 | FileCheck %s
// RUN: llvm-profdata show default_*.profraw --all-functions --counts --memop-sizes 2>&1 | FileCheck %s -check-prefix=PROFDATA2
// CHECK: could not use mmap; using fread instead
// PROFDATA: Block counts: [1]
// PROFDATA: [ 0, 0, 1 ]
// PROFDATA: Maximum function count: 1
// PROFDATA2: Block counts: [2]
// PROFDATA2: [ 0, 0, 2 ]
// PROFDATA2: Maximum function count: 2
#include <string.h>
int ar[8];
int main() {
memcpy(ar, ar + 2, ar[0]);
memcpy(ar, ar + 2, ar[2]);
return ar[2];
}