summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>2014-05-16 01:30:24 +0000
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>2014-05-16 01:30:24 +0000
commitfda7696ffbc58e4485f46a1de85512ee7fb65128 (patch)
treefe3278eb3a7ddf7c31cf82dad734a6a61aec1f80
parent3a7550a78bd8f4c9e1eea7002e7ade6deb276d4c (diff)
InstrProf: Fix shared object profiling
Change the API of the instrumented profiling library to work with shared objects. - Most things are now declared hidden, so that each executable gets its own copy. - Initialization hooks up a linked list of writers. - The raw format with shared objects that are profiled consists of a concatenated series of profiles. llvm-profdata knows how to deal with that since r208938. <rdar://problem/16918688> git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@208940 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/profile/InstrProfiling.c3
-rw-r--r--lib/profile/InstrProfiling.h3
-rw-r--r--lib/profile/InstrProfilingBuffer.c11
-rw-r--r--lib/profile/InstrProfilingFile.c50
-rw-r--r--lib/profile/InstrProfilingPlatformDarwin.c12
-rw-r--r--lib/profile/InstrProfilingPlatformOther.c7
-rw-r--r--lib/profile/InstrProfilingRuntime.cc11
-rw-r--r--test/profile/Inputs/instrprof-dynamic-a.cpp7
-rw-r--r--test/profile/Inputs/instrprof-dynamic-b.cpp7
-rw-r--r--test/profile/Inputs/instrprof-dynamic-header.h5
-rw-r--r--test/profile/Inputs/instrprof-dynamic-main.cpp9
-rw-r--r--test/profile/instrprof-dynamic-one-shared.test23
-rw-r--r--test/profile/instrprof-dynamic-two-shared.test24
-rw-r--r--test/profile/lit.cfg3
14 files changed, 162 insertions, 13 deletions
diff --git a/lib/profile/InstrProfiling.c b/lib/profile/InstrProfiling.c
index 123dd0d3b..aeb3681aa 100644
--- a/lib/profile/InstrProfiling.c
+++ b/lib/profile/InstrProfiling.c
@@ -10,6 +10,7 @@
#include "InstrProfiling.h"
#include <string.h>
+__attribute__((visibility("hidden")))
uint64_t __llvm_profile_get_magic(void) {
/* Magic number to detect file format and endianness.
*
@@ -32,11 +33,13 @@ uint64_t __llvm_profile_get_magic(void) {
(uint64_t)129;
}
+__attribute__((visibility("hidden")))
uint64_t __llvm_profile_get_version(void) {
/* This should be bumped any time the output format changes. */
return 1;
}
+__attribute__((visibility("hidden")))
void __llvm_profile_reset_counters(void) {
uint64_t *I = __llvm_profile_counters_begin();
uint64_t *E = __llvm_profile_counters_end();
diff --git a/lib/profile/InstrProfiling.h b/lib/profile/InstrProfiling.h
index 5aba69e12..57ebf3c3a 100644
--- a/lib/profile/InstrProfiling.h
+++ b/lib/profile/InstrProfiling.h
@@ -83,6 +83,9 @@ void __llvm_profile_set_filename(const char *Name);
/*! \brief Register to write instrumentation data to file at exit. */
int __llvm_profile_register_write_file_atexit(void);
+/*! \brief Register the write file function for this executable. */
+void __llvm_profile_register_write_file(void);
+
/*! \brief Get the magic token for the file format. */
uint64_t __llvm_profile_get_magic(void);
diff --git a/lib/profile/InstrProfilingBuffer.c b/lib/profile/InstrProfilingBuffer.c
index 8c6d43e7b..b53d4f795 100644
--- a/lib/profile/InstrProfilingBuffer.c
+++ b/lib/profile/InstrProfilingBuffer.c
@@ -10,14 +10,18 @@
#include "InstrProfiling.h"
#include <string.h>
+__attribute__((visibility("hidden")))
uint64_t __llvm_profile_get_size_for_buffer(void) {
/* Match logic in __llvm_profile_write_buffer(). */
+ const uint64_t NamesSize = PROFILE_RANGE_SIZE(names) * sizeof(char);
+ const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
return sizeof(uint64_t) * PROFILE_HEADER_SIZE +
PROFILE_RANGE_SIZE(data) * sizeof(__llvm_profile_data) +
PROFILE_RANGE_SIZE(counters) * sizeof(uint64_t) +
- PROFILE_RANGE_SIZE(names) * sizeof(char);
+ NamesSize + Padding;
}
+__attribute__((visibility("hidden")))
int __llvm_profile_write_buffer(char *Buffer) {
/* Match logic in __llvm_profile_get_size_for_buffer().
* Match logic in __llvm_profile_write_file().
@@ -33,6 +37,10 @@ int __llvm_profile_write_buffer(char *Buffer) {
const uint64_t DataSize = DataEnd - DataBegin;
const uint64_t CountersSize = CountersEnd - CountersBegin;
const uint64_t NamesSize = NamesEnd - NamesBegin;
+ const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
+
+ /* Enough zeroes for padding. */
+ const char Zeroes[sizeof(uint64_t)] = {0};
/* Create the header. */
uint64_t Header[PROFILE_HEADER_SIZE];
@@ -54,6 +62,7 @@ int __llvm_profile_write_buffer(char *Buffer) {
UPDATE_memcpy(DataBegin, DataSize * sizeof(__llvm_profile_data));
UPDATE_memcpy(CountersBegin, CountersSize * sizeof(uint64_t));
UPDATE_memcpy(NamesBegin, NamesSize * sizeof(char));
+ UPDATE_memcpy(Zeroes, Padding * sizeof(char));
#undef UPDATE_memcpy
return 0;
diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c
index 2c40ca5af..5ed32d562 100644
--- a/lib/profile/InstrProfilingFile.c
+++ b/lib/profile/InstrProfilingFile.c
@@ -25,6 +25,10 @@ static int writeFile(FILE *File) {
const uint64_t DataSize = DataEnd - DataBegin;
const uint64_t CountersSize = CountersEnd - CountersBegin;
const uint64_t NamesSize = NamesEnd - NamesBegin;
+ const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
+
+ /* Enough zeroes for padding. */
+ const char Zeroes[sizeof(uint64_t)] = {0};
/* Create the header. */
uint64_t Header[PROFILE_HEADER_SIZE];
@@ -43,9 +47,30 @@ static int writeFile(FILE *File) {
CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File);
CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File);
+ CHECK_fwrite(Zeroes, sizeof(char), Padding, File);
#undef CHECK_fwrite
- return 0;
+ return 0;
+}
+
+typedef struct __llvm_profile_writer {
+ struct __llvm_profile_writer *Next;
+ int (*Data)(FILE *);
+} __llvm_profile_writer;
+
+__attribute__((weak)) __llvm_profile_writer *__llvm_profile_HeadWriter = NULL;
+static __llvm_profile_writer Writer = {NULL, writeFile};
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_register_write_file(void) {
+ static int HasBeenRegistered = 0;
+
+ if (HasBeenRegistered)
+ return;
+
+ HasBeenRegistered = 1;
+ Writer.Next = __llvm_profile_HeadWriter;
+ __llvm_profile_HeadWriter = &Writer;
}
static int writeFileWithName(const char *OutputName) {
@@ -57,19 +82,28 @@ static int writeFileWithName(const char *OutputName) {
if (!OutputFile)
return -1;
- RetVal = writeFile(OutputFile);
+ __llvm_profile_writer *Writer = __llvm_profile_HeadWriter;
+ if (Writer)
+ for (; Writer; Writer = Writer->Next) {
+ RetVal = Writer->Data(OutputFile);
+ if (RetVal != 0)
+ break;
+ }
+ else
+ // Default to calling this executable's writeFile.
+ RetVal = writeFile(OutputFile);
fclose(OutputFile);
return RetVal;
}
-static const char *CurrentFilename = NULL;
-void __llvm_profile_set_filename(const char *Filename) {
- CurrentFilename = Filename;
+__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
+__attribute__((weak)) void __llvm_profile_set_filename(const char *Filename) {
+ __llvm_profile_CurrentFilename = Filename;
}
int getpid(void);
-int __llvm_profile_write_file(void) {
+__attribute__((weak)) int __llvm_profile_write_file(void) {
char *AllocatedFilename = NULL;
int I, J;
int RetVal;
@@ -80,7 +114,7 @@ int __llvm_profile_write_file(void) {
int NumPids = 0;
/* Get the filename. */
- const char *Filename = CurrentFilename;
+ const char *Filename = __llvm_profile_CurrentFilename;
#define UPDATE_FILENAME(NextFilename) \
if (!Filename || !Filename[0]) Filename = NextFilename
UPDATE_FILENAME(getenv("LLVM_PROFILE_FILE"));
@@ -131,7 +165,7 @@ static void writeFileWithoutReturn(void) {
__llvm_profile_write_file();
}
-int __llvm_profile_register_write_file_atexit(void) {
+__attribute__((weak)) int __llvm_profile_register_write_file_atexit(void) {
static int HasBeenRegistered = 0;
if (HasBeenRegistered)
diff --git a/lib/profile/InstrProfilingPlatformDarwin.c b/lib/profile/InstrProfilingPlatformDarwin.c
index 6e34db612..74019772d 100644
--- a/lib/profile/InstrProfilingPlatformDarwin.c
+++ b/lib/profile/InstrProfilingPlatformDarwin.c
@@ -11,21 +11,33 @@
#if defined(__APPLE__)
/* Use linker magic to find the bounds of the Data section. */
+__attribute__((visibility("hidden")))
extern __llvm_profile_data DataStart __asm("section$start$__DATA$__llvm_prf_data");
+__attribute__((visibility("hidden")))
extern __llvm_profile_data DataEnd __asm("section$end$__DATA$__llvm_prf_data");
+__attribute__((visibility("hidden")))
extern char NamesStart __asm("section$start$__DATA$__llvm_prf_names");
+__attribute__((visibility("hidden")))
extern char NamesEnd __asm("section$end$__DATA$__llvm_prf_names");
+__attribute__((visibility("hidden")))
extern uint64_t CountersStart __asm("section$start$__DATA$__llvm_prf_cnts");
+__attribute__((visibility("hidden")))
extern uint64_t CountersEnd __asm("section$end$__DATA$__llvm_prf_cnts");
+__attribute__((visibility("hidden")))
const __llvm_profile_data *__llvm_profile_data_begin(void) {
return &DataStart;
}
+__attribute__((visibility("hidden")))
const __llvm_profile_data *__llvm_profile_data_end(void) {
return &DataEnd;
}
+__attribute__((visibility("hidden")))
const char *__llvm_profile_names_begin(void) { return &NamesStart; }
+__attribute__((visibility("hidden")))
const char *__llvm_profile_names_end(void) { return &NamesEnd; }
+__attribute__((visibility("hidden")))
uint64_t *__llvm_profile_counters_begin(void) { return &CountersStart; }
+__attribute__((visibility("hidden")))
uint64_t *__llvm_profile_counters_end(void) { return &CountersEnd; }
#endif
diff --git a/lib/profile/InstrProfilingPlatformOther.c b/lib/profile/InstrProfilingPlatformOther.c
index 407ca0a7e..404c1a851 100644
--- a/lib/profile/InstrProfilingPlatformOther.c
+++ b/lib/profile/InstrProfilingPlatformOther.c
@@ -26,6 +26,7 @@ static uint64_t *CountersLast = NULL;
* calls are only required (and only emitted) on targets where we haven't
* implemented linker magic to find the bounds of the sections.
*/
+__attribute__((visibility("hidden")))
void __llvm_profile_register_function(void *Data_) {
/* TODO: Only emit this function if we can't use linker magic. */
const __llvm_profile_data *Data = (__llvm_profile_data*)Data_;
@@ -54,14 +55,20 @@ void __llvm_profile_register_function(void *Data_) {
#undef UPDATE_LAST
}
+__attribute__((visibility("hidden")))
const __llvm_profile_data *__llvm_profile_data_begin(void) {
return DataFirst;
}
+__attribute__((visibility("hidden")))
const __llvm_profile_data *__llvm_profile_data_end(void) {
return DataLast;
}
+__attribute__((visibility("hidden")))
const char *__llvm_profile_names_begin(void) { return NamesFirst; }
+__attribute__((visibility("hidden")))
const char *__llvm_profile_names_end(void) { return NamesLast; }
+__attribute__((visibility("hidden")))
uint64_t *__llvm_profile_counters_begin(void) { return CountersFirst; }
+__attribute__((visibility("hidden")))
uint64_t *__llvm_profile_counters_end(void) { return CountersLast; }
#endif
diff --git a/lib/profile/InstrProfilingRuntime.cc b/lib/profile/InstrProfilingRuntime.cc
index 79018177e..280de834b 100644
--- a/lib/profile/InstrProfilingRuntime.cc
+++ b/lib/profile/InstrProfilingRuntime.cc
@@ -11,17 +11,20 @@ extern "C" {
#include "InstrProfiling.h"
-int __llvm_profile_runtime;
+__attribute__((visibility("hidden"))) int __llvm_profile_runtime;
}
namespace {
-class RegisterAtExit {
+class RegisterRuntime {
public:
- RegisterAtExit() { __llvm_profile_register_write_file_atexit(); }
+ RegisterRuntime() {
+ __llvm_profile_register_write_file_atexit();
+ __llvm_profile_register_write_file();
+ }
};
-RegisterAtExit Registration;
+RegisterRuntime Registration;
}
diff --git a/test/profile/Inputs/instrprof-dynamic-a.cpp b/test/profile/Inputs/instrprof-dynamic-a.cpp
new file mode 100644
index 000000000..67de263c4
--- /dev/null
+++ b/test/profile/Inputs/instrprof-dynamic-a.cpp
@@ -0,0 +1,7 @@
+#include "instrprof-dynamic-header.h"
+void a() {
+ if (true) {
+ bar<void>();
+ bar<char>();
+ }
+}
diff --git a/test/profile/Inputs/instrprof-dynamic-b.cpp b/test/profile/Inputs/instrprof-dynamic-b.cpp
new file mode 100644
index 000000000..c8fb75ef5
--- /dev/null
+++ b/test/profile/Inputs/instrprof-dynamic-b.cpp
@@ -0,0 +1,7 @@
+#include "instrprof-dynamic-header.h"
+void b() {
+ if (true) {
+ bar<void>();
+ bar<int>();
+ }
+}
diff --git a/test/profile/Inputs/instrprof-dynamic-header.h b/test/profile/Inputs/instrprof-dynamic-header.h
new file mode 100644
index 000000000..1dc2e37ef
--- /dev/null
+++ b/test/profile/Inputs/instrprof-dynamic-header.h
@@ -0,0 +1,5 @@
+template <class T> void bar() {
+ if (true) {}
+}
+void a();
+void b();
diff --git a/test/profile/Inputs/instrprof-dynamic-main.cpp b/test/profile/Inputs/instrprof-dynamic-main.cpp
new file mode 100644
index 000000000..0dd602139
--- /dev/null
+++ b/test/profile/Inputs/instrprof-dynamic-main.cpp
@@ -0,0 +1,9 @@
+#include "instrprof-dynamic-header.h"
+void foo(int K) { if (K) {} }
+int main(int argc, char *argv[]) {
+ foo(5);
+ bar<void>();
+ a();
+ b();
+ return 0;
+}
diff --git a/test/profile/instrprof-dynamic-one-shared.test b/test/profile/instrprof-dynamic-one-shared.test
new file mode 100644
index 000000000..38be4fe8b
--- /dev/null
+++ b/test/profile/instrprof-dynamic-one-shared.test
@@ -0,0 +1,23 @@
+RUN: mkdir -p %t.d
+RUN: %clang_profgen -o %t.d/a.shared -fPIC -shared %S/Inputs/instrprof-dynamic-a.cpp
+RUN: %clang_profgen -o %t-shared -fPIC -rpath %t.d %t.d/a.shared %S/Inputs/instrprof-dynamic-b.cpp %S/Inputs/instrprof-dynamic-main.cpp
+
+RUN: %clang_profgen -o %t-static %S/Inputs/instrprof-dynamic-a.cpp %S/Inputs/instrprof-dynamic-b.cpp %S/Inputs/instrprof-dynamic-main.cpp
+
+RUN: env LLVM_PROFILE_FILE=%t-static.profraw %run %t-static
+RUN: env LLVM_PROFILE_FILE=%t-shared.profraw %run %t-shared
+
+RUN: llvm-profdata merge -o %t-static.profdata %t-static.profraw
+RUN: llvm-profdata merge -o %t-shared.profdata %t-shared.profraw
+
+RUN: %clang_profuse=%t-static.profdata -o %t-a.static.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-a.cpp
+RUN: %clang_profuse=%t-shared.profdata -o %t-a.shared.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-a.cpp
+RUN: diff %t-a.static.ll %t-a.shared.ll
+
+RUN: %clang_profuse=%t-static.profdata -o %t-b.static.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-b.cpp
+RUN: %clang_profuse=%t-shared.profdata -o %t-b.shared.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-b.cpp
+RUN: diff %t-b.static.ll %t-b.shared.ll
+
+RUN: %clang_profuse=%t-static.profdata -o %t-main.static.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-main.cpp
+RUN: %clang_profuse=%t-shared.profdata -o %t-main.shared.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-main.cpp
+RUN: diff %t-main.static.ll %t-main.shared.ll
diff --git a/test/profile/instrprof-dynamic-two-shared.test b/test/profile/instrprof-dynamic-two-shared.test
new file mode 100644
index 000000000..830359dec
--- /dev/null
+++ b/test/profile/instrprof-dynamic-two-shared.test
@@ -0,0 +1,24 @@
+RUN: mkdir -p %t.d
+RUN: %clang_profgen -o %t.d/a.shared -fPIC -shared %S/Inputs/instrprof-dynamic-a.cpp
+RUN: %clang_profgen -o %t.d/b.shared -fPIC -shared %S/Inputs/instrprof-dynamic-b.cpp
+RUN: %clang_profgen -o %t-shared -fPIC -rpath %t.d %t.d/a.shared %t.d/b.shared %S/Inputs/instrprof-dynamic-main.cpp
+
+RUN: %clang_profgen -o %t-static %S/Inputs/instrprof-dynamic-a.cpp %S/Inputs/instrprof-dynamic-b.cpp %S/Inputs/instrprof-dynamic-main.cpp
+
+RUN: env LLVM_PROFILE_FILE=%t-static.profraw %run %t-static
+RUN: env LLVM_PROFILE_FILE=%t-shared.profraw %run %t-shared
+
+RUN: llvm-profdata merge -o %t-static.profdata %t-static.profraw
+RUN: llvm-profdata merge -o %t-shared.profdata %t-shared.profraw
+
+RUN: %clang_profuse=%t-static.profdata -o %t-a.static.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-a.cpp
+RUN: %clang_profuse=%t-shared.profdata -o %t-a.shared.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-a.cpp
+RUN: diff %t-a.static.ll %t-a.shared.ll
+
+RUN: %clang_profuse=%t-static.profdata -o %t-b.static.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-b.cpp
+RUN: %clang_profuse=%t-shared.profdata -o %t-b.shared.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-b.cpp
+RUN: diff %t-b.static.ll %t-b.shared.ll
+
+RUN: %clang_profuse=%t-static.profdata -o %t-main.static.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-main.cpp
+RUN: %clang_profuse=%t-shared.profdata -o %t-main.shared.ll -S -emit-llvm %S/Inputs/instrprof-dynamic-main.cpp
+RUN: diff %t-main.static.ll %t-main.shared.ll
diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg
index da09f1a61..e4d510c5f 100644
--- a/test/profile/lit.cfg
+++ b/test/profile/lit.cfg
@@ -27,6 +27,9 @@ if config.test_exec_root is None:
# Test suffixes.
config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm', '.ll', '.test']
+# What to exclude.
+config.excludes = ['Inputs']
+
# Clang flags.
clang_cflags = [config.target_cflags]