Commit 5a486e0f authored by Vedant Kumar's avatar Vedant Kumar
Browse files

[profile] Avoid allocating a page on the stack, NFC

When writing out a profile, avoid allocating a page on the stack for the
purpose of writing out zeroes, as some embedded environments do not have
enough stack space to accomodate this.

Instead, use a small, fixed-size zero buffer that can be written
repeatedly.

For a synthetic file with >100,000 functions, I did not measure a
significant difference in profile write times. We are removing a
page-length zero-fill `memset()` in favor of several smaller buffered
`fwrite()` calls: in practice, I am not sure there is much of a
difference. The performance impact is only expected to affect the
continuous sync mode (%c) -- zero padding is less than 8 bytes in all
other cases.

rdar://57810014

Differential Revision: https://reviews.llvm.org/D71323
parent d25437e9
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -122,11 +122,23 @@ static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
                           uint32_t NumIOVecs) {
  uint32_t I;
  FILE *File = (FILE *)This->WriterCtx;
  char Zeroes[sizeof(uint64_t)] = {0};
  for (I = 0; I < NumIOVecs; I++) {
    if (IOVecs[I].Data) {
      if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
          IOVecs[I].NumElm)
        return 1;
    } else if (IOVecs[I].UseZeroPadding) {
      size_t BytesToWrite = IOVecs[I].ElmSize * IOVecs[I].NumElm;
      while (BytesToWrite > 0) {
        size_t PartialWriteLen =
            (sizeof(uint64_t) > BytesToWrite) ? BytesToWrite : sizeof(uint64_t);
        if (fwrite(Zeroes, sizeof(uint8_t), PartialWriteLen, File) !=
            PartialWriteLen) {
          return 1;
        }
        BytesToWrite -= PartialWriteLen;
      }
    } else {
      if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1)
        return 1;
+7 −0
Original line number Diff line number Diff line
@@ -41,11 +41,18 @@ int __llvm_profile_write_buffer_internal(
/*!
 * The data structure describing the data to be written by the
 * low level writer callback function.
 *
 * If \ref ProfDataIOVec.Data is null, and \ref ProfDataIOVec.UseZeroPadding is
 * 0, the write is skipped (the writer simply advances ElmSize*NumElm bytes).
 *
 * If \ref ProfDataIOVec.Data is null, and \ref ProfDataIOVec.UseZeroPadding is
 * nonzero, ElmSize*NumElm zero bytes are written.
 */
typedef struct ProfDataIOVec {
  const void *Data;
  size_t ElmSize;
  size_t NumElm;
  int UseZeroPadding;
} ProfDataIOVec;

struct ProfDataWriter;
+2 −0
Original line number Diff line number Diff line
@@ -128,6 +128,8 @@ static uint32_t lprofVMOWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
                             __llvm_profile_offset, Length);
      if (Status != ZX_OK)
        return -1;
    } else if (IOVecs[I].UseZeroPadding) {
      /* Resizing the VMO should zero fill. */
    }
    __llvm_profile_offset += Length;
  }
+12 −14
Original line number Diff line number Diff line
@@ -41,6 +41,9 @@ COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataWriter *This,
    size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;
    if (IOVecs[I].Data)
      memcpy(*Buffer, IOVecs[I].Data, Length);
    else if (IOVecs[I].UseZeroPadding) {
      /* Allocating the buffer should zero fill. */
    }
    *Buffer += Length;
  }
  return 0;
@@ -85,7 +88,7 @@ lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) {
      return -1;
  }
  /* Special case, bypass the buffer completely. */
  ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size}};
  ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size, 0}};
  if (Size > BufferIO->BufferSz) {
    if (BufferIO->FileWriter->Write(BufferIO->FileWriter, IO, 1))
      return -1;
@@ -104,7 +107,7 @@ lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) {
COMPILER_RT_VISIBILITY int lprofBufferIOFlush(ProfBufferIO *BufferIO) {
  if (BufferIO->CurOffset) {
    ProfDataIOVec IO[] = {
        {BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset}};
        {BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset, 0}};
    if (BufferIO->FileWriter->Write(BufferIO->FileWriter, IO, 1))
      return -1;
    BufferIO->CurOffset = 0;
@@ -259,11 +262,6 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
  const uint64_t CountersSize = CountersEnd - CountersBegin;
  const uint64_t NamesSize = NamesEnd - NamesBegin;

  /* Enough zeroes for padding. */
  unsigned PageSize = getpagesize();
  char *Zeroes = (char *)COMPILER_RT_ALLOCA(PageSize);
  memset(Zeroes, 0, PageSize);

  /* Create the header. */
  __llvm_profile_header Header;

@@ -284,13 +282,13 @@ lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,

  /* Write the data. */
  ProfDataIOVec IOVec[] = {
      {&Header, sizeof(__llvm_profile_header), 1},
      {DataBegin, sizeof(__llvm_profile_data), DataSize},
      {Zeroes, sizeof(uint8_t), PaddingBytesBeforeCounters},
      {CountersBegin, sizeof(uint64_t), CountersSize},
      {Zeroes, sizeof(uint8_t), PaddingBytesAfterCounters},
      {SkipNameDataWrite ? NULL : NamesBegin, sizeof(uint8_t), NamesSize},
      {Zeroes, sizeof(uint8_t), PaddingBytesAfterNames}};
      {&Header, sizeof(__llvm_profile_header), 1, 0},
      {DataBegin, sizeof(__llvm_profile_data), DataSize, 0},
      {NULL, sizeof(uint8_t), PaddingBytesBeforeCounters, 1},
      {CountersBegin, sizeof(uint64_t), CountersSize, 0},
      {NULL, sizeof(uint8_t), PaddingBytesAfterCounters, 1},
      {SkipNameDataWrite ? NULL : NamesBegin, sizeof(uint8_t), NamesSize, 0},
      {NULL, sizeof(uint8_t), PaddingBytesAfterNames, 1}};
  if (Writer->Write(Writer, IOVec, sizeof(IOVec) / sizeof(*IOVec)))
    return -1;