diff options
-rw-r--r-- | compiler-rt/lib/profile/InstrProfilingFile.c | 7 | ||||
-rw-r--r-- | compiler-rt/lib/profile/InstrProfilingInternal.h | 49 | ||||
-rw-r--r-- | compiler-rt/lib/profile/InstrProfilingWriter.c | 116 | ||||
-rw-r--r-- | compiler-rt/test/profile/instrprof-bufferio.c | 128 |
4 files changed, 252 insertions, 48 deletions
diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c index a803ba52729..4ea7fbf9738 100644 --- a/compiler-rt/lib/profile/InstrProfilingFile.c +++ b/compiler-rt/lib/profile/InstrProfilingFile.c @@ -30,6 +30,13 @@ static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, return 0; } +COMPILER_RT_VISIBILITY ProfBufferIO * +llvmCreateBufferIOInternal(void *File, uint32_t BufferSz) { + CallocHook = calloc; + FreeHook = free; + return llvmCreateBufferIO(fileWriter, File, BufferSz); +} + static int writeFile(FILE *File) { const char *BufferSzStr = 0; uint64_t ValueDataSize = 0; diff --git a/compiler-rt/lib/profile/InstrProfilingInternal.h b/compiler-rt/lib/profile/InstrProfilingInternal.h index 8edd82c3b14..4aab78ea509 100644 --- a/compiler-rt/lib/profile/InstrProfilingInternal.h +++ b/compiler-rt/lib/profile/InstrProfilingInternal.h @@ -39,7 +39,8 @@ int __llvm_profile_write_buffer_internal( const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd); /*! - * This is an internal function not intended to be used externally. + * The data structure describing the data to be written by the + * low level writer callback function. */ typedef struct ProfDataIOVec { const void *Data; @@ -49,8 +50,54 @@ typedef struct ProfDataIOVec { typedef uint32_t (*WriterCallback)(ProfDataIOVec *, uint32_t NumIOVecs, void **WriterCtx); + +/*! + * The data structure for buffered IO of profile data. + */ +typedef struct ProfBufferIO { + /* File handle. */ + void *File; + /* Low level IO callback. */ + WriterCallback FileWriter; + /* The start of the buffer. */ + uint8_t *BufferStart; + /* Total size of the buffer. */ + uint32_t BufferSz; + /* Current byte offset from the start of the buffer. */ + uint32_t CurOffset; +} ProfBufferIO; + +/* The creator interface used by testing. */ +ProfBufferIO *llvmCreateBufferIOInternal(void *File, uint32_t DefaultBufferSz); +/*! + * This is the interface to create a handle for buffered IO. + */ +ProfBufferIO *llvmCreateBufferIO(WriterCallback FileWriter, void *File, + uint32_t DefaultBufferSz); +/*! + * The interface to destroy the bufferIO handle and reclaim + * the memory. + */ +void llvmDeleteBufferIO(ProfBufferIO *BufferIO); + +/*! + * This is the interface to write \c Data of \c Size bytes through + * \c BufferIO. Returns 0 if successful, otherwise return -1. + */ +int llvmBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, + uint32_t Size); +/*! + * The interface to flush the remaining data in the buffer. + * through the low level writer callback. + */ +int llvmBufferIOFlush(ProfBufferIO *BufferIO); + +/* The low level interface to write data into a buffer. It is used as the + * callback by other high level writer methods such as buffered IO writer + * and profile data writer. */ uint32_t llvmBufferWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs, void **WriterCtx); + int llvmWriteProfData(WriterCallback Writer, void *WriterCtx, struct ValueProfData **ValueDataArray, const uint64_t ValueDataSize); diff --git a/compiler-rt/lib/profile/InstrProfilingWriter.c b/compiler-rt/lib/profile/InstrProfilingWriter.c index 6153a00509a..a07bc538ed4 100644 --- a/compiler-rt/lib/profile/InstrProfilingWriter.c +++ b/compiler-rt/lib/profile/InstrProfilingWriter.c @@ -33,6 +33,64 @@ COMPILER_RT_VISIBILITY uint32_t llvmBufferWriter(ProfDataIOVec *IOVecs, return 0; } +static void llvmInitBufferIO(ProfBufferIO *BufferIO, WriterCallback FileWriter, + void *File, uint8_t *Buffer, uint32_t BufferSz) { + BufferIO->File = File; + BufferIO->FileWriter = FileWriter; + BufferIO->BufferStart = Buffer; + BufferIO->BufferSz = BufferSz; + BufferIO->CurOffset = 0; +} + +COMPILER_RT_VISIBILITY ProfBufferIO * +llvmCreateBufferIO(WriterCallback FileWriter, void *File, uint32_t BufferSz) { + ProfBufferIO *BufferIO = (ProfBufferIO *)CallocHook(1, sizeof(ProfBufferIO)); + uint8_t *Buffer = (uint8_t *)CallocHook(1, BufferSz); + if (!Buffer) { + FreeHook(BufferIO); + return 0; + } + llvmInitBufferIO(BufferIO, FileWriter, File, Buffer, BufferSz); + return BufferIO; +} + +COMPILER_RT_VISIBILITY void llvmDeleteBufferIO(ProfBufferIO *BufferIO) { + FreeHook(BufferIO->BufferStart); + FreeHook(BufferIO); +} + +COMPILER_RT_VISIBILITY int +llvmBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) { + /* Buffer is not large enough, it is time to flush. */ + if (Size + BufferIO->CurOffset > BufferIO->BufferSz) { + if (llvmBufferIOFlush(BufferIO) != 0) + return -1; + } + /* Special case, bypass the buffer completely. */ + ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size}}; + if (Size > BufferIO->BufferSz) { + if (BufferIO->FileWriter(IO, 1, &BufferIO->File)) + return -1; + } else { + /* Write the data to buffer */ + uint8_t *Buffer = BufferIO->BufferStart + BufferIO->CurOffset; + llvmBufferWriter(IO, 1, (void **)&Buffer); + BufferIO->CurOffset = Buffer - BufferIO->BufferStart; + } + return 0; +} + +COMPILER_RT_VISIBILITY int llvmBufferIOFlush(ProfBufferIO *BufferIO) { + if (BufferIO->CurOffset) { + ProfDataIOVec IO[] = { + {BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset}}; + if (BufferIO->FileWriter(IO, 1, &BufferIO->File)) + return -1; + BufferIO->CurOffset = 0; + } + return 0; +} + COMPILER_RT_VISIBILITY int llvmWriteProfData(WriterCallback Writer, void *WriterCtx, ValueProfData **ValueDataArray, @@ -53,64 +111,28 @@ COMPILER_RT_VISIBILITY int llvmWriteProfData(WriterCallback Writer, static int writeValueProfData(WriterCallback Writer, void *WriterCtx, ValueProfData **ValueDataBegin, uint64_t NumVData) { - ValueProfData **ValueDataArray = ValueDataBegin; - char *BufferStart = 0, *Buffer; - ValueProfData *CurVData; + ProfBufferIO *BufferIO; uint32_t I = 0, BufferSz; if (!ValueDataBegin) return 0; BufferSz = VPBufferSize ? VPBufferSize : VP_BUFFER_SIZE; - BufferStart = (char *)CallocHook(BufferSz, sizeof(uint8_t)); - if (!BufferStart) - return -1; + BufferIO = llvmCreateBufferIO(Writer, WriterCtx, BufferSz); - uint32_t WriteSize = 0; - Buffer = BufferStart; - do { - CurVData = ValueDataArray[I]; - if (!CurVData) { - I++; + for (I = 0; I < NumVData; I++) { + ValueProfData *CurVData = ValueDataBegin[I]; + if (!CurVData) continue; - } - - /* Buffer is full or not large enough, it is time to flush. */ - if (CurVData->TotalSize + WriteSize > BufferSz) { - if (WriteSize) { - ProfDataIOVec IO[] = {{BufferStart, sizeof(uint8_t), WriteSize}}; - if (Writer(IO, 1, &WriterCtx)) - return -1; - WriteSize = 0; - Buffer = BufferStart; - } - /* Special case, bypass the buffer completely. */ - if (CurVData->TotalSize > BufferSz) { - ProfDataIOVec IO[] = {{CurVData, sizeof(uint8_t), CurVData->TotalSize}}; - if (Writer(IO, 1, &WriterCtx)) - return -1; - FreeHook(ValueDataArray[I]); - I++; - } - } else { - /* Write the data to buffer */ - ProfDataIOVec IO[] = {{CurVData, sizeof(uint8_t), CurVData->TotalSize}}; - llvmBufferWriter(IO, 1, (void **)&Buffer); - WriteSize += CurVData->TotalSize; - FreeHook(ValueDataArray[I]); - I++; - } - } while (I < NumVData); - - /* Final flush. */ - if (WriteSize) { - ProfDataIOVec IO[] = {{BufferStart, sizeof(uint8_t), WriteSize}}; - if (Writer(IO, 1, &WriterCtx)) + if (llvmBufferIOWrite(BufferIO, (const uint8_t *)CurVData, + CurVData->TotalSize) != 0) return -1; } - FreeHook(ValueDataBegin); - FreeHook(BufferStart); + if (llvmBufferIOFlush(BufferIO) != 0) + return -1; + llvmDeleteBufferIO(BufferIO); + return 0; } diff --git a/compiler-rt/test/profile/instrprof-bufferio.c b/compiler-rt/test/profile/instrprof-bufferio.c new file mode 100644 index 00000000000..eed548fd0da --- /dev/null +++ b/compiler-rt/test/profile/instrprof-bufferio.c @@ -0,0 +1,128 @@ +// RUN: %clang_profgen -O3 -o %t %s +// RUN: %run %t %t.out.1 %t.out.2 %t.out.3 %t.out.4 +// RUN: cat %t.out.1 | FileCheck %s +// RUN: diff %t.out.1 %t.out.2 +// RUN: diff %t.out.2 %t.out.3 +// RUN: diff %t.out.3 %t.out.4 + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +typedef struct ProfBufferIO ProfBufferIO; +ProfBufferIO *llvmCreateBufferIOInternal(FILE *File, uint32_t DefaultBufferSz); +void llvmDeleteBufferIO(ProfBufferIO *BufferIO); + +int llvmBufferIOWrite(ProfBufferIO *BufferIO, const char *Data, uint32_t Size); +int llvmBufferIOFlush(ProfBufferIO *BufferIO); + +int __llvm_profile_runtime = 0; + +const char *SmallData = "ABC\n"; +const char *MediumData = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\n"; +char LargeData[10 * 1024]; +int main(int argc, const char *argv[]) { + ProfBufferIO *BufferIO; + FILE *File[4]; + uint32_t IOBufferSize[4] = {8, 128, 8 * 1024, 11 * 1024}; + int I, J; + if (argc < 5) + return 1; + + for (I = 0; I < 10 * 1024 - 2; I++) + LargeData[I] = 'A'; + + LargeData[I++] = '\n'; + LargeData[I++] = '\0'; + + for (J = 0; J < 4; J++) { + File[J] = fopen(argv[1 + J], "w"); + if (!File[J]) + return 1; + + BufferIO = llvmCreateBufferIOInternal(File[J], IOBufferSize[J]); + + llvmBufferIOWrite(BufferIO, "Short Strings:\n", strlen("Short Strings:\n")); + for (I = 0; I < 1024; I++) { + llvmBufferIOWrite(BufferIO, SmallData, strlen(SmallData)); + } + llvmBufferIOWrite(BufferIO, "Long Strings:\n", strlen("Long Strings:\n")); + for (I = 0; I < 1024; I++) { + llvmBufferIOWrite(BufferIO, MediumData, strlen(MediumData)); + } + llvmBufferIOWrite(BufferIO, "Extra Long Strings:\n", + strlen("Extra Long Strings:\n")); + for (I = 0; I < 10; I++) { + llvmBufferIOWrite(BufferIO, LargeData, strlen(LargeData)); + } + llvmBufferIOWrite(BufferIO, "Mixed Strings:\n", strlen("Mixed Strings:\n")); + for (I = 0; I < 1024; I++) { + llvmBufferIOWrite(BufferIO, MediumData, strlen(MediumData)); + llvmBufferIOWrite(BufferIO, SmallData, strlen(SmallData)); + } + llvmBufferIOWrite(BufferIO, "Endings:\n", strlen("Endings:\n")); + llvmBufferIOWrite(BufferIO, "END\n", strlen("END\n")); + llvmBufferIOWrite(BufferIO, "ENDEND\n", strlen("ENDEND\n")); + llvmBufferIOWrite(BufferIO, "ENDENDEND\n", strlen("ENDENDEND\n")); + llvmBufferIOWrite(BufferIO, "ENDENDENDEND\n", strlen("ENDENDENDEND\n")); + llvmBufferIOFlush(BufferIO); + + llvmDeleteBufferIO(BufferIO); + + fclose(File[J]); + } + return 0; +} + +// CHECK-LABEL: Short Strings: +// CHECK: ABC +// CHECK-NEXT: ABC +// CHECK-NEXT: ABC +// CHECK-NEXT: ABC +// CHECK-NEXT: ABC +// CHECK-NEXT: ABC +// CHECK-NEXT: ABC +// CHECK-NEXT: ABC +// CHECK-NEXT: ABC +// CHECK-NEXT: ABC +// CHECK-NEXT: ABC +// CHECK-NEXT: ABC +// CHECK-NEXT: ABC +// CHECK-NEXT: ABC +// CHECK-LABEL: Long Strings: +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-LABEL: Mixed Strings: +// CHECK: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABC +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABC +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABC +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABC +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABC +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABC +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABC +// CHECK-NEXT: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +// CHECK-NEXT: ABC +// CHECK-LABEL: Endings: +// CHECK: END +// CHECK-NEXT: ENDEND +// CHECK-NEXT: ENDENDEND +// CHECK-NEXT: ENDENDENDEND |