diff options
author | tstellar <tstellar@91177308-0d34-0410-b5e6-96231b3b80d8> | 2012-09-18 19:40:39 +0000 |
---|---|---|
committer | tstellar <tstellar@91177308-0d34-0410-b5e6-96231b3b80d8> | 2012-09-18 19:40:39 +0000 |
commit | 15d14cb83df480dd4aab6435873ca50254891a2d (patch) | |
tree | e5ef7d77a1e7703b625d5de82d50c26e4944cdc7 /runtime |
Create R600 Branch
git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/R600/@164161 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/CMakeLists.txt | 5 | ||||
-rw-r--r-- | runtime/LLVMBuild.txt | 21 | ||||
-rw-r--r-- | runtime/Makefile | 31 | ||||
-rw-r--r-- | runtime/README.txt | 4 | ||||
-rw-r--r-- | runtime/libprofile/BasicBlockTracing.c | 67 | ||||
-rw-r--r-- | runtime/libprofile/CMakeLists.txt | 20 | ||||
-rw-r--r-- | runtime/libprofile/CommonProfiling.c | 151 | ||||
-rw-r--r-- | runtime/libprofile/EdgeProfiling.c | 45 | ||||
-rw-r--r-- | runtime/libprofile/GCDAProfiling.c | 205 | ||||
-rw-r--r-- | runtime/libprofile/Makefile | 51 | ||||
-rw-r--r-- | runtime/libprofile/OptimalEdgeProfiling.c | 45 | ||||
-rw-r--r-- | runtime/libprofile/PathProfiling.c | 270 | ||||
-rw-r--r-- | runtime/libprofile/Profiling.h | 36 | ||||
-rw-r--r-- | runtime/libprofile/libprofile.exports | 12 |
14 files changed, 963 insertions, 0 deletions
diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt new file mode 100644 index 0000000000..502b91dc58 --- /dev/null +++ b/runtime/CMakeLists.txt @@ -0,0 +1,5 @@ +if( NOT LLVM_BUILD_RUNTIME ) + set(EXCLUDE_FROM_ALL ON) +endif() + +add_subdirectory(libprofile) diff --git a/runtime/LLVMBuild.txt b/runtime/LLVMBuild.txt new file mode 100644 index 0000000000..05334fda50 --- /dev/null +++ b/runtime/LLVMBuild.txt @@ -0,0 +1,21 @@ +;===- ./runtime/LLVMBuild.txt ----------------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Group +name = Runtime +parent = $ROOT diff --git a/runtime/Makefile b/runtime/Makefile new file mode 100644 index 0000000000..d0e85d5826 --- /dev/null +++ b/runtime/Makefile @@ -0,0 +1,31 @@ +##===- runtime/Makefile ------------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = .. +include $(LEVEL)/Makefile.config + +ifndef NO_RUNTIME_LIBS + +PARALLEL_DIRS := libprofile + +# Disable libprofile: a faulty libtool is generated by autoconf which breaks the +# build on Sparc +ifeq ($(ARCH), Sparc) +PARALLEL_DIRS := $(filter-out libprofile, $(PARALLEL_DIRS)) +endif + +ifeq ($(TARGET_OS), $(filter $(TARGET_OS), Cygwin MingW Minix)) +PARALLEL_DIRS := $(filter-out libprofile, $(PARALLEL_DIRS)) +endif + +endif + +include $(LEVEL)/Makefile.common + +install:: diff --git a/runtime/README.txt b/runtime/README.txt new file mode 100644 index 0000000000..2e2e547de3 --- /dev/null +++ b/runtime/README.txt @@ -0,0 +1,4 @@ +This directory contains the various runtime libraries used by components of +the LLVM compiler. For example, the automatic pool allocation transformation +inserts calls to an external pool allocator library. This runtime library is +an example of the type of library that lives in these directories. diff --git a/runtime/libprofile/BasicBlockTracing.c b/runtime/libprofile/BasicBlockTracing.c new file mode 100644 index 0000000000..0815e2e516 --- /dev/null +++ b/runtime/libprofile/BasicBlockTracing.c @@ -0,0 +1,67 @@ +/*===-- BasicBlockTracing.c - Support library for basic block tracing -----===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +|*===----------------------------------------------------------------------===*| +|* +|* This file implements the call back routines for the basic block tracing +|* instrumentation pass. This should be used with the -trace-basic-blocks +|* LLVM pass. +|* +\*===----------------------------------------------------------------------===*/ + +#include "Profiling.h" +#include <stdlib.h> +#include <stdio.h> + +static unsigned *ArrayStart, *ArrayEnd, *ArrayCursor; + +/* WriteAndFlushBBTraceData - write out the currently accumulated trace data + * and reset the cursor to point to the beginning of the buffer. + */ +static void WriteAndFlushBBTraceData () { + write_profiling_data(BBTraceInfo, ArrayStart, (ArrayCursor - ArrayStart)); + ArrayCursor = ArrayStart; +} + +/* BBTraceAtExitHandler - When the program exits, just write out any remaining + * data and free the trace buffer. + */ +static void BBTraceAtExitHandler(void) { + WriteAndFlushBBTraceData (); + free (ArrayStart); +} + +/* llvm_trace_basic_block - called upon hitting a new basic block. */ +void llvm_trace_basic_block (unsigned BBNum) { + *ArrayCursor++ = BBNum; + if (ArrayCursor == ArrayEnd) + WriteAndFlushBBTraceData (); +} + +/* llvm_start_basic_block_tracing - This is the main entry point of the basic + * block tracing library. It is responsible for setting up the atexit + * handler and allocating the trace buffer. + */ +int llvm_start_basic_block_tracing(int argc, const char **argv, + unsigned *arrayStart, unsigned numElements) { + int Ret; + const unsigned BufferSize = 128 * 1024; + unsigned ArraySize; + + Ret = save_arguments(argc, argv); + + /* Allocate a buffer to contain BB tracing data */ + ArraySize = BufferSize / sizeof (unsigned); + ArrayStart = malloc (ArraySize * sizeof (unsigned)); + ArrayEnd = ArrayStart + ArraySize; + ArrayCursor = ArrayStart; + + /* Set up the atexit handler. */ + atexit (BBTraceAtExitHandler); + + return Ret; +} diff --git a/runtime/libprofile/CMakeLists.txt b/runtime/libprofile/CMakeLists.txt new file mode 100644 index 0000000000..8609715b33 --- /dev/null +++ b/runtime/libprofile/CMakeLists.txt @@ -0,0 +1,20 @@ +set(SOURCES + BasicBlockTracing.c + CommonProfiling.c + GCDAProfiling.c + PathProfiling.c + EdgeProfiling.c + OptimalEdgeProfiling.c + Profiling.h + ) + +add_llvm_library( profile_rt-static ${SOURCES} ) +set_target_properties( profile_rt-static + PROPERTIES + OUTPUT_NAME "profile_rt" ) + +set(BUILD_SHARED_LIBS ON) +add_llvm_library( profile_rt-shared ${SOURCES} ) +set_target_properties( profile_rt-shared + PROPERTIES + OUTPUT_NAME "profile_rt" ) diff --git a/runtime/libprofile/CommonProfiling.c b/runtime/libprofile/CommonProfiling.c new file mode 100644 index 0000000000..acc17ce11e --- /dev/null +++ b/runtime/libprofile/CommonProfiling.c @@ -0,0 +1,151 @@ +/*===-- CommonProfiling.c - Profiling support library support -------------===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +|*===----------------------------------------------------------------------===*| +|* +|* This file implements functions used by the various different types of +|* profiling implementations. +|* +\*===----------------------------------------------------------------------===*/ + +#include "Profiling.h" +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include <unistd.h> +#else +#include <io.h> +#endif +#include <stdlib.h> + +static char *SavedArgs = 0; +static unsigned SavedArgsLength = 0; + +static const char *OutputFilename = "llvmprof.out"; + +/* save_arguments - Save argc and argv as passed into the program for the file + * we output. + */ +int save_arguments(int argc, const char **argv) { + unsigned Length, i; + if (SavedArgs || !argv) return argc; /* This can be called multiple times */ + + /* Check to see if there are any arguments passed into the program for the + * profiler. If there are, strip them off and remember their settings. + */ + while (argc > 1 && !strncmp(argv[1], "-llvmprof-", 10)) { + /* Ok, we have an llvmprof argument. Remove it from the arg list and decide + * what to do with it. + */ + const char *Arg = argv[1]; + memmove((char**)&argv[1], &argv[2], (argc-1)*sizeof(char*)); + --argc; + + if (!strcmp(Arg, "-llvmprof-output")) { + if (argc == 1) + puts("-llvmprof-output requires a filename argument!"); + else { + OutputFilename = strdup(argv[1]); + memmove((char**)&argv[1], &argv[2], (argc-1)*sizeof(char*)); + --argc; + } + } else { + printf("Unknown option to the profiler runtime: '%s' - ignored.\n", Arg); + } + } + + for (Length = 0, i = 0; i != (unsigned)argc; ++i) + Length += strlen(argv[i])+1; + + /* Defensively check for a zero length, even though this is unlikely + * to happen in practice. This avoids calling malloc() below with a + * size of 0. + */ + if (Length == 0) { + SavedArgs = 0; + SavedArgsLength = 0; + return argc; + } + + SavedArgs = (char*)malloc(Length); + for (Length = 0, i = 0; i != (unsigned)argc; ++i) { + unsigned Len = strlen(argv[i]); + memcpy(SavedArgs+Length, argv[i], Len); + Length += Len; + SavedArgs[Length++] = ' '; + } + + SavedArgsLength = Length; + + return argc; +} + + +/* + * Retrieves the file descriptor for the profile file. + */ +int getOutFile() { + static int OutFile = -1; + + /* If this is the first time this function is called, open the output file + * for appending, creating it if it does not already exist. + */ + if (OutFile == -1) { + OutFile = open(OutputFilename, O_CREAT | O_WRONLY, 0666); + lseek(OutFile, 0, SEEK_END); /* O_APPEND prevents seeking */ + if (OutFile == -1) { + fprintf(stderr, "LLVM profiling runtime: while opening '%s': ", + OutputFilename); + perror(""); + return(OutFile); + } + + /* Output the command line arguments to the file. */ + { + int PTy = ArgumentInfo; + int Zeros = 0; + if (write(OutFile, &PTy, sizeof(int)) < 0 || + write(OutFile, &SavedArgsLength, sizeof(unsigned)) < 0 || + write(OutFile, SavedArgs, SavedArgsLength) < 0 ) { + fprintf(stderr,"error: unable to write to output file."); + exit(0); + } + /* Pad out to a multiple of four bytes */ + if (SavedArgsLength & 3) { + if (write(OutFile, &Zeros, 4-(SavedArgsLength&3)) < 0) { + fprintf(stderr,"error: unable to write to output file."); + exit(0); + } + } + } + } + return(OutFile); +} + +/* write_profiling_data - Write a raw block of profiling counters out to the + * llvmprof.out file. Note that we allow programs to be instrumented with + * multiple different kinds of instrumentation. For this reason, this function + * may be called more than once. + */ +void write_profiling_data(enum ProfilingType PT, unsigned *Start, + unsigned NumElements) { + int PTy; + int outFile = getOutFile(); + + /* Write out this record! */ + PTy = PT; + if( write(outFile, &PTy, sizeof(int)) < 0 || + write(outFile, &NumElements, sizeof(unsigned)) < 0 || + write(outFile, Start, NumElements*sizeof(unsigned)) < 0 ) { + fprintf(stderr,"error: unable to write to output file."); + exit(0); + } +} diff --git a/runtime/libprofile/EdgeProfiling.c b/runtime/libprofile/EdgeProfiling.c new file mode 100644 index 0000000000..f19e188f0d --- /dev/null +++ b/runtime/libprofile/EdgeProfiling.c @@ -0,0 +1,45 @@ +/*===-- EdgeProfiling.c - Support library for edge profiling --------------===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +|*===----------------------------------------------------------------------===*| +|* +|* This file implements the call back routines for the edge profiling +|* instrumentation pass. This should be used with the -insert-edge-profiling +|* LLVM pass. +|* +\*===----------------------------------------------------------------------===*/ + +#include "Profiling.h" +#include <stdlib.h> + +static unsigned *ArrayStart; +static unsigned NumElements; + +/* EdgeProfAtExitHandler - When the program exits, just write out the profiling + * data. + */ +static void EdgeProfAtExitHandler(void) { + /* Note that if this were doing something more intelligent with the + * instrumentation, we could do some computation here to expand what we + * collected into simple edge profiles. Since we directly count each edge, we + * just write out all of the counters directly. + */ + write_profiling_data(EdgeInfo, ArrayStart, NumElements); +} + + +/* llvm_start_edge_profiling - This is the main entry point of the edge + * profiling library. It is responsible for setting up the atexit handler. + */ +int llvm_start_edge_profiling(int argc, const char **argv, + unsigned *arrayStart, unsigned numElements) { + int Ret = save_arguments(argc, argv); + ArrayStart = arrayStart; + NumElements = numElements; + atexit(EdgeProfAtExitHandler); + return Ret; +} diff --git a/runtime/libprofile/GCDAProfiling.c b/runtime/libprofile/GCDAProfiling.c new file mode 100644 index 0000000000..f2dc4f7988 --- /dev/null +++ b/runtime/libprofile/GCDAProfiling.c @@ -0,0 +1,205 @@ +/*===- GCDAProfiling.c - Support library for GCDA file emission -----------===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +|*===----------------------------------------------------------------------===*| +|* +|* This file implements the call back routines for the gcov profiling +|* instrumentation pass. Link against this library when running code through +|* the -insert-gcov-profiling LLVM pass. +|* +|* We emit files in a corrupt version of GCOV's "gcda" file format. These files +|* are only close enough that LCOV will happily parse them. Anything that lcov +|* ignores is missing. +|* +|* TODO: gcov is multi-process safe by having each exit open the existing file +|* and append to it. We'd like to achieve that and be thread-safe too. +|* +\*===----------------------------------------------------------------------===*/ + +#include "llvm/Support/DataTypes.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#ifdef _WIN32 +#include <direct.h> +#endif + +/* #define DEBUG_GCDAPROFILING */ + +/* + * --- GCOV file format I/O primitives --- + */ + +static FILE *output_file = NULL; + +static void write_int32(uint32_t i) { + fwrite(&i, 4, 1, output_file); +} + +static void write_int64(uint64_t i) { + uint32_t lo = i >> 0; + uint32_t hi = i >> 32; + write_int32(lo); + write_int32(hi); +} + +static uint32_t length_of_string(const char *s) { + return (strlen(s) / 4) + 1; +} + +static void write_string(const char *s) { + uint32_t len = length_of_string(s); + write_int32(len); + fwrite(s, strlen(s), 1, output_file); + fwrite("\0\0\0\0", 4 - (strlen(s) % 4), 1, output_file); +} + +static char *mangle_filename(const char *orig_filename) { + /* TODO: handle GCOV_PREFIX_STRIP */ + const char *prefix; + char *filename = 0; + + prefix = getenv("GCOV_PREFIX"); + + if (!prefix) + return strdup(orig_filename); + + filename = malloc(strlen(prefix) + 1 + strlen(orig_filename) + 1); + strcpy(filename, prefix); + strcat(filename, "/"); + strcat(filename, orig_filename); + return filename; +} + +static void recursive_mkdir(const char *filename) { + char *pathname; + int i, e; + + for (i = 1, e = strlen(filename); i != e; ++i) { + if (filename[i] != '/') continue; + pathname = malloc(i + 1); + strncpy(pathname, filename, i); + pathname[i] = '\0'; +#ifdef _WIN32 + _mkdir(pathname); +#else + mkdir(pathname, 0750); /* some of these will fail, ignore it. */ +#endif + free(pathname); + } +} + +/* + * --- LLVM line counter API --- + */ + +/* A file in this case is a translation unit. Each .o file built with line + * profiling enabled will emit to a different file. Only one file may be + * started at a time. + */ +void llvm_gcda_start_file(const char *orig_filename) { + char *filename; + filename = mangle_filename(orig_filename); + recursive_mkdir(filename); + output_file = fopen(filename, "w+b"); + + if (!output_file) { + const char *cptr = strrchr(orig_filename, '/'); + output_file = fopen(cptr ? cptr + 1 : orig_filename, "w+b"); + + if (!output_file) { + fprintf(stderr, "LLVM profiling runtime: cannot open '%s': ", + cptr ? cptr + 1 : orig_filename); + perror(""); + free(filename); + return; + } + } + + /* gcda file, version 404*, stamp LLVM. */ +#ifdef __APPLE__ + fwrite("adcg*204MVLL", 12, 1, output_file); +#else + fwrite("adcg*404MVLL", 12, 1, output_file); +#endif + +#ifdef DEBUG_GCDAPROFILING + printf("llvmgcda: [%s]\n", orig_filename); +#endif + + free(filename); +} + +/* Given an array of pointers to counters (counters), increment the n-th one, + * where we're also given a pointer to n (predecessor). + */ +void llvm_gcda_increment_indirect_counter(uint32_t *predecessor, + uint64_t **counters) { + uint64_t *counter; + uint32_t pred; + + pred = *predecessor; + if (pred == 0xffffffff) + return; + counter = counters[pred]; + + /* Don't crash if the pred# is out of sync. This can happen due to threads, + or because of a TODO in GCOVProfiling.cpp buildEdgeLookupTable(). */ + if (counter) + ++*counter; +#ifdef DEBUG_GCDAPROFILING + else + printf("llvmgcda: increment_indirect_counter counters=%x, pred=%u\n", + state_table_row, *predecessor); +#endif +} + +void llvm_gcda_emit_function(uint32_t ident, const char *function_name) { +#ifdef DEBUG_GCDAPROFILING + printf("llvmgcda: function id=%x\n", ident); +#endif + if (!output_file) return; + + /* function tag */ + fwrite("\0\0\0\1", 4, 1, output_file); + write_int32(3 + 1 + length_of_string(function_name)); + write_int32(ident); + write_int32(0); + write_int32(0); + write_string(function_name); +} + +void llvm_gcda_emit_arcs(uint32_t num_counters, uint64_t *counters) { + uint32_t i; + + /* Counter #1 (arcs) tag */ + if (!output_file) return; + fwrite("\0\0\xa1\1", 4, 1, output_file); + write_int32(num_counters * 2); + for (i = 0; i < num_counters; ++i) + write_int64(counters[i]); + +#ifdef DEBUG_GCDAPROFILING + printf("llvmgcda: %u arcs\n", num_counters); + for (i = 0; i < num_counters; ++i) + printf("llvmgcda: %llu\n", (unsigned long long)counters[i]); +#endif +} + +void llvm_gcda_end_file() { + /* Write out EOF record. */ + if (!output_file) return; + fwrite("\0\0\0\0\0\0\0\0", 8, 1, output_file); + fclose(output_file); + output_file = NULL; + +#ifdef DEBUG_GCDAPROFILING + printf("llvmgcda: -----\n"); +#endif +} diff --git a/runtime/libprofile/Makefile b/runtime/libprofile/Makefile new file mode 100644 index 0000000000..d8511495ce --- /dev/null +++ b/runtime/libprofile/Makefile @@ -0,0 +1,51 @@ +##===- runtime/libprofile/Makefile -------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +include $(LEVEL)/Makefile.config + +ifneq ($(strip $(LLVMCC)),) +BYTECODE_LIBRARY = 1 +endif +LIBRARYNAME = profile_rt +LINK_LIBS_IN_SHARED = 1 +SHARED_LIBRARY = 1 +EXTRA_DIST = libprofile.exports +EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/libprofile.exports + +# Build and install this archive. +BUILD_ARCHIVE = 1 +override NO_INSTALL_ARCHIVES = + +include $(LEVEL)/Makefile.common + +ifeq ($(HOST_OS),Darwin) + # Special hack to allow libprofile_rt to have an offset version number. + PROFILE_RT_LIBRARY_VERSION := $(LLVM_SUBMIT_VERSION) + + # Set dylib internal version number to llvmCore submission number. + ifdef LLVM_SUBMIT_VERSION + LLVMLibsOptions := $(LLVMLibsOptions) -Wl,-current_version \ + -Wl,$(PROFILE_RT_LIBRARY_VERSION).$(LLVM_SUBMIT_SUBVERSION) \ + -Wl,-compatibility_version -Wl,1 + endif + # Extra options to override libtool defaults. + LLVMLibsOptions := $(LLVMLibsOptions) \ + -Wl,-dead_strip \ + -Wl,-seg1addr -Wl,0xE0000000 + + # Mac OS X 10.4 and earlier tools do not allow a second -install_name on + # command line. + DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/') + ifneq ($(DARWIN_VERS),8) + LLVMLibsOptions := $(LLVMLibsOptions) \ + -Wl,-install_name \ + -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)" + endif +endif diff --git a/runtime/libprofile/OptimalEdgeProfiling.c b/runtime/libprofile/OptimalEdgeProfiling.c new file mode 100644 index 0000000000..3a7631b6e8 --- /dev/null +++ b/runtime/libprofile/OptimalEdgeProfiling.c @@ -0,0 +1,45 @@ +/*===-- OptimalEdgeProfiling.c - Support library for opt. edge profiling --===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +|*===----------------------------------------------------------------------===*| +|* +|* This file implements the call back routines for the edge profiling +|* instrumentation pass. This should be used with the +|* -insert-opt-edge-profiling LLVM pass. +|* +\*===----------------------------------------------------------------------===*/ + +#include "Profiling.h" +#include <stdlib.h> + +static unsigned *ArrayStart; +static unsigned NumElements; + +/* OptEdgeProfAtExitHandler - When the program exits, just write out the + * profiling data. + */ +static void OptEdgeProfAtExitHandler(void) { + /* Note that, although the array has a counter for each edge, not all + * counters are updated, the ones that are not used are initialised with -1. + * When loading this information the counters with value -1 have to be + * recalculated, it is guaranteed that this is possible. + */ + write_profiling_data(OptEdgeInfo, ArrayStart, NumElements); +} + + +/* llvm_start_opt_edge_profiling - This is the main entry point of the edge + * profiling library. It is responsible for setting up the atexit handler. + */ +int llvm_start_opt_edge_profiling(int argc, const char **argv, + unsigned *arrayStart, unsigned numElements) { + int Ret = save_arguments(argc, argv); + ArrayStart = arrayStart; + NumElements = numElements; + atexit(OptEdgeProfAtExitHandler); + return Ret; +} diff --git a/runtime/libprofile/PathProfiling.c b/runtime/libprofile/PathProfiling.c new file mode 100644 index 0000000000..71ee944fc5 --- /dev/null +++ b/runtime/libprofile/PathProfiling.c @@ -0,0 +1,270 @@ +/*===-- PathProfiling.c - Support library for path profiling --------------===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +|*===----------------------------------------------------------------------===*| +|* +|* This file implements the call back routines for the path profiling +|* instrumentation pass. This should be used with the -insert-path-profiling +|* LLVM pass. +|* +\*===----------------------------------------------------------------------===*/ + +#include "Profiling.h" +#include "llvm/Analysis/ProfileInfoTypes.h" +#include "llvm/Support/DataTypes.h" +#include <sys/types.h> +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include <unistd.h> +#else +#include <io.h> +#endif +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +/* note that this is used for functions with large path counts, + but it is unlikely those paths will ALL be executed */ +#define ARBITRARY_HASH_BIN_COUNT 100 + +typedef struct pathHashEntry_s { + uint32_t pathNumber; + uint32_t pathCount; + struct pathHashEntry_s* next; +} pathHashEntry_t; + +typedef struct pathHashTable_s { + pathHashEntry_t* hashBins[ARBITRARY_HASH_BIN_COUNT]; + uint32_t pathCounts; +} pathHashTable_t; + +typedef struct { + enum ProfilingStorageType type; + uint32_t size; + void* array; +} ftEntry_t; + +/* pointer to the function table allocated in the instrumented program */ +ftEntry_t* ft; +uint32_t ftSize; + +/* write an array table to file */ +void writeArrayTable(uint32_t fNumber, ftEntry_t* ft, uint32_t* funcCount) { + int outFile = getOutFile(); + uint32_t arrayHeaderLocation = 0; + uint32_t arrayCurrentLocation = 0; + uint32_t arrayIterator = 0; + uint32_t functionUsed = 0; + uint32_t pathCounts = 0; + + /* look through each entry in the array to determine whether the function + was executed at all */ + for( arrayIterator = 0; arrayIterator < ft->size; arrayIterator++ ) { + uint32_t pc = ((uint32_t*)ft->array)[arrayIterator]; + + /* was this path executed? */ + if( pc ) { + PathProfileTableEntry pte; + pte.pathNumber = arrayIterator; + pte.pathCounter = pc; + pathCounts++; + + /* one-time initialization stuff */ + if(!functionUsed) { + arrayHeaderLocation = lseek(outFile, 0, SEEK_CUR); + lseek(outFile, sizeof(PathProfileHeader), SEEK_CUR); + functionUsed = 1; + (*funcCount)++; + } + + /* write path data */ + if (write(outFile, &pte, sizeof(PathProfileTableEntry)) < 0) { + fprintf(stderr, "error: unable to write path entry to output file.\n"); + return; + } + } + } + + /* If this function was executed, write the header */ + if( functionUsed ) { + PathProfileHeader fHeader; + fHeader.fnNumber = fNumber; + fHeader.numEntries = pathCounts; + + arrayCurrentLocation = lseek(outFile, 0, SEEK_CUR); + lseek(outFile, arrayHeaderLocation, SEEK_SET); + + if (write(outFile, &fHeader, sizeof(PathProfileHeader)) < 0) { + fprintf(stderr, + "error: unable to write function header to output file.\n"); + return; + } + + lseek(outFile, arrayCurrentLocation, SEEK_SET); + } +} + +static uint32_t hash (uint32_t key) { + /* this may benefit from a proper hash function */ + return key%ARBITRARY_HASH_BIN_COUNT; +} + +/* output a specific function's hash table to the profile file */ +void writeHashTable(uint32_t functionNumber, pathHashTable_t* hashTable) { + int outFile = getOutFile(); + PathProfileHeader header; + uint32_t i; + + header.fnNumber = functionNumber; + header.numEntries = hashTable->pathCounts; + + if (write(outFile, &header, sizeof(PathProfileHeader)) < 0) { + fprintf(stderr, "error: unable to write function header to output file.\n"); + return; + } + + for (i = 0; i < ARBITRARY_HASH_BIN_COUNT; i++) { + pathHashEntry_t* hashEntry = hashTable->hashBins[i]; + + while (hashEntry) { + pathHashEntry_t* temp; + + PathProfileTableEntry pte; + pte.pathNumber = hashEntry->pathNumber; + pte.pathCounter = hashEntry->pathCount; + + if (write(outFile, &pte, sizeof(PathProfileTableEntry)) < 0) { + fprintf(stderr, "error: unable to write path entry to output file.\n"); + return; + } + + temp = hashEntry; + hashEntry = hashEntry->next; + free (temp); + + } + } +} + +/* Return a pointer to this path's specific path counter */ +static uint32_t* getPathCounter(uint32_t functionNumber, + uint32_t pathNumber) { + pathHashTable_t* hashTable; + pathHashEntry_t* hashEntry; + uint32_t index = hash(pathNumber); + + if( ft[functionNumber-1].array == 0) + ft[functionNumber-1].array = calloc(sizeof(pathHashTable_t), 1); + + hashTable = (pathHashTable_t*)((ftEntry_t*)ft)[functionNumber-1].array; + hashEntry = hashTable->hashBins[index]; + + while (hashEntry) { + if (hashEntry->pathNumber == pathNumber) { + return &hashEntry->pathCount; + } + + hashEntry = hashEntry->next; + } + + hashEntry = malloc(sizeof(pathHashEntry_t)); + hashEntry->pathNumber = pathNumber; + hashEntry->pathCount = 0; + hashEntry->next = hashTable->hashBins[index]; + hashTable->hashBins[index] = hashEntry; + hashTable->pathCounts++; + return &hashEntry->pathCount; +} + +/* Increment a specific path's count */ +void llvm_increment_path_count (uint32_t functionNumber, uint32_t pathNumber) { + uint32_t* pathCounter = getPathCounter(functionNumber, pathNumber); + if( *pathCounter < 0xffffffff ) + (*pathCounter)++; +} + +/* Increment a specific path's count */ +void llvm_decrement_path_count (uint32_t functionNumber, uint32_t pathNumber) { + uint32_t* pathCounter = getPathCounter(functionNumber, pathNumber); + (*pathCounter)--; +} + +/* + * Writes out a path profile given a function table, in the following format. + * + * + * | <-- 32 bits --> | + * +-----------------+-----------------+ + * 0x00 | profileType | functionCount | + * +-----------------+-----------------+ + * 0x08 | functionNum | profileEntries | // function 1 + * +-----------------+-----------------+ + * 0x10 | pathNumber | pathCounter | // entry 1.1 + * +-----------------+-----------------+ + * 0x18 | pathNumber | pathCounter | // entry 1.2 + * +-----------------+-----------------+ + * ... | ... | ... | // entry 1.n + * +-----------------+-----------------+ + * ... | functionNum | profileEntries | // function 2 + * +-----------------+-----------------+ + * ... | pathNumber | pathCounter | // entry 2.1 + * +-----------------+-----------------+ + * ... | pathNumber | pathCounter | // entry 2.2 + * +-----------------+-----------------+ + * ... | ... | ... | // entry 2.n + * +-----------------+-----------------+ + * + */ +static void pathProfAtExitHandler(void) { + int outFile = getOutFile(); + uint32_t i; + uint32_t header[2] = { PathInfo, 0 }; + uint32_t headerLocation; + uint32_t currentLocation; + + /* skip over the header for now */ + headerLocation = lseek(outFile, 0, SEEK_CUR); + lseek(outFile, 2*sizeof(uint32_t), SEEK_CUR); + + /* Iterate through each function */ + for( i = 0; i < ftSize; i++ ) { + if( ft[i].type == ProfilingArray ) { + writeArrayTable(i+1,&ft[i],header + 1); + + } else if( ft[i].type == ProfilingHash ) { + /* If the hash exists, write it to file */ + if( ft[i].array ) { + writeHashTable(i+1,ft[i].array); + header[1]++; + free(ft[i].array); + } + } + } + + /* Setup and write the path profile header */ + currentLocation = lseek(outFile, 0, SEEK_CUR); + lseek(outFile, headerLocation, SEEK_SET); + + if (write(outFile, header, sizeof(header)) < 0) { + fprintf(stderr, + "error: unable to write path profile header to output file.\n"); + return; + } + + lseek(outFile, currentLocation, SEEK_SET); +} +/* llvm_start_path_profiling - This is the main entry point of the path + * profiling library. It is responsible for setting up the atexit handler. + */ +int llvm_start_path_profiling(int argc, const char** argv, + void* functionTable, uint32_t numElements) { + int Ret = save_arguments(argc, argv); + ft = functionTable; + ftSize = numElements; + atexit(pathProfAtExitHandler); + + return Ret; +} diff --git a/runtime/libprofile/Profiling.h b/runtime/libprofile/Profiling.h new file mode 100644 index 0000000000..acc6399a18 --- /dev/null +++ b/runtime/libprofile/Profiling.h @@ -0,0 +1,36 @@ +/*===-- Profiling.h - Profiling support library support routines ----------===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +|*===----------------------------------------------------------------------===*| +|* +|* This file defines functions shared by the various different profiling +|* implementations. +|* +\*===----------------------------------------------------------------------===*/ + +#ifndef PROFILING_H +#define PROFILING_H + +#include "llvm/Analysis/ProfileDataTypes.h" /* for enum ProfilingType */ + +/* save_arguments - Save argc and argv as passed into the program for the file + * we output. + */ +int save_arguments(int argc, const char **argv); + +/* + * Retrieves the file descriptor for the profile file. + */ +int getOutFile(); + +/* write_profiling_data - Write out a typed packet of profiling data to the + * current output file. + */ +void write_profiling_data(enum ProfilingType PT, unsigned *Start, + unsigned NumElements); + +#endif diff --git a/runtime/libprofile/libprofile.exports b/runtime/libprofile/libprofile.exports new file mode 100644 index 0000000000..2f25be6920 --- /dev/null +++ b/runtime/libprofile/libprofile.exports @@ -0,0 +1,12 @@ +llvm_start_edge_profiling +llvm_start_opt_edge_profiling +llvm_start_path_profiling +llvm_start_basic_block_tracing +llvm_trace_basic_block +llvm_increment_path_count +llvm_decrement_path_count +llvm_gcda_start_file +llvm_gcda_increment_indirect_counter +llvm_gcda_emit_function +llvm_gcda_emit_arcs +llvm_gcda_end_file |