PGO: Splitting implementation files; no functionality change

Split implementation files along a uses-libc/shouldn't-use-libc
boundary.

  - InstrProfiling.h is a shared header.

  - InstrProfiling.c provides an API to extract profiling data from the
    runtime, but avoids the use of libc.  Currently this is a lie:
    __llvm_pgo_write_buffer() uses `FILE*` and related functions.  It
    will be updated soon to write to a `char*` buffer instead.

  - InstrProfilingExtras.c provides a more convenient API for
    interfacing with the profiling runtime, but has logic that does (and
    will continue to) use libc.

<rdar://problem/15943240>

llvm-svn: 204268
This commit is contained in:
Duncan P. N. Exon Smith 2014-03-19 22:10:27 +00:00
parent 61c97335c6
commit 8353a26e85
5 changed files with 173 additions and 132 deletions

View File

@ -1,6 +1,7 @@
set(PROFILE_SOURCES set(PROFILE_SOURCES
GCDAProfiling.c GCDAProfiling.c
PGOProfiling.c) InstrProfiling.c
InstrProfilingExtras.c)
filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386 arm) filter_available_targets(PROFILE_SUPPORTED_ARCH x86_64 i386 arm)

View File

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

View File

@ -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 <stdio.h>
#include <stdlib.h>
#define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__))
#if !I386_FREEBSD
#include <inttypes.h>
#endif
#if !defined(_MSC_VER) && !I386_FREEBSD
#include <stdint.h>
#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);

View File

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

View File

@ -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 <stdio.h>
#include <stdlib.h>
#define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__))
#if !I386_FREEBSD
#include <inttypes.h>
#endif
#if !defined(_MSC_VER) && !I386_FREEBSD
#include <stdint.h>
#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);
}
}