forked from OSchip/llvm-project
ProfileData: Allow multiple profiles in RawInstrProfReader
Allow multiple raw profiles to coexist in a single .profraw file, given the following conditions: - Zero padding at the end of or between profiles will be skipped. - Each profile must start with a valid header. - Mixing endianness or pointer sizes in concatenated profiles files is not allowed. This is needed to handle cases where a program's shared libraries are profiled as well as the main executable itself, as we'll need to emit each executable's counters. Combining the tables in the runtime would be expensive for the instrumented program. rdar://16918688 llvm-svn: 208938
This commit is contained in:
parent
c21d3d5f90
commit
a119f32344
|
@ -165,6 +165,7 @@ private:
|
|||
const ProfileData *DataEnd;
|
||||
const uint64_t *CountersStart;
|
||||
const char *NamesStart;
|
||||
const char *ProfileEnd;
|
||||
|
||||
RawInstrProfReader(const TextInstrProfReader &) LLVM_DELETED_FUNCTION;
|
||||
RawInstrProfReader &operator=(const TextInstrProfReader &)
|
||||
|
@ -178,6 +179,7 @@ public:
|
|||
error_code readNextRecord(InstrProfRecord &Record) override;
|
||||
|
||||
private:
|
||||
error_code readNextHeader(const char *CurrentPos);
|
||||
error_code readHeader(const RawHeader &Header);
|
||||
template <class IntT>
|
||||
IntT swap(IntT Int) const {
|
||||
|
|
|
@ -172,6 +172,29 @@ error_code RawInstrProfReader<IntPtrT>::readHeader() {
|
|||
return readHeader(*Header);
|
||||
}
|
||||
|
||||
template <class IntPtrT>
|
||||
error_code RawInstrProfReader<IntPtrT>::readNextHeader(const char *CurrentPos) {
|
||||
const char *End = DataBuffer->getBufferEnd();
|
||||
// Skip zero padding between profiles.
|
||||
while (CurrentPos != End && *CurrentPos == 0)
|
||||
++CurrentPos;
|
||||
// If there's nothing left, we're done.
|
||||
if (CurrentPos == End)
|
||||
return instrprof_error::eof;
|
||||
// If there isn't enough space for another header, this is probably just
|
||||
// garbage at the end of the file.
|
||||
if (CurrentPos + sizeof(RawHeader) > End)
|
||||
return instrprof_error::malformed;
|
||||
// The magic should have the same byte order as in the previous header.
|
||||
uint64_t Magic = *reinterpret_cast<const uint64_t *>(CurrentPos);
|
||||
if (Magic != swap(getRawMagic<IntPtrT>()))
|
||||
return instrprof_error::bad_magic;
|
||||
|
||||
// There's another profile to read, so we need to process the header.
|
||||
auto *Header = reinterpret_cast<const RawHeader *>(CurrentPos);
|
||||
return readHeader(*Header);
|
||||
}
|
||||
|
||||
static uint64_t getRawVersion() {
|
||||
return 1;
|
||||
}
|
||||
|
@ -190,16 +213,17 @@ error_code RawInstrProfReader<IntPtrT>::readHeader(const RawHeader &Header) {
|
|||
ptrdiff_t DataOffset = sizeof(RawHeader);
|
||||
ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize;
|
||||
ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize;
|
||||
size_t FileSize = NamesOffset + sizeof(char) * NamesSize;
|
||||
size_t ProfileSize = NamesOffset + sizeof(char) * NamesSize;
|
||||
|
||||
if (FileSize != DataBuffer->getBufferSize())
|
||||
auto *Start = reinterpret_cast<const char *>(&Header);
|
||||
if (Start + ProfileSize > DataBuffer->getBufferEnd())
|
||||
return error(instrprof_error::bad_header);
|
||||
|
||||
const char *Start = DataBuffer->getBufferStart();
|
||||
Data = reinterpret_cast<const ProfileData *>(Start + DataOffset);
|
||||
DataEnd = Data + DataSize;
|
||||
CountersStart = reinterpret_cast<const uint64_t *>(Start + CountersOffset);
|
||||
NamesStart = Start + NamesOffset;
|
||||
ProfileEnd = Start + ProfileSize;
|
||||
|
||||
return success();
|
||||
}
|
||||
|
@ -208,7 +232,8 @@ template <class IntPtrT>
|
|||
error_code
|
||||
RawInstrProfReader<IntPtrT>::readNextRecord(InstrProfRecord &Record) {
|
||||
if (Data == DataEnd)
|
||||
return error(instrprof_error::eof);
|
||||
if (error_code EC = readNextHeader(ProfileEnd))
|
||||
return EC;
|
||||
|
||||
// Get the raw data.
|
||||
StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize));
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
RUN: printf '\201rforpl\377' > %t-foo.profraw
|
||||
RUN: printf '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
|
||||
RUN: printf '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
|
||||
RUN: printf '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
|
||||
RUN: printf '\3\0\0\0\0\0\0\0' >> %t-foo.profraw
|
||||
RUN: printf '\0\0\4\0\1\0\0\0' >> %t-foo.profraw
|
||||
RUN: printf '\0\0\4\0\2\0\0\0' >> %t-foo.profraw
|
||||
|
||||
RUN: printf '\3\0\0\0' >> %t-foo.profraw
|
||||
RUN: printf '\1\0\0\0' >> %t-foo.profraw
|
||||
RUN: printf '\1\0\0\0\0\0\0\0' >> %t-foo.profraw
|
||||
RUN: printf '\0\0\4\0\2\0\0\0' >> %t-foo.profraw
|
||||
RUN: printf '\0\0\4\0\1\0\0\0' >> %t-foo.profraw
|
||||
|
||||
RUN: printf '\023\0\0\0\0\0\0\0' >> %t-foo.profraw
|
||||
RUN: printf 'foo' >> %t-foo.profraw
|
||||
|
||||
RUN: printf '\201rforpl\377' > %t-bar.profraw
|
||||
RUN: printf '\1\0\0\0\0\0\0\0' >> %t-bar.profraw
|
||||
RUN: printf '\1\0\0\0\0\0\0\0' >> %t-bar.profraw
|
||||
RUN: printf '\2\0\0\0\0\0\0\0' >> %t-bar.profraw
|
||||
RUN: printf '\3\0\0\0\0\0\0\0' >> %t-bar.profraw
|
||||
RUN: printf '\0\0\6\0\1\0\0\0' >> %t-bar.profraw
|
||||
RUN: printf '\0\0\6\0\2\0\0\0' >> %t-bar.profraw
|
||||
|
||||
RUN: printf '\3\0\0\0' >> %t-bar.profraw
|
||||
RUN: printf '\2\0\0\0' >> %t-bar.profraw
|
||||
RUN: printf '\2\0\0\0\0\0\0\0' >> %t-bar.profraw
|
||||
RUN: printf '\0\0\6\0\2\0\0\0' >> %t-bar.profraw
|
||||
RUN: printf '\0\0\6\0\1\0\0\0' >> %t-bar.profraw
|
||||
|
||||
RUN: printf '\067\0\0\0\0\0\0\0' >> %t-bar.profraw
|
||||
RUN: printf '\101\0\0\0\0\0\0\0' >> %t-bar.profraw
|
||||
RUN: printf 'bar' >> %t-bar.profraw
|
||||
|
||||
Versions of the profiles that are padded to eight byte alignment.
|
||||
RUN: cat %t-foo.profraw > %t-foo-padded.profraw
|
||||
RUN: printf '\0\0\0\0\0' >> %t-foo-padded.profraw
|
||||
RUN: cat %t-bar.profraw > %t-bar-padded.profraw
|
||||
RUN: printf '\0\0\0\0\0' >> %t-bar-padded.profraw
|
||||
|
||||
RUN: cat %t-foo.profraw %t-bar.profraw > %t-nopad.profraw
|
||||
RUN: cat %t-foo-padded.profraw %t-bar.profraw > %t-pad-between.profraw
|
||||
RUN: cat %t-foo-padded.profraw %t-bar-padded.profraw > %t-pad.profraw
|
||||
|
||||
RUN: llvm-profdata show %t-nopad.profraw -all-functions -counts | FileCheck %s
|
||||
RUN: llvm-profdata show %t-pad-between.profraw -all-functions -counts | FileCheck %s
|
||||
RUN: llvm-profdata show %t-pad.profraw -all-functions -counts | FileCheck %s
|
||||
|
||||
CHECK: Counters:
|
||||
CHECK: foo:
|
||||
CHECK: Hash: 0x0000000000000001
|
||||
CHECK: Counters: 1
|
||||
CHECK: Function count: 19
|
||||
CHECK: Block counts: []
|
||||
CHECK: bar:
|
||||
CHECK: Hash: 0x0000000000000002
|
||||
CHECK: Counters: 2
|
||||
CHECK: Function count: 55
|
||||
CHECK: Block counts: [65]
|
||||
CHECK: Functions shown: 2
|
||||
CHECK: Total functions: 2
|
||||
CHECK: Maximum function count: 55
|
||||
CHECK: Maximum internal block count: 65
|
Loading…
Reference in New Issue