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>

llvm-svn: 208940
This commit is contained in:
Duncan P. N. Exon Smith 2014-05-16 01:30:24 +00:00
parent 9121220804
commit 084398857a
14 changed files with 162 additions and 13 deletions

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -0,0 +1,7 @@
#include "instrprof-dynamic-header.h"
void a() {
if (true) {
bar<void>();
bar<char>();
}
}

View File

@ -0,0 +1,7 @@
#include "instrprof-dynamic-header.h"
void b() {
if (true) {
bar<void>();
bar<int>();
}
}

View File

@ -0,0 +1,5 @@
template <class T> void bar() {
if (true) {}
}
void a();
void b();

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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]