X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FProfileData%2FInstrProfWriter.cpp;h=07667e1221e828154cfc621c0ecba5af42d586ab;hp=2188543ed61c3002f93825dddca18940026b8534;hb=4f87d1237a5336568da44bc23d5654b1ed2168ff;hpb=09e5af7d611387f03e7c5051ef44420e4ee0c6e9 diff --git a/lib/ProfileData/InstrProfWriter.cpp b/lib/ProfileData/InstrProfWriter.cpp index 2188543ed61..07667e1221e 100644 --- a/lib/ProfileData/InstrProfWriter.cpp +++ b/lib/ProfileData/InstrProfWriter.cpp @@ -13,27 +13,29 @@ //===----------------------------------------------------------------------===// #include "llvm/ProfileData/InstrProfWriter.h" -#include "InstrProfIndexed.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/OnDiskHashTable.h" +#include using namespace llvm; namespace { +static support::endianness ValueProfDataEndianness = support::little; + class InstrProfRecordTrait { public: typedef StringRef key_type; typedef StringRef key_type_ref; - typedef const InstrProfWriter::CounterData *const data_type; - typedef const InstrProfWriter::CounterData *const data_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(IndexedInstrProf::HashType, K); + return IndexedInstrProf::ComputeHash(K); } static std::pair @@ -45,8 +47,15 @@ public: LE.write(N); offset_type M = 0; - for (const auto &Counts : *V) - M += (2 + Counts.second.size()) * sizeof(uint64_t); + 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); @@ -60,50 +69,60 @@ public: offset_type) { using namespace llvm::support; endian::Writer LE(Out); + for (const auto &ProfileData : *V) { + const InstrProfRecord &ProfRecord = ProfileData.second; - for (const auto &Counts : *V) { - LE.write(Counts.first); - LE.write(Counts.second.size()); - for (uint64_t I : Counts.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); } } }; } -std::error_code -InstrProfWriter::addFunctionCounts(StringRef FunctionName, - uint64_t FunctionHash, - ArrayRef Counters) { - auto &CounterData = FunctionData[FunctionName]; +// 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; - auto Where = CounterData.find(FunctionHash); - if (Where == CounterData.end()) { + instrprof_error Result = instrprof_error::success; + if (NewFunc) { // We've never seen a function with this name and hash, add it. - CounterData[FunctionHash] = Counters; - // We keep track of the max function count as we go for simplicity. - if (Counters[0] > MaxFunctionCount) - MaxFunctionCount = Counters[0]; - return instrprof_error::success; + 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're updating a function we've seen before. - auto &FoundCounters = Where->second; - // If the number of counters doesn't match we either have bad data or a hash - // collision. - if (FoundCounters.size() != Counters.size()) - return instrprof_error::count_mismatch; - - for (size_t I = 0, E = Counters.size(); I < E; ++I) { - if (FoundCounters[I] + Counters[I] < FoundCounters[I]) - return instrprof_error::counter_overflow; - FoundCounters[I] += Counters[I]; - } // We keep track of the max function count as we go for simplicity. - if (FoundCounters[0] > MaxFunctionCount) - MaxFunctionCount = FoundCounters[0]; + // Update this statistic no matter the result of the merge. + if (Dest.Counts[0] > MaxFunctionCount) + MaxFunctionCount = Dest.Counts[0]; - return instrprof_error::success; + return Result; } std::pair InstrProfWriter::writeImpl(raw_ostream &OS) { @@ -117,13 +136,23 @@ std::pair InstrProfWriter::writeImpl(raw_ostream &OS) { endian::Writer LE(OS); // Write the header. - LE.write(IndexedInstrProf::Magic); - LE.write(IndexedInstrProf::Version); - LE.write(MaxFunctionCount); - LE.write(static_cast(IndexedInstrProf::HashType)); + 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); @@ -138,9 +167,65 @@ void InstrProfWriter::write(raw_fd_ostream &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);