PGO: Statically generate data structures
[blocksruntime.git] / lib / profile / PGOProfiling.c
blob2d919942b8d95ca9f7cdd4609e89b8a270c69ccd
1 /*===- PGOProfiling.c - Support library for PGO instrumentation -----------===*\
2 |*
3 |* The LLVM Compiler Infrastructure
4 |*
5 |* This file is distributed under the University of Illinois Open Source
6 |* License. See LICENSE.TXT for details.
7 |*
8 \*===----------------------------------------------------------------------===*/
10 #include <stdio.h>
11 #include <stdlib.h>
13 #define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__))
15 #if !I386_FREEBSD
16 #include <inttypes.h>
17 #endif
19 #if !defined(_MSC_VER) && !I386_FREEBSD
20 #include <stdint.h>
21 #endif
23 #if defined(_MSC_VER)
24 typedef unsigned int uint32_t;
25 typedef unsigned int uint64_t;
26 #elif I386_FREEBSD
27 /* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to
28 * FreeBSD 10, r232261) when compiled in 32-bit mode.
30 #define PRIu64 "llu"
31 typedef unsigned int uint32_t;
32 typedef unsigned long long uint64_t;
33 #endif
35 typedef struct __ProfileData {
36 const uint32_t NameSize;
37 const uint32_t NumCounters;
38 const char *const Name;
39 const uint64_t *const Counters;
40 } __ProfileData;
42 /* TODO: Calculate these with linker magic. */
43 static __ProfileData *First = NULL;
44 static __ProfileData *Final = NULL;
45 /*!
46 * \brief Register an instrumented function.
48 * Calls to this are emitted by clang with -fprofile-instr-generate. Such
49 * calls are only required (and only emitted) on targets where we haven't
50 * implemented linker magic to find the bounds of the section.
52 * For now, that's all targets.
54 void __llvm_pgo_register_function(void *Data_) {
55 /* TODO: Only emit this function if we can't use linker magic. */
56 __ProfileData *Data = (__ProfileData*)Data_;
57 if (!First || Data < First)
58 First = Data;
59 if (!Final || Data > Final)
60 Final = Data;
63 /*! \brief Get the first instrumentation record. */
64 static __ProfileData *getFirst() {
65 /* TODO: Use extern + linker magic instead of a static variable. */
66 return First;
69 /*! \brief Get the last instrumentation record. */
70 static __ProfileData *getLast() {
71 /* TODO: Use extern + linker magic instead of a static variable. */
72 return Final + 1;
75 /* TODO: void __llvm_pgo_get_size_for_buffer(void); */
76 /* TODO: void __llvm_pgo_write_buffer(char *Buffer); */
78 static void writeFunction(FILE *OutputFile, const __ProfileData *Data) {
79 /* TODO: Requires libc: break requirement by writing directly to a buffer
80 * instead of a FILE stream.
82 uint32_t I;
83 for (I = 0; I < Data->NameSize; ++I)
84 fputc(Data->Name[I], OutputFile);
85 fprintf(OutputFile, " %u\n", Data->NumCounters);
86 for (I = 0; I < Data->NumCounters; ++I)
87 fprintf(OutputFile, "%" PRIu64 "\n", Data->Counters[I]);
88 fprintf(OutputFile, "\n");
91 /*! \brief Write instrumentation data to the given file. */
92 void __llvm_pgo_write_file(const char *OutputName) {
93 /* TODO: Requires libc: move to separate translation unit. */
94 __ProfileData *I, *E;
95 FILE *OutputFile;
96 if (!OutputName || !OutputName[0])
97 return;
98 OutputFile = fopen(OutputName, "w");
99 if (!OutputFile) return;
101 /* TODO: mmap file to buffer of size __llvm_pgo_get_size_for_buffer() and
102 * call __llvm_pgo_write_buffer().
104 for (I = getFirst(), E = getLast(); I != E; ++I)
105 writeFunction(OutputFile, I);
107 fclose(OutputFile);
110 /*! \brief Write instrumentation data to the default file. */
111 void __llvm_pgo_write_default_file() {
112 /* TODO: Requires libc: move to separate translation unit. */
113 const char *OutputName = getenv("LLVM_PROFILE_FILE");
114 if (OutputName == NULL || OutputName[0] == '\0')
115 OutputName = "default.profdata";
116 __llvm_pgo_write_file(OutputName);
120 * \brief Register to write instrumentation data to the default file at exit.
122 void __llvm_pgo_register_write_atexit() {
123 /* TODO: Requires libc: move to separate translation unit. */
124 static int HasBeenRegistered = 0;
126 if (!HasBeenRegistered) {
127 HasBeenRegistered = 1;
128 atexit(__llvm_pgo_write_default_file);