summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXinliang David Li <davidxl@google.com>2016-06-06 03:17:58 +0000
committerXinliang David Li <davidxl@google.com>2016-06-06 03:17:58 +0000
commit0bdc52140c2a233fbbc227ad078bfc837246414f (patch)
tree824d273f8dfe7baa0da4d553e0b0c5949823401d
parentc30637134ec5d2286d80950d727db06049318e47 (diff)
[profile] in-process mergeing support (part-2)
(Part-1 merging API is in profile runtime) This patch implements a portable file opening API with exclusive access for the process. In-process profile merge requires profile file update to be atomic/fully sychronized. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@271864 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/profile/CMakeLists.txt22
-rw-r--r--lib/profile/InstrProfilingUtil.c55
-rw-r--r--lib/profile/InstrProfilingUtil.h5
-rw-r--r--test/profile/Inputs/instrprof-file_ex.c59
-rw-r--r--test/profile/Linux/instrprof-file_ex.test16
5 files changed, 156 insertions, 1 deletions
diff --git a/lib/profile/CMakeLists.txt b/lib/profile/CMakeLists.txt
index 0905ff3e6..5bcdca129 100644
--- a/lib/profile/CMakeLists.txt
+++ b/lib/profile/CMakeLists.txt
@@ -22,6 +22,22 @@ int main() {
}
" COMPILER_RT_TARGET_HAS_ATOMICS)
+CHECK_CXX_SOURCE_COMPILES("
+#if defined(__linux__)
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+int fd;
+int main() {
+ struct flock s_flock;
+
+ s_flock.l_type = F_WRLCK;
+ fcntl(fd, F_SETLKW, &s_flock);
+ return 0;
+}
+
+" COMPILER_RT_TARGET_HAS_FCNTL_LCK)
+
add_custom_target(profile)
set(PROFILE_SOURCES
@@ -55,6 +71,12 @@ if(COMPILER_RT_TARGET_HAS_ATOMICS)
-DCOMPILER_RT_HAS_ATOMICS=1)
endif()
+if(COMPILER_RT_TARGET_HAS_FCNTL_LCK)
+ set(EXTRA_FLAGS
+ ${EXTRA_FLAGS}
+ -DCOMPILER_RT_HAS_FCNTL_LCK=1)
+endif()
+
if(APPLE)
add_compiler_rt_runtime(clang_rt.profile
STATIC
diff --git a/lib/profile/InstrProfilingUtil.c b/lib/profile/InstrProfilingUtil.c
index eb79d4222..24e302d4a 100644
--- a/lib/profile/InstrProfilingUtil.c
+++ b/lib/profile/InstrProfilingUtil.c
@@ -12,9 +12,15 @@
#ifdef _WIN32
#include <direct.h>
+#include <windows.h>
#else
#include <sys/stat.h>
#include <sys/types.h>
+#if defined(__linux__)
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
#endif
#ifdef COMPILER_RT_HAS_UNAME
@@ -35,7 +41,7 @@ void __llvm_profile_recursive_mkdir(char *path) {
#ifdef _WIN32
_mkdir(path);
#else
- mkdir(path, 0755); /* Some of these will fail, ignore it. */
+ mkdir(path, 0755); /* Some of these will fail, ignore it. */
#endif
path[i] = save;
}
@@ -70,4 +76,51 @@ int lprofGetHostName(char *Name, int Len) {
}
#endif
+FILE *lprofOpenFileEx(const char *ProfileName) {
+ FILE *f;
+ int fd;
+#ifdef COMPILER_RT_HAS_FCNTL_LCK
+ struct flock s_flock;
+
+ s_flock.l_whence = SEEK_SET;
+ s_flock.l_start = 0;
+ s_flock.l_len = 0; /* Until EOF. */
+ s_flock.l_pid = getpid();
+
+ s_flock.l_type = F_WRLCK;
+ fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
+ if (fd < 0)
+ return 0;
+
+ while (fcntl(fd, F_SETLKW, &s_flock) && errno == EINTR)
+ continue;
+
+ f = fdopen(fd, "r+b");
+#elif defined(_WIN32)
+ HANDLE h = CreateFile(ProfileName, GENERIC_READ | GENERIC_WRITE, 0, 0,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+ if (h == INVALID_HANDLE_VALUE)
+ return 0;
+
+ fd = _open_osfhandle((intptr_t)h, 0);
+ if (fd == -1) {
+ CloseHandle(h);
+ return 0;
+ }
+
+ f = _fdopen(fd, "r+b");
+ if (f == 0) {
+ CloseHandle(h);
+ return 0;
+ }
+#else
+ /* Worst case no locking applied. */
+ PROF_WARN("Concurrent file access is not supported : %s\n", "lack file locking");
+ fd = open(ProfileName, O_RDWR | O_CREAT, 0666);
+ if (fd < 0)
+ return 0;
+ f = fdopen(fd, "r+b");
+#endif
+ return f;
+}
diff --git a/lib/profile/InstrProfilingUtil.h b/lib/profile/InstrProfilingUtil.h
index b2bdd6519..16d3fbf42 100644
--- a/lib/profile/InstrProfilingUtil.h
+++ b/lib/profile/InstrProfilingUtil.h
@@ -11,10 +11,15 @@
#define PROFILE_INSTRPROFILINGUTIL_H
#include <stddef.h>
+#include <stdio.h>
/*! \brief Create a directory tree. */
void __llvm_profile_recursive_mkdir(char *Pathname);
+/*! Open file \c Filename for read+write with write
+ * lock for exclusive access. The caller will block
+ * if the lock is already held by another process. */
+FILE *lprofOpenFileEx(const char *Filename);
/* PS4 doesn't have getenv. Define a shim. */
#if __ORBIS__
static inline char *getenv(const char *name) { return NULL; }
diff --git a/test/profile/Inputs/instrprof-file_ex.c b/test/profile/Inputs/instrprof-file_ex.c
new file mode 100644
index 000000000..22e7555a1
--- /dev/null
+++ b/test/profile/Inputs/instrprof-file_ex.c
@@ -0,0 +1,59 @@
+/* This is a test case where the parent process forks 10
+ * children which contend to write to the same file. With
+ * file locking support, the data from each child should not
+ * be lost.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+extern FILE *lprofOpenFileEx(const char *);
+int main(int argc, char *argv[]) {
+ pid_t tid;
+ FILE *F;
+ const char *FN;
+ int child[10];
+ int c;
+ int i;
+
+ if (argc < 2) {
+ fprintf(stderr, "Requires one argument \n");
+ exit(1);
+ }
+ FN = argv[1];
+ truncate(FN, 0);
+
+ for (i = 0; i < 10; i++) {
+ c = fork();
+ // in child:
+ if (c == 0) {
+ FILE *F = lprofOpenFileEx(FN);
+ if (!F) {
+ fprintf(stderr, "Can not open file %s from child\n", FN);
+ exit(1);
+ }
+ fseek(F, 0, SEEK_END);
+ fprintf(F, "Dump from Child %d\n", i + 11);
+ fclose(F);
+ exit(0);
+ } else {
+ child[i] = c;
+ }
+ }
+
+ // In parent
+ for (i = 0; i < 10; i++) {
+ int child_status;
+ if ((tid = waitpid(child[i], &child_status, 0) == -1))
+ break;
+ }
+ F = lprofOpenFileEx(FN);
+ if (!F) {
+ fprintf(stderr, "Can not open file %s from parent\n", FN);
+ exit(1);
+ }
+ fseek(F, 0, SEEK_END);
+ fprintf(F, "Dump from parent %d\n", i + 11);
+ return 0;
+}
diff --git a/test/profile/Linux/instrprof-file_ex.test b/test/profile/Linux/instrprof-file_ex.test
new file mode 100644
index 000000000..af79b7398
--- /dev/null
+++ b/test/profile/Linux/instrprof-file_ex.test
@@ -0,0 +1,16 @@
+RUN: mkdir -p %t.d
+RUN: %clang_profgen -fprofile-instr-generate %S/../Inputs/instrprof-file_ex.c -o %t
+RUN: %run %t %t.d/run.dump
+RUN: sort %t.d/run.dump | FileCheck %s
+
+CHECK: Dump from Child 11
+CHECK-NEXT: Dump from Child 12
+CHECK-NEXT: Dump from Child 13
+CHECK-NEXT: Dump from Child 14
+CHECK-NEXT: Dump from Child 15
+CHECK-NEXT: Dump from Child 16
+CHECK-NEXT: Dump from Child 17
+CHECK-NEXT: Dump from Child 18
+CHECK-NEXT: Dump from Child 19
+CHECK-NEXT: Dump from Child 20
+CHECK-NEXT: Dump from parent 21