diff options
author | Duncan P. N. Exon Smith <dexonsmith@apple.com> | 2014-03-17 23:44:56 +0000 |
---|---|---|
committer | Duncan P. N. Exon Smith <dexonsmith@apple.com> | 2014-03-17 23:44:56 +0000 |
commit | 7f69d8a878e4640c4e0f8b690e2790e9f2db68ac (patch) | |
tree | c60f4e86523e7cac8605178b9f982cead5ad3ccd | |
parent | ede3c3836ba6803968a00fd966d2af11bb4e2cfc (diff) |
Reapply "PGO: Statically generate data structures"
Reapply r204079 and r204083, this time with stubs for fputc in
compiler-rt.
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@204091 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | SDKs/darwin/usr/include/stdio.h | 1 | ||||
-rw-r--r-- | SDKs/linux/usr/include/stdio.h | 1 | ||||
-rw-r--r-- | lib/profile/PGOProfiling.c | 127 |
3 files changed, 81 insertions, 48 deletions
diff --git a/SDKs/darwin/usr/include/stdio.h b/SDKs/darwin/usr/include/stdio.h index 006652fb9..ab5f1a3b2 100644 --- a/SDKs/darwin/usr/include/stdio.h +++ b/SDKs/darwin/usr/include/stdio.h @@ -75,6 +75,7 @@ int fflush(FILE *); FILE *fopen(const char * __restrict, const char * __restrict) __asm(__FOPEN_NAME); FILE *fdopen(int, const char *) __asm(__FDOPEN_NAME); int fprintf(FILE * __restrict, const char * __restrict, ...); +int fputc(int, FILE *); size_t fwrite(const void * __restrict, size_t, size_t, FILE * __restrict) __asm(__FWRITE_NAME); size_t fread(void * __restrict, size_t, size_t, FILE * __restrict); diff --git a/SDKs/linux/usr/include/stdio.h b/SDKs/linux/usr/include/stdio.h index fba593640..e2161daa4 100644 --- a/SDKs/linux/usr/include/stdio.h +++ b/SDKs/linux/usr/include/stdio.h @@ -35,6 +35,7 @@ extern int fflush(FILE *); extern FILE *fopen(const char * restrict, const char * restrict); extern FILE *fdopen(int, const char * restrict); extern int fprintf(FILE * restrict, const char * restrict, ...); +extern int fputc(int, FILE *); extern size_t fwrite(const void * restrict, size_t, size_t, FILE * restrict); extern size_t fread(void * restrict, size_t, size_t, FILE * restrict); extern long ftell(FILE *); diff --git a/lib/profile/PGOProfiling.c b/lib/profile/PGOProfiling.c index 986fd8459..23a48604a 100644 --- a/lib/profile/PGOProfiling.c +++ b/lib/profile/PGOProfiling.c @@ -32,68 +32,99 @@ typedef unsigned int uint32_t; typedef unsigned long long uint64_t; #endif -static FILE *OutputFile = NULL; - -/* - * A list of functions to write out the data. +typedef struct __llvm_pgo_data { + const uint32_t NameSize; + const uint32_t NumCounters; + 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. */ -typedef void (*writeout_fn)(); - -struct writeout_fn_node { - writeout_fn fn; - struct writeout_fn_node *next; -}; - -static struct writeout_fn_node *writeout_fn_head = NULL; -static struct writeout_fn_node *writeout_fn_tail = NULL; - -void llvm_pgo_emit(const char *MangledName, uint32_t NumCounters, - uint64_t *Counters) { - uint32_t i; - fprintf(OutputFile, "%s %u\n", MangledName, NumCounters); - for (i = 0; i < NumCounters; ++i) - fprintf(OutputFile, "%" PRIu64 "\n", Counters[i]); - fprintf(OutputFile, "\n"); +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; } -void llvm_pgo_register_writeout_function(writeout_fn fn) { - struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node)); - new_node->fn = fn; - new_node->next = NULL; +/*! \brief Get the first instrumentation record. */ +static __llvm_pgo_data *getFirst() { + /* TODO: Use extern + linker magic instead of a static variable. */ + return First; +} - if (!writeout_fn_head) { - writeout_fn_head = writeout_fn_tail = new_node; - } else { - writeout_fn_tail->next = new_node; - writeout_fn_tail = new_node; - } +/*! \brief Get the last instrumentation record. */ +static __llvm_pgo_data *getLast() { + /* TODO: Use extern + linker magic instead of a static variable. */ + return Final + 1; } -void llvm_pgo_writeout_files() { - const char *OutputName = getenv("LLVM_PROFILE_FILE"); - if (OutputName == NULL || OutputName[0] == '\0') - OutputName = "default.profdata"; +/* 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, " %u\n", 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; - while (writeout_fn_head) { - struct writeout_fn_node *node = writeout_fn_head; - writeout_fn_head = writeout_fn_head->next; - node->fn(); - free(node); - } + /* 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); } -void llvm_pgo_init(writeout_fn wfn) { - static int atexit_ran = 0; +/*! \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); +} - if (wfn) - llvm_pgo_register_writeout_function(wfn); +/*! + * \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 (atexit_ran == 0) { - atexit_ran = 1; - atexit(llvm_pgo_writeout_files); + if (!HasBeenRegistered) { + HasBeenRegistered = 1; + atexit(__llvm_pgo_write_default_file); } } |