diff options
author | Xinliang David Li <davidxl@google.com> | 2015-11-10 00:24:45 +0000 |
---|---|---|
committer | Xinliang David Li <davidxl@google.com> | 2015-11-10 00:24:45 +0000 |
commit | ee4158957b6547ed180fb470d91c1ce22fffc06e (patch) | |
tree | 5c2f1d9cdd1e0ee9bdbfb95749471ac7212cd4b9 /llvm/lib/ProfileData | |
parent | 9d3e4f66513b760727df19df12380cb77e94435d (diff) | |
download | bcm5719-llvm-ee4158957b6547ed180fb470d91c1ce22fffc06e.tar.gz bcm5719-llvm-ee4158957b6547ed180fb470d91c1ce22fffc06e.zip |
[PGO] Make indexed value profile data more compact
- Make indexed value profile data more compact by peeling out
the per-site value count field into its own smaller sized array.
- Introduced formal data structure definitions to specify value
profile data layout in indexed format. Previously the layout
of the data is only assumed in the client code (scattered in
three different places : size computation, EmitData, and ReadData
- The new data structure serves as a central place for layout documentation.
- Add interfaces to force BE output for value profile data (testing purpose)
- Add byte swap unit tests
Differential Revision: http://reviews.llvm.org/D14401
llvm-svn: 252563
Diffstat (limited to 'llvm/lib/ProfileData')
-rw-r--r-- | llvm/lib/ProfileData/InstrProf.cpp | 228 | ||||
-rw-r--r-- | llvm/lib/ProfileData/InstrProfReader.cpp | 47 | ||||
-rw-r--r-- | llvm/lib/ProfileData/InstrProfWriter.cpp | 57 |
3 files changed, 248 insertions, 84 deletions
diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp index 377d77197d9..22c04fbf58e 100644 --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -128,4 +128,232 @@ GlobalVariable *createPGOFuncNameVar(Module &M, GlobalVariable *createPGOFuncNameVar(Function &F, StringRef FuncName) { return createPGOFuncNameVar(*F.getParent(), F.getLinkage(), FuncName); } + +namespace IndexedInstrProf { + +uint32_t ValueProfRecord::getHeaderSize(uint32_t NumValueSites) { + uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) + + sizeof(uint8_t) * NumValueSites; + // Round the size to multiple of 8 bytes. + Size = (Size + 7) & ~7; + return Size; +} + +uint32_t ValueProfRecord::getSize(uint32_t NumValueSites, + uint32_t NumValueData) { + return getHeaderSize(NumValueSites) + + sizeof(InstrProfValueData) * NumValueData; +} + +void ValueProfRecord::deserializeTo(InstrProfRecord &Record, + InstrProfRecord::ValueMapType *VMap) { + Record.reserveSites(Kind, NumValueSites); + + InstrProfValueData *ValueData = this->getValueData(); + for (uint64_t VSite = 0; VSite < NumValueSites; ++VSite) { + uint8_t ValueDataCount = this->SiteCountArray[VSite]; + Record.addValueData(Kind, VSite, ValueData, ValueDataCount, VMap); + ValueData += ValueDataCount; + } +} + +void ValueProfRecord::serializeFrom(const InstrProfRecord &Record, + uint32_t ValueKind, + uint32_t NumValueSites) { + Kind = ValueKind; + this->NumValueSites = NumValueSites; + InstrProfValueData *DstVD = getValueData(); + for (uint32_t S = 0; S < NumValueSites; S++) { + uint32_t ND = Record.getNumValueDataForSite(ValueKind, S); + SiteCountArray[S] = ND; + std::unique_ptr<InstrProfValueData[]> SrcVD = + Record.getValueForSite(ValueKind, S); + for (uint32_t I = 0; I < ND; I++) { + DstVD[I] = SrcVD[I]; + switch (ValueKind) { + case IPVK_IndirectCallTarget: + DstVD[I].Value = ComputeHash(HashType, (const char *)DstVD[I].Value); + break; + default: + llvm_unreachable("value kind not handled !"); + } + } + DstVD += ND; + } +} + +template <class T> static T swapToHostOrder(T v, support::endianness Orig) { + if (Orig == getHostEndianness()) + return v; + sys::swapByteOrder<T>(v); + return v; +} + +// For writing/serializing, Old is the host endianness, and New is +// byte order intended on disk. For Reading/deserialization, Old +// is the on-disk source endianness, and New is the host endianness. +void ValueProfRecord::swapBytes(support::endianness Old, + support::endianness New) { + using namespace support; + if (Old == New) + return; + + if (getHostEndianness() != Old) { + sys::swapByteOrder<uint32_t>(NumValueSites); + sys::swapByteOrder<uint32_t>(Kind); + } + uint32_t ND = getNumValueData(); + InstrProfValueData *VD = getValueData(); + + // No need to swap byte array: SiteCountArrray. + for (uint32_t I = 0; I < ND; I++) { + sys::swapByteOrder<uint64_t>(VD[I].Value); + sys::swapByteOrder<uint64_t>(VD[I].Count); + } + if (getHostEndianness() == Old) { + sys::swapByteOrder<uint32_t>(NumValueSites); + sys::swapByteOrder<uint32_t>(Kind); + } +} + +uint32_t ValueProfData::getSize(const InstrProfRecord &Record) { + uint32_t TotalSize = sizeof(ValueProfData); + uint32_t NumValueKinds = Record.getNumValueKinds(); + if (NumValueKinds == 0) + return TotalSize; + + for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; Kind++) { + uint32_t NumValueSites = Record.getNumValueSites(Kind); + if (!NumValueSites) + continue; + TotalSize += + ValueProfRecord::getSize(NumValueSites, Record.getNumValueData(Kind)); + } + return TotalSize; +} + +void ValueProfData::deserializeTo(InstrProfRecord &Record, + InstrProfRecord::ValueMapType *VMap) { + if (NumValueKinds == 0) + return; + + ValueProfRecord *VR = getFirstValueProfRecord(); + for (uint32_t K = 0; K < NumValueKinds; K++) { + VR->deserializeTo(Record, VMap); + VR = VR->getNext(); + } +} + +std::unique_ptr<ValueProfData> +ValueProfData::serializeFrom(const InstrProfRecord &Record) { + uint32_t TotalSize = getSize(Record); + std::unique_ptr<ValueProfData> VPD( + reinterpret_cast<ValueProfData *>(new char[TotalSize])); + + VPD->TotalSize = TotalSize; + VPD->NumValueKinds = Record.getNumValueKinds(); + ValueProfRecord *VR = VPD->getFirstValueProfRecord(); + for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; Kind++) { + uint32_t NumValueSites = Record.getNumValueSites(Kind); + if (!NumValueSites) + continue; + VR->serializeFrom(Record, Kind, NumValueSites); + VR = VR->getNext(); + } + return VPD; +} + +ErrorOr<std::unique_ptr<ValueProfData>> +ValueProfData::getValueProfData(const unsigned char *D, + const unsigned char *const BufferEnd, + support::endianness Endianness) { + using namespace support; + if (D + sizeof(ValueProfData) > BufferEnd) + return instrprof_error::truncated; + + uint32_t TotalSize = swapToHostOrder<uint32_t>( + reinterpret_cast<const uint32_t *>(D)[0], Endianness); + uint32_t NumValueKinds = swapToHostOrder<uint32_t>( + reinterpret_cast<const uint32_t *>(D)[1], Endianness); + + if (D + TotalSize > BufferEnd) + return instrprof_error::too_large; + if (NumValueKinds > IPVK_Last + 1) + return instrprof_error::malformed; + // Total size needs to be mulltiple of quadword size. + if (TotalSize % sizeof(uint64_t)) + return instrprof_error::malformed; + + std::unique_ptr<ValueProfData> VPD( + reinterpret_cast<ValueProfData *>(new char[TotalSize])); + memcpy(VPD.get(), D, TotalSize); + // Byte swap. + VPD->swapBytesToHost(Endianness); + + // Data integrety check: + ValueProfRecord *VR = VPD->getFirstValueProfRecord(); + for (uint32_t K = 0; K < VPD->NumValueKinds; K++) { + if (VR->Kind > IPVK_Last) + return instrprof_error::malformed; + VR = VR->getNext(); + if ((char *)VR - (char *)VPD.get() > TotalSize) + return instrprof_error::malformed; + } + + D += TotalSize; + return std::move(VPD); +} + +void ValueProfData::swapBytesToHost(support::endianness Endianness) { + using namespace support; + if (Endianness == getHostEndianness()) + return; + + sys::swapByteOrder<uint32_t>(TotalSize); + sys::swapByteOrder<uint32_t>(NumValueKinds); + + ValueProfRecord *VR = getFirstValueProfRecord(); + for (uint32_t K = 0; K < NumValueKinds; K++) { + VR->swapBytes(Endianness, getHostEndianness()); + VR = VR->getNext(); + } +} + +void ValueProfData::swapBytesFromHost(support::endianness Endianness) { + using namespace support; + if (Endianness == getHostEndianness()) + return; + + ValueProfRecord *VR = getFirstValueProfRecord(); + for (uint32_t K = 0; K < NumValueKinds; K++) { + ValueProfRecord *NVR = VR->getNext(); + VR->swapBytes(getHostEndianness(), Endianness); + VR = NVR; + } + sys::swapByteOrder<uint32_t>(TotalSize); + sys::swapByteOrder<uint32_t>(NumValueKinds); +} + +ValueProfRecord *ValueProfData::getFirstValueProfRecord() { + return reinterpret_cast<ValueProfRecord *>((char *)this + + sizeof(ValueProfData)); +} + +uint32_t ValueProfRecord::getNumValueData() const { + uint32_t NumValueData = 0; + for (uint32_t I = 0; I < NumValueSites; I++) + NumValueData += SiteCountArray[I]; + return NumValueData; +} + +ValueProfRecord *ValueProfRecord::getNext() { + return reinterpret_cast<ValueProfRecord *>((char *)this + getSize()); +} + +InstrProfValueData *ValueProfRecord::getValueData() { + return reinterpret_cast<InstrProfValueData *>((char *)this + + getHeaderSize(NumValueSites)); +} + +} // End of IndexedInstrProf namespace. } diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp index 66fd961c84f..b968e6beafc 100644 --- a/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/llvm/lib/ProfileData/InstrProfReader.cpp @@ -298,51 +298,16 @@ typedef InstrProfLookupTrait::offset_type offset_type; bool InstrProfLookupTrait::ReadValueProfilingData( const unsigned char *&D, const unsigned char *const End) { + ErrorOr<std::unique_ptr<IndexedInstrProf::ValueProfData>> VDataPtrOrErr = + IndexedInstrProf::ValueProfData::getValueProfData( + D, End, ValueProfDataEndianness); - using namespace support; - // Read number of value kinds with value sites. - if (D + sizeof(uint64_t) > End) + if (VDataPtrOrErr.getError()) return false; - uint64_t ValueKindCount = endian::readNext<uint64_t, little, unaligned>(D); - - InstrProfRecord &ProfRecord = DataBuffer.back(); - for (uint32_t Kind = 0; Kind < ValueKindCount; ++Kind) { - - // Read value kind and number of value sites for kind. - if (D + 2 * sizeof(uint64_t) > End) - return false; - - uint64_t ValueKind = endian::readNext<uint64_t, little, unaligned>(D); - uint64_t ValueSiteCount = endian::readNext<uint64_t, little, unaligned>(D); - ProfRecord.reserveSites(ValueKind, ValueSiteCount); + VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), &HashKeys); + D += VDataPtrOrErr.get()->TotalSize; - for (uint64_t VSite = 0; VSite < ValueSiteCount; ++VSite) { - // Read number of value data pairs at value site. - if (D + sizeof(uint64_t) > End) - return false; - - uint64_t ValueDataCount = - endian::readNext<uint64_t, little, unaligned>(D); - - // Check if there are as many ValueDataPairs as ValueDataCount in memory. - if (D + (ValueDataCount << 1) * sizeof(uint64_t) > End) - return false; - - std::unique_ptr<InstrProfValueData[]> VDataPtr( - ValueDataCount == 0 ? nullptr - : new InstrProfValueData[ValueDataCount]); - - for (uint64_t VCount = 0; VCount < ValueDataCount; ++VCount) { - VDataPtr[VCount].Value = - endian::readNext<uint64_t, little, unaligned>(D); - VDataPtr[VCount].Count = - endian::readNext<uint64_t, little, unaligned>(D); - } - ProfRecord.addValueData(ValueKind, VSite, VDataPtr.get(), ValueDataCount, - &HashKeys); - } - } return true; } diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp index b073d8df918..b6725df5278 100644 --- a/llvm/lib/ProfileData/InstrProfWriter.cpp +++ b/llvm/lib/ProfileData/InstrProfWriter.cpp @@ -20,6 +20,8 @@ using namespace llvm; namespace { +static support::endianness ValueProfDataEndianness = support::little; + class InstrProfRecordTrait { public: typedef StringRef key_type; @@ -51,20 +53,7 @@ public: M += ProfRecord.Counts.size() * sizeof(uint64_t); // Value data - M += sizeof(uint64_t); // Number of value kinds with value sites. - for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) { - uint32_t NumValueSites = ProfRecord.getNumValueSites(Kind); - if (NumValueSites == 0) - continue; - M += sizeof(uint64_t); // Value kind - M += sizeof(uint64_t); // The number of value sites for given value kind - for (uint32_t I = 0; I < NumValueSites; I++) { - M += sizeof(uint64_t); // Number of value data pairs at a value site - uint64_t NumValueDataForSite = - ProfRecord.getNumValueDataForSite(Kind, I); - M += 2 * sizeof(uint64_t) * NumValueDataForSite; // Value data pairs - } - } + M += IndexedInstrProf::ValueProfData::getSize(ProfileData.second); } LE.write<offset_type>(M); @@ -87,36 +76,12 @@ public: for (uint64_t I : ProfRecord.Counts) LE.write<uint64_t>(I); - // Compute the number of value kinds with value sites. - uint64_t NumValueKinds = ProfRecord.getNumValueKinds(); - LE.write<uint64_t>(NumValueKinds); - // Write value data - for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) { - uint32_t NumValueSites = ProfRecord.getNumValueSites(Kind); - if (NumValueSites == 0) - continue; - LE.write<uint64_t>(Kind); // Write value kind - // Write number of value sites for current value kind - LE.write<uint64_t>(NumValueSites); - - for (uint32_t I = 0; I < NumValueSites; I++) { - // Write number of value data pairs at this value site - uint64_t NumValueDataForSite = - ProfRecord.getNumValueDataForSite(Kind, I); - LE.write<uint64_t>(NumValueDataForSite); - std::unique_ptr<InstrProfValueData[]> VD = - ProfRecord.getValueForSite(Kind, I); - - for (uint32_t V = 0; V < NumValueDataForSite; V++) { - if (Kind == IPVK_IndirectCallTarget) - LE.write<uint64_t>(ComputeHash((const char *)VD[V].Value)); - else - LE.write<uint64_t>(VD[V].Value); - LE.write<uint64_t>(VD[V].Count); - } - } - } + std::unique_ptr<IndexedInstrProf::ValueProfData> VDataPtr = + IndexedInstrProf::ValueProfData::serializeFrom(ProfileData.second); + uint32_t S = VDataPtr->getSize(); + VDataPtr->swapBytesFromHost(ValueProfDataEndianness); + Out.write((const char *)VDataPtr.get(), S); } } }; @@ -148,6 +113,12 @@ static std::error_code combineInstrProfRecords(InstrProfRecord &Dest, return instrprof_error::success; } +// Internal interface for testing purpose only. +void InstrProfWriter::setValueProfDataEndianness( + support::endianness Endianness) { + ValueProfDataEndianness = Endianness; +} + void InstrProfWriter::updateStringTableReferences(InstrProfRecord &I) { I.updateStrings(&StringTable); } |