diff --git a/compiler-rt/lib/profile/CMakeLists.txt b/compiler-rt/lib/profile/CMakeLists.txt index 14815874f19e..20675372b237 100644 --- a/compiler-rt/lib/profile/CMakeLists.txt +++ b/compiler-rt/lib/profile/CMakeLists.txt @@ -1,6 +1,7 @@ set(PROFILE_SOURCES GCDAProfiling.c - PGOProfiling.c) + InstrProfiling.c + InstrProfilingExtras.c) filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386 arm) diff --git a/compiler-rt/lib/profile/InstrProfiling.c b/compiler-rt/lib/profile/InstrProfiling.c new file mode 100644 index 000000000000..4c9bb7e2b8f4 --- /dev/null +++ b/compiler-rt/lib/profile/InstrProfiling.c @@ -0,0 +1,70 @@ +/*===- InstrProfiling.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 "InstrProfiling.h" + +/* TODO: Calculate these with linker magic. */ +static __llvm_pgo_data *First = NULL; +static __llvm_pgo_data *Final = NULL; + +/*! + * \brief Register an instrumented function. + * + * Calls to this are emitted by clang with -fprofile-instr-generate. Such + * calls are only required (and only emitted) on targets where we haven't + * implemented linker magic to find the bounds of the section. + * + * For now, that's all targets. + */ +void __llvm_pgo_register_function(void *Data_) { + /* TODO: Only emit this function if we can't use linker magic. */ + __llvm_pgo_data *Data = (__llvm_pgo_data*)Data_; + if (!First || Data < First) + First = Data; + if (!Final || Data > Final) + Final = Data; +} + +/*! \brief Get the first instrumentation record. */ +static __llvm_pgo_data *getFirst() { + /* TODO: Use extern + linker magic instead of a static variable. */ + return First; +} + +/*! \brief Get the last instrumentation record. */ +static __llvm_pgo_data *getLast() { + /* TODO: Use extern + linker magic instead of a static variable. */ + return Final + 1; +} + +/* TODO: void __llvm_pgo_get_size_for_buffer(void); */ + +static void writeFunction(FILE *OutputFile, const __llvm_pgo_data *Data) { + /* TODO: Requires libc: break requirement by writing directly to a buffer + * instead of a FILE stream. + */ + uint32_t I; + for (I = 0; I < Data->NameSize; ++I) + fputc(Data->Name[I], OutputFile); + fprintf(OutputFile, "\n%" PRIu64 "\n%u\n", Data->FuncHash, Data->NumCounters); + for (I = 0; I < Data->NumCounters; ++I) + fprintf(OutputFile, "%" PRIu64 "\n", Data->Counters[I]); + fprintf(OutputFile, "\n"); +} + +void __llvm_pgo_write_buffer(FILE *OutputFile) { + /* TODO: Requires libc: break requirement by taking a char* buffer instead of + * a FILE stream. + */ + __llvm_pgo_data *I, *E; + + for (I = getFirst(), E = getLast(); I != E; ++I) + writeFunction(OutputFile, I); +} + diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h new file mode 100644 index 000000000000..8aaab016a165 --- /dev/null +++ b/compiler-rt/lib/profile/InstrProfiling.h @@ -0,0 +1,52 @@ +/*===- InstrProfiling.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. +|* +\*===----------------------------------------------------------------------===*/ + +#include +#include + +#define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__)) + +#if !I386_FREEBSD +#include +#endif + +#if !defined(_MSC_VER) && !I386_FREEBSD +#include +#endif + +#if defined(_MSC_VER) +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +#elif I386_FREEBSD +/* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to + * FreeBSD 10, r232261) when compiled in 32-bit mode. + */ +#define PRIu64 "llu" +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +#endif + +typedef struct __llvm_pgo_data { + const uint32_t NameSize; + const uint32_t NumCounters; + const uint64_t FuncHash; + const char *const Name; + const uint64_t *const Counters; +} __llvm_pgo_data; + +/* TODO: void __llvm_pgo_get_size_for_buffer(void); */ + +/*! + * \brief Write instrumentation data to the given buffer. + * + * This function is currently broken: it shouldn't rely on libc, but it does. + * It should be changed to take a char* buffer, and write binary data directly + * to it. + */ +void __llvm_pgo_write_buffer(FILE *OutputFile); diff --git a/compiler-rt/lib/profile/InstrProfilingExtras.c b/compiler-rt/lib/profile/InstrProfilingExtras.c new file mode 100644 index 000000000000..03399a3477f4 --- /dev/null +++ b/compiler-rt/lib/profile/InstrProfilingExtras.c @@ -0,0 +1,49 @@ +/*===- InstrProfilingExtras.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 "InstrProfiling.h" + +/*! \brief Write instrumentation data to the given file. */ +void __llvm_pgo_write_file(const char *OutputName) { + /* TODO: Requires libc: move to separate translation unit. */ + FILE *OutputFile; + if (!OutputName || !OutputName[0]) + return; + OutputFile = fopen(OutputName, "w"); + if (!OutputFile) return; + + /* TODO: mmap file to buffer of size __llvm_pgo_get_size_for_buffer() and + * pass the buffer in, instead of the file. + */ + __llvm_pgo_write_buffer(OutputFile); + + fclose(OutputFile); +} + +/*! \brief Write instrumentation data to the default file. */ +void __llvm_pgo_write_default_file() { + /* TODO: Requires libc: move to separate translation unit. */ + const char *OutputName = getenv("LLVM_PROFILE_FILE"); + if (OutputName == NULL || OutputName[0] == '\0') + OutputName = "default.profdata"; + __llvm_pgo_write_file(OutputName); +} + +/*! + * \brief Register to write instrumentation data to the default file at exit. + */ +void __llvm_pgo_register_write_atexit() { + /* TODO: Requires libc: move to separate translation unit. */ + static int HasBeenRegistered = 0; + + if (!HasBeenRegistered) { + HasBeenRegistered = 1; + atexit(__llvm_pgo_write_default_file); + } +} diff --git a/compiler-rt/lib/profile/PGOProfiling.c b/compiler-rt/lib/profile/PGOProfiling.c deleted file mode 100644 index e40eb87fc36e..000000000000 --- a/compiler-rt/lib/profile/PGOProfiling.c +++ /dev/null @@ -1,131 +0,0 @@ -/*===- PGOProfiling.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 -#include - -#define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__)) - -#if !I386_FREEBSD -#include -#endif - -#if !defined(_MSC_VER) && !I386_FREEBSD -#include -#endif - -#if defined(_MSC_VER) -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; -#elif I386_FREEBSD -/* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to - * FreeBSD 10, r232261) when compiled in 32-bit mode. - */ -#define PRIu64 "llu" -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; -#endif - -typedef struct __llvm_pgo_data { - const uint32_t NameSize; - const uint32_t NumCounters; - const uint64_t FuncHash; - const char *const Name; - const uint64_t *const Counters; -} __llvm_pgo_data; - -/* TODO: Calculate these with linker magic. */ -static __llvm_pgo_data *First = NULL; -static __llvm_pgo_data *Final = NULL; -/*! - * \brief Register an instrumented function. - * - * Calls to this are emitted by clang with -fprofile-instr-generate. Such - * calls are only required (and only emitted) on targets where we haven't - * implemented linker magic to find the bounds of the section. - * - * For now, that's all targets. - */ -void __llvm_pgo_register_function(void *Data_) { - /* TODO: Only emit this function if we can't use linker magic. */ - __llvm_pgo_data *Data = (__llvm_pgo_data*)Data_; - if (!First || Data < First) - First = Data; - if (!Final || Data > Final) - Final = Data; -} - -/*! \brief Get the first instrumentation record. */ -static __llvm_pgo_data *getFirst() { - /* TODO: Use extern + linker magic instead of a static variable. */ - return First; -} - -/*! \brief Get the last instrumentation record. */ -static __llvm_pgo_data *getLast() { - /* TODO: Use extern + linker magic instead of a static variable. */ - return Final + 1; -} - -/* TODO: void __llvm_pgo_get_size_for_buffer(void); */ -/* TODO: void __llvm_pgo_write_buffer(char *Buffer); */ - -static void writeFunction(FILE *OutputFile, const __llvm_pgo_data *Data) { - /* TODO: Requires libc: break requirement by writing directly to a buffer - * instead of a FILE stream. - */ - uint32_t I; - for (I = 0; I < Data->NameSize; ++I) - fputc(Data->Name[I], OutputFile); - fprintf(OutputFile, "\n%" PRIu64 "\n%u\n", Data->FuncHash, Data->NumCounters); - for (I = 0; I < Data->NumCounters; ++I) - fprintf(OutputFile, "%" PRIu64 "\n", Data->Counters[I]); - fprintf(OutputFile, "\n"); -} - -/*! \brief Write instrumentation data to the given file. */ -void __llvm_pgo_write_file(const char *OutputName) { - /* TODO: Requires libc: move to separate translation unit. */ - __llvm_pgo_data *I, *E; - FILE *OutputFile; - if (!OutputName || !OutputName[0]) - return; - OutputFile = fopen(OutputName, "w"); - if (!OutputFile) return; - - /* TODO: mmap file to buffer of size __llvm_pgo_get_size_for_buffer() and - * call __llvm_pgo_write_buffer(). - */ - for (I = getFirst(), E = getLast(); I != E; ++I) - writeFunction(OutputFile, I); - - fclose(OutputFile); -} - -/*! \brief Write instrumentation data to the default file. */ -void __llvm_pgo_write_default_file() { - /* TODO: Requires libc: move to separate translation unit. */ - const char *OutputName = getenv("LLVM_PROFILE_FILE"); - if (OutputName == NULL || OutputName[0] == '\0') - OutputName = "default.profdata"; - __llvm_pgo_write_file(OutputName); -} - -/*! - * \brief Register to write instrumentation data to the default file at exit. - */ -void __llvm_pgo_register_write_atexit() { - /* TODO: Requires libc: move to separate translation unit. */ - static int HasBeenRegistered = 0; - - if (!HasBeenRegistered) { - HasBeenRegistered = 1; - atexit(__llvm_pgo_write_default_file); - } -}