aboutsummaryrefslogtreecommitdiff
path: root/lib/profile
diff options
context:
space:
mode:
Diffstat (limited to 'lib/profile')
-rw-r--r--lib/profile/CMakeLists.txt5
-rw-r--r--lib/profile/GCDAProfiling.c35
-rw-r--r--lib/profile/InstrProfiling.h17
-rw-r--r--lib/profile/InstrProfilingFile.c95
-rw-r--r--lib/profile/InstrProfilingUtil.c35
-rw-r--r--lib/profile/InstrProfilingUtil.h16
6 files changed, 147 insertions, 56 deletions
diff --git a/lib/profile/CMakeLists.txt b/lib/profile/CMakeLists.txt
index 420d7660ee36..d03409fc45b7 100644
--- a/lib/profile/CMakeLists.txt
+++ b/lib/profile/CMakeLists.txt
@@ -7,11 +7,12 @@ set(PROFILE_SOURCES
InstrProfilingFile.c
InstrProfilingPlatformDarwin.c
InstrProfilingPlatformOther.c
- InstrProfilingRuntime.cc)
+ InstrProfilingRuntime.cc
+ InstrProfilingUtil.c)
if(APPLE)
add_compiler_rt_osx_static_runtime(clang_rt.profile_osx
- ARCH ${PROFILE_SUPPORTED_ARCH}
+ ARCHS ${PROFILE_SUPPORTED_ARCH}
SOURCES ${PROFILE_SOURCES})
add_dependencies(profile clang_rt.profile_osx)
else()
diff --git a/lib/profile/GCDAProfiling.c b/lib/profile/GCDAProfiling.c
index 45fbd07e544b..aec232856e74 100644
--- a/lib/profile/GCDAProfiling.c
+++ b/lib/profile/GCDAProfiling.c
@@ -20,23 +20,18 @@
|*
\*===----------------------------------------------------------------------===*/
+#include "InstrProfilingUtil.h"
+
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
-#ifdef _WIN32
-#include <direct.h>
-#endif
+#include <sys/file.h>
#define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__))
-#if !I386_FREEBSD
-#include <sys/stat.h>
-#include <sys/types.h>
-#endif
-
#if !defined(_MSC_VER) && !I386_FREEBSD
#include <stdint.h>
#endif
@@ -51,7 +46,6 @@ typedef unsigned long long uint64_t;
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;
-int mkdir(const char*, unsigned short);
#endif
/* #define DEBUG_GCDAPROFILING */
@@ -208,21 +202,6 @@ static char *mangle_filename(const char *orig_filename) {
return new_filename;
}
-static void recursive_mkdir(char *path) {
- int i;
-
- for (i = 1; path[i] != '\0'; ++i) {
- if (path[i] != '/') continue;
- path[i] = '\0';
-#ifdef _WIN32
- _mkdir(path);
-#else
- mkdir(path, 0755); /* Some of these will fail, ignore it. */
-#endif
- path[i] = '/';
- }
-}
-
static int map_file() {
fseek(output_file, 0L, SEEK_END);
file_size = ftell(output_file);
@@ -282,7 +261,7 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4],
fd = open(filename, O_RDWR | O_CREAT, 0644);
if (fd == -1) {
/* Try creating the directories first then opening the file. */
- recursive_mkdir(filename);
+ __llvm_profile_recursive_mkdir(filename);
fd = open(filename, O_RDWR | O_CREAT, 0644);
if (fd == -1) {
/* Bah! It's hopeless. */
@@ -294,6 +273,11 @@ void llvm_gcda_start_file(const char *orig_filename, const char version[4],
}
}
+ /* Try to flock the file to serialize concurrent processes writing out to the
+ * same GCDA. This can fail if the filesystem doesn't support it, but in that
+ * case we'll just carry on with the old racy behaviour and hope for the best.
+ */
+ flock(fd, LOCK_EX);
output_file = fdopen(fd, mode);
/* Initialize the write buffer. */
@@ -493,6 +477,7 @@ void llvm_gcda_end_file() {
}
fclose(output_file);
+ flock(fd, LOCK_UN);
output_file = NULL;
write_buffer = NULL;
}
diff --git a/lib/profile/InstrProfiling.h b/lib/profile/InstrProfiling.h
index 2b1bd003668e..3778a88893e6 100644
--- a/lib/profile/InstrProfiling.h
+++ b/lib/profile/InstrProfiling.h
@@ -62,7 +62,9 @@ uint64_t *__llvm_profile_end_counters(void);
*
* Writes to the file with the last name given to \a __llvm_profile_set_filename(),
* or if it hasn't been called, the \c LLVM_PROFILE_FILE environment variable,
- * or if that's not set, \c "default.profdata".
+ * or if that's not set, the last name given to
+ * \a __llvm_profile_override_default_filename(), or if that's not set,
+ * \c "default.profraw".
*/
int __llvm_profile_write_file(void);
@@ -77,6 +79,19 @@ int __llvm_profile_write_file(void);
*/
void __llvm_profile_set_filename(const char *Name);
+/*!
+ * \brief Set the filename for writing instrumentation data, unless the
+ * \c LLVM_PROFILE_FILE environment variable was set.
+ *
+ * Unless overridden, sets the filename to be used for subsequent calls to
+ * \a __llvm_profile_write_file().
+ *
+ * \c Name is not copied, so it must remain valid. Passing NULL resets the
+ * filename logic to the default behaviour (unless the \c LLVM_PROFILE_FILE
+ * was set in which case it has no effect).
+ */
+void __llvm_profile_override_default_filename(const char *Name);
+
/*! \brief Register to write instrumentation data to file at exit. */
int __llvm_profile_register_write_file_atexit(void);
diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c
index 346665fd5b3e..68e8c7b07871 100644
--- a/lib/profile/InstrProfilingFile.c
+++ b/lib/profile/InstrProfilingFile.c
@@ -8,10 +8,11 @@
\*===----------------------------------------------------------------------===*/
#include "InstrProfiling.h"
+#include "InstrProfilingUtil.h"
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/errno.h>
#define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
@@ -76,40 +77,61 @@ static int writeFileWithName(const char *OutputName) {
__attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
-static void setFilename(const char *Filename, int OwnsFilename) {
- if (__llvm_profile_OwnsFilename)
- free(UNCONST(__llvm_profile_CurrentFilename));
-
- __llvm_profile_CurrentFilename = Filename;
- __llvm_profile_OwnsFilename = OwnsFilename;
-}
-
static void truncateCurrentFile(void) {
- const char *Filename = __llvm_profile_CurrentFilename;
+ const char *Filename;
+ FILE *File;
+
+ Filename = __llvm_profile_CurrentFilename;
if (!Filename || !Filename[0])
return;
+ /* Create the directory holding the file, if needed. */
+ if (strchr(Filename, '/')) {
+ char *Copy = malloc(strlen(Filename) + 1);
+ strcpy(Copy, Filename);
+ __llvm_profile_recursive_mkdir(Copy);
+ free(Copy);
+ }
+
/* Truncate the file. Later we'll reopen and append. */
- FILE *File = fopen(Filename, "w");
+ File = fopen(Filename, "w");
if (!File)
return;
fclose(File);
}
-static void setDefaultFilename(void) { setFilename("default.profraw", 0); }
+static void setFilename(const char *Filename, int OwnsFilename) {
+ /* Check if this is a new filename and therefore needs truncation. */
+ int NewFile = !__llvm_profile_CurrentFilename ||
+ (Filename && strcmp(Filename, __llvm_profile_CurrentFilename));
+ if (__llvm_profile_OwnsFilename)
+ free(UNCONST(__llvm_profile_CurrentFilename));
-int getpid(void);
-static int setFilenameFromEnvironment(void) {
- const char *Filename = getenv("LLVM_PROFILE_FILE");
- if (!Filename || !Filename[0])
- return -1;
+ __llvm_profile_CurrentFilename = Filename;
+ __llvm_profile_OwnsFilename = OwnsFilename;
- /* Check the filename for "%p", which indicates a pid-substitution. */
+ /* If not a new file, append to support profiling multiple shared objects. */
+ if (NewFile)
+ truncateCurrentFile();
+}
+
+static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
+
+int getpid(void);
+static int setFilenamePossiblyWithPid(const char *Filename) {
#define MAX_PID_SIZE 16
char PidChars[MAX_PID_SIZE] = {0};
- int NumPids = 0;
- int PidLength = 0;
- int I;
+ int NumPids = 0, PidLength = 0;
+ char *Allocated;
+ int I, J;
+
+ /* Reset filename on NULL, except with env var which is checked by caller. */
+ if (!Filename) {
+ resetFilenameToDefault();
+ return 0;
+ }
+
+ /* Check the filename for "%p", which indicates a pid-substitution. */
for (I = 0; Filename[I]; ++I)
if (Filename[I] == '%' && Filename[++I] == 'p')
if (!NumPids++) {
@@ -123,12 +145,11 @@ static int setFilenameFromEnvironment(void) {
}
/* Allocate enough space for the substituted filename. */
- char *Allocated = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
+ Allocated = malloc(I + NumPids*(PidLength - 2) + 1);
if (!Allocated)
return -1;
/* Construct the new filename. */
- int J;
for (I = 0, J = 0; Filename[I]; ++I)
if (Filename[I] == '%') {
if (Filename[++I] == 'p') {
@@ -145,11 +166,20 @@ static int setFilenameFromEnvironment(void) {
return 0;
}
+static int setFilenameFromEnvironment(void) {
+ const char *Filename = getenv("LLVM_PROFILE_FILE");
+
+ if (!Filename || !Filename[0])
+ return -1;
+
+ return setFilenamePossiblyWithPid(Filename);
+}
+
static void setFilenameAutomatically(void) {
if (!setFilenameFromEnvironment())
return;
- setDefaultFilename();
+ resetFilenameToDefault();
}
__attribute__((visibility("hidden")))
@@ -160,23 +190,32 @@ void __llvm_profile_initialize_file(void) {
/* Detect the filename and truncate. */
setFilenameAutomatically();
- truncateCurrentFile();
}
__attribute__((visibility("hidden")))
void __llvm_profile_set_filename(const char *Filename) {
- setFilename(Filename, 0);
- truncateCurrentFile();
+ setFilenamePossiblyWithPid(Filename);
+}
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_override_default_filename(const char *Filename) {
+ /* If the env var is set, skip setting filename from argument. */
+ const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
+ if (Env_Filename && Env_Filename[0])
+ return;
+ setFilenamePossiblyWithPid(Filename);
}
__attribute__((visibility("hidden")))
int __llvm_profile_write_file(void) {
+ int rc;
+
/* Check the filename. */
if (!__llvm_profile_CurrentFilename)
return -1;
/* Write the file. */
- int rc = writeFileWithName(__llvm_profile_CurrentFilename);
+ rc = writeFileWithName(__llvm_profile_CurrentFilename);
if (rc && getenv("LLVM_PROFILE_VERBOSE_ERRORS"))
fprintf(stderr, "LLVM Profile: Failed to write file \"%s\": %s\n",
__llvm_profile_CurrentFilename, strerror(errno));
diff --git a/lib/profile/InstrProfilingUtil.c b/lib/profile/InstrProfilingUtil.c
new file mode 100644
index 000000000000..e146dfca83c8
--- /dev/null
+++ b/lib/profile/InstrProfilingUtil.c
@@ -0,0 +1,35 @@
+/*===- InstrProfilingUtil.c - Support library for PGO instrumentation -----===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#include "InstrProfilingUtil.h"
+
+#ifdef _WIN32
+#include <direct.h>
+#elif I386_FREEBSD
+int mkdir(const char*, unsigned short);
+#else
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_recursive_mkdir(char *path) {
+ int i;
+
+ for (i = 1; path[i] != '\0'; ++i) {
+ if (path[i] != '/') continue;
+ path[i] = '\0';
+#ifdef _WIN32
+ _mkdir(path);
+#else
+ mkdir(path, 0755); /* Some of these will fail, ignore it. */
+#endif
+ path[i] = '/';
+ }
+}
diff --git a/lib/profile/InstrProfilingUtil.h b/lib/profile/InstrProfilingUtil.h
new file mode 100644
index 000000000000..756b18e7c56d
--- /dev/null
+++ b/lib/profile/InstrProfilingUtil.h
@@ -0,0 +1,16 @@
+/*===- InstrProfilingUtil.h - Support library for PGO instrumentation -----===*\
+|*
+|* The LLVM Compiler Infrastructure
+|*
+|* This file is distributed under the University of Illinois Open Source
+|* License. See LICENSE.TXT for details.
+|*
+\*===----------------------------------------------------------------------===*/
+
+#ifndef PROFILE_INSTRPROFILINGUTIL_H
+#define PROFILE_INSTRPROFILINGUTIL_H
+
+/*! \brief Create a directory tree. */
+void __llvm_profile_recursive_mkdir(char *Pathname);
+
+#endif /* PROFILE_INSTRPROFILINGUTIL_H */