X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FProfileData%2FInstrProfWriter.cpp;h=07667e1221e828154cfc621c0ecba5af42d586ab;hp=3024f9676e329883c8c5f841ef98caadd1079a71;hb=4f87d1237a5336568da44bc23d5654b1ed2168ff;hpb=c61e1f53d97e35b9f75dabb7099f35eabffcce5b diff --git a/lib/ProfileData/InstrProfWriter.cpp b/lib/ProfileData/InstrProfWriter.cpp index 3024f9676e3..07667e1221e 100644 --- a/lib/ProfileData/InstrProfWriter.cpp +++ b/lib/ProfileData/InstrProfWriter.cpp @@ -13,48 +13,232 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/InstrProfWriter.h" -#include "llvm/Support/Endian.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/OnDiskHashTable.h" +#include using namespace llvm; -error_code InstrProfWriter::addFunctionCounts(StringRef FunctionName, - uint64_t FunctionHash, - ArrayRef Counters) { - auto Where = FunctionData.find(FunctionName); - if (Where == FunctionData.end()) { - // If this is the first time we've seen this function, just add it. - auto &Data = FunctionData[FunctionName]; - Data.Hash = FunctionHash; - Data.Counts = Counters; - return instrprof_error::success;; +namespace { +static support::endianness ValueProfDataEndianness = support::little; + +class InstrProfRecordTrait { +public: + typedef StringRef key_type; + typedef StringRef key_type_ref; + + typedef const InstrProfWriter::ProfilingData *const data_type; + typedef const InstrProfWriter::ProfilingData *const data_type_ref; + + typedef uint64_t hash_value_type; + typedef uint64_t offset_type; + + static hash_value_type ComputeHash(key_type_ref K) { + return IndexedInstrProf::ComputeHash(K); + } + + static std::pair + EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V) { + using namespace llvm::support; + endian::Writer LE(Out); + + offset_type N = K.size(); + LE.write(N); + + offset_type M = 0; + for (const auto &ProfileData : *V) { + const InstrProfRecord &ProfRecord = ProfileData.second; + M += sizeof(uint64_t); // The function hash + M += sizeof(uint64_t); // The size of the Counts vector + M += ProfRecord.Counts.size() * sizeof(uint64_t); + + // Value data + M += ValueProfData::getSize(ProfileData.second); + } + LE.write(M); + + return std::make_pair(N, M); } - auto &Data = Where->getValue(); - // We can only add to existing functions if they match, so we check the hash - // and number of counters. - if (Data.Hash != FunctionHash) - return instrprof_error::hash_mismatch; - if (Data.Counts.size() != Counters.size()) - return instrprof_error::count_mismatch; - // These match, add up the counters. - for (size_t I = 0, E = Counters.size(); I < E; ++I) { - if (Data.Counts[I] + Counters[I] < Data.Counts[I]) - return instrprof_error::counter_overflow; - Data.Counts[I] += Counters[I]; + static void EmitKey(raw_ostream &Out, key_type_ref K, offset_type N){ + Out.write(K.data(), N); } - return instrprof_error::success; + + static void EmitData(raw_ostream &Out, key_type_ref, data_type_ref V, + offset_type) { + using namespace llvm::support; + endian::Writer LE(Out); + for (const auto &ProfileData : *V) { + const InstrProfRecord &ProfRecord = ProfileData.second; + + LE.write(ProfileData.first); // Function hash + LE.write(ProfRecord.Counts.size()); + for (uint64_t I : ProfRecord.Counts) + LE.write(I); + + // Write value data + std::unique_ptr VDataPtr = + ValueProfData::serializeFrom(ProfileData.second); + uint32_t S = VDataPtr->getSize(); + VDataPtr->swapBytesFromHost(ValueProfDataEndianness); + Out.write((const char *)VDataPtr.get(), S); + } + } +}; +} + +// Internal interface for testing purpose only. +void InstrProfWriter::setValueProfDataEndianness( + support::endianness Endianness) { + ValueProfDataEndianness = Endianness; +} + +std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I, + uint64_t Weight) { + auto &ProfileDataMap = FunctionData[I.Name]; + + bool NewFunc; + ProfilingData::iterator Where; + std::tie(Where, NewFunc) = + ProfileDataMap.insert(std::make_pair(I.Hash, InstrProfRecord())); + InstrProfRecord &Dest = Where->second; + + instrprof_error Result = instrprof_error::success; + if (NewFunc) { + // We've never seen a function with this name and hash, add it. + Dest = std::move(I); + // Fix up the name to avoid dangling reference. + Dest.Name = FunctionData.find(Dest.Name)->getKey(); + if (Weight > 1) + Result = Dest.scale(Weight); + } else { + // We're updating a function we've seen before. + Result = Dest.merge(I, Weight); + } + + // We keep track of the max function count as we go for simplicity. + // Update this statistic no matter the result of the merge. + if (Dest.Counts[0] > MaxFunctionCount) + MaxFunctionCount = Dest.Counts[0]; + + return Result; } -void InstrProfWriter::write(raw_ostream &OS) { - // Write out the counts for each function. - for (const auto &I : FunctionData) { - StringRef Name = I.getKey(); - uint64_t Hash = I.getValue().Hash; - const std::vector &Counts = I.getValue().Counts; +std::pair InstrProfWriter::writeImpl(raw_ostream &OS) { + OnDiskChainedHashTableGenerator Generator; - OS << Name << "\n" << Hash << "\n" << Counts.size() << "\n"; - for (uint64_t Count : Counts) - OS << Count << "\n"; + // Populate the hash table generator. + for (const auto &I : FunctionData) + Generator.insert(I.getKey(), &I.getValue()); + + using namespace llvm::support; + endian::Writer LE(OS); + + // Write the header. + IndexedInstrProf::Header Header; + Header.Magic = IndexedInstrProf::Magic; + Header.Version = IndexedInstrProf::Version; + Header.MaxFunctionCount = MaxFunctionCount; + Header.HashType = static_cast(IndexedInstrProf::HashType); + Header.HashOffset = 0; + int N = sizeof(IndexedInstrProf::Header) / sizeof(uint64_t); + + // Only write out all the fields execpt 'HashOffset'. We need + // to remember the offset of that field to allow back patching + // later. + for (int I = 0; I < N - 1; I++) + LE.write(reinterpret_cast(&Header)[I]); + + // Save a space to write the hash table start location. + uint64_t HashTableStartLoc = OS.tell(); + // Reserve the space for HashOffset field. + LE.write(0); + // Write the hash table. + uint64_t HashTableStart = Generator.Emit(OS); + + return std::make_pair(HashTableStartLoc, HashTableStart); +} + +void InstrProfWriter::write(raw_fd_ostream &OS) { + // Write the hash table. + auto TableStart = writeImpl(OS); + + // Go back and fill in the hash table start. + using namespace support; + OS.seek(TableStart.first); + // Now patch the HashOffset field previously reserved. + endian::Writer(OS).write(TableStart.second); +} + +static const char *ValueProfKindStr[] = { +#define VALUE_PROF_KIND(Enumerator, Value) #Enumerator, +#include "llvm/ProfileData/InstrProfData.inc" +}; + +void InstrProfWriter::writeRecordInText(const InstrProfRecord &Func, + InstrProfSymtab &Symtab, + raw_fd_ostream &OS) { + OS << Func.Name << "\n"; + OS << "# Func Hash:\n" << Func.Hash << "\n"; + OS << "# Num Counters:\n" << Func.Counts.size() << "\n"; + OS << "# Counter Values:\n"; + for (uint64_t Count : Func.Counts) + OS << Count << "\n"; + + uint32_t NumValueKinds = Func.getNumValueKinds(); + if (!NumValueKinds) { OS << "\n"; + return; + } + + OS << "# Num Value Kinds:\n" << Func.getNumValueKinds() << "\n"; + for (uint32_t VK = 0; VK < IPVK_Last + 1; VK++) { + uint32_t NS = Func.getNumValueSites(VK); + if (!NS) + continue; + OS << "# ValueKind = " << ValueProfKindStr[VK] << ":\n" << VK << "\n"; + OS << "# NumValueSites:\n" << NS << "\n"; + for (uint32_t S = 0; S < NS; S++) { + uint32_t ND = Func.getNumValueDataForSite(VK, S); + OS << ND << "\n"; + std::unique_ptr VD = Func.getValueForSite(VK, S); + for (uint32_t I = 0; I < ND; I++) { + if (VK == IPVK_IndirectCallTarget) + OS << Symtab.getFuncName(VD[I].Value) << ":" << VD[I].Count << "\n"; + else + OS << VD[I].Value << ":" << VD[I].Count << "\n"; + } + } } + + OS << "\n"; +} + +void InstrProfWriter::writeText(raw_fd_ostream &OS) { + InstrProfSymtab Symtab; + for (const auto &I : FunctionData) + Symtab.addFuncName(I.getKey()); + Symtab.finalizeSymtab(); + + for (const auto &I : FunctionData) + for (const auto &Func : I.getValue()) + writeRecordInText(Func.second, Symtab, OS); +} + +std::unique_ptr InstrProfWriter::writeBuffer() { + std::string Data; + llvm::raw_string_ostream OS(Data); + // Write the hash table. + auto TableStart = writeImpl(OS); + OS.flush(); + + // Go back and fill in the hash table start. + using namespace support; + uint64_t Bytes = endian::byte_swap(TableStart.second); + Data.replace(TableStart.first, sizeof(uint64_t), (const char *)&Bytes, + sizeof(uint64_t)); + + // Return this in an aligned memory buffer. + return MemoryBuffer::getMemBufferCopy(Data); }