-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[profile] Implement a non-mmap path when reading profile files from a non-local filesystem #131177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
b817019
f764d1e
c3c037b
153a141
0680091
549b019
43f4926
bfe6fa9
ee17bfa
99602d3
8e10f3f
04d66b2
987eeeb
6f55e68
189ac38
18550f9
9112370
a26ea14
66340b6
3fd025e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,15 @@ | |
| #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 | ||
|
|
@@ -258,6 +267,120 @@ COMPILER_RT_VISIBILITY FILE *lprofOpenFileEx(const char *ProfileName) { | |
| return f; | ||
| } | ||
|
|
||
| // Return 1 (true) if the file descriptor Fd represents a file that is on a | ||
| // local filesystem, otherwise return 0. | ||
| static int is_local_filesystem(int Fd) { | ||
| #if defined(_AIX) | ||
| 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); | ||
| 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. | ||
| #endif | ||
| return 0; | ||
| } | ||
|
|
||
| static int isMmapSafe(int Fd) { | ||
w2yehia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (getenv("LLVM_NO_MMAP")) // For testing purposes. | ||
w2yehia marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return 0; | ||
| (void)&is_local_filesystem; // a fake reference to satisfy -Wunused-function | ||
w2yehia marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| #ifdef _AIX | ||
| return is_local_filesystem(Fd); | ||
| #else | ||
| return 1; | ||
| #endif | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't using
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I couldn't find any evidence that it's broken, in general, on linux or other platforms. Note that in this case, we're using mmap to read a file, while maintaining exclusive access to it (opened with No one reported a problem in the past 5+ years, so I think we're good not doing anything on non-AIX platforms for now. |
||
| } | ||
|
|
||
| COMPILER_RT_VISIBILITY void lprofGetFileContentBuffer(FILE *F, uint64_t Length, | ||
| ManagedMemory *Buf) { | ||
| Buf->Status = MM_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 = MM_MMAP; | ||
| return; | ||
| } | ||
|
|
||
| if (getenv("LLVM_PROFILE_VERBOSE")) | ||
| PROF_NOTE("%s\n", "Could not use mmap; using fread instead."); | ||
w2yehia marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| 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; | ||
hubert-reinterpretcast marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // 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; | ||
hubert-reinterpretcast marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| // Reading was successful, record the result in the Buf parameter. | ||
| Buf->Addr = Buffer; | ||
| Buf->Status = MM_MALLOC; | ||
| } | ||
|
|
||
| void lprofReleaseBuffer(ManagedMemory *Buf, size_t Length) { | ||
w2yehia marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| switch (Buf->Status) { | ||
| case MM_MALLOC: | ||
| free(Buf->Addr); | ||
| break; | ||
| case MM_MMAP: | ||
| munmap(Buf->Addr, Length); | ||
w2yehia marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| break; | ||
| case MM_INVALID: | ||
w2yehia marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| PROF_ERR("%s: Buffer has invalid state: %d\n", __func__, Buf->Status); | ||
| break; | ||
| } | ||
| Buf->Addr = NULL; | ||
| Buf->Status = MM_INVALID; | ||
| } | ||
hubert-reinterpretcast marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| COMPILER_RT_VISIBILITY const char *lprofGetPathPrefix(int *PrefixStrip, | ||
| size_t *PrefixLen) { | ||
| const char *Prefix = getenv("GCOV_PREFIX"); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // 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, the second time a merge will occur which will trigger an mmap. | ||
w2yehia marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // RUN: ./a.out | ||
| // RUN: llvm-profdata show default_*.profraw --all-functions --counts --memop-sizes 2>&1 | FileCheck %s -check-prefix=PROFDATA | ||
| // RUN: env LLVM_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]; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.