Skip to content

Commit

Permalink
[profile] Avoid allocating a page on the stack, NFC
Browse files Browse the repository at this point in the history
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
  • Loading branch information
vedantk committed Dec 11, 2019
1 parent d25437e commit 5a486e0
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 14 deletions.
12 changes: 12 additions & 0 deletions compiler-rt/lib/profile/InstrProfilingFile.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions compiler-rt/lib/profile/InstrProfilingInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/profile/InstrProfilingPlatformFuchsia.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
26 changes: 12 additions & 14 deletions compiler-rt/lib/profile/InstrProfilingWriter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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;

Expand Down

0 comments on commit 5a486e0

Please sign in to comment.