diff options
-rw-r--r-- | llvm/include/llvm/ProfileData/InstrProf.h | 105 | ||||
-rw-r--r-- | llvm/include/llvm/ProfileData/InstrProfReader.h | 10 | ||||
-rw-r--r-- | llvm/include/llvm/ProfileData/InstrProfWriter.h | 15 | ||||
-rw-r--r-- | llvm/lib/ProfileData/InstrProf.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/ProfileData/InstrProfIndexed.h | 2 | ||||
-rw-r--r-- | llvm/lib/ProfileData/InstrProfReader.cpp | 110 | ||||
-rw-r--r-- | llvm/lib/ProfileData/InstrProfWriter.cpp | 148 | ||||
-rw-r--r-- | llvm/tools/llvm-profdata/llvm-profdata.cpp | 29 | ||||
-rw-r--r-- | llvm/unittests/ProfileData/CoverageMappingTest.cpp | 12 | ||||
-rw-r--r-- | llvm/unittests/ProfileData/InstrProfTest.cpp | 18 |
10 files changed, 358 insertions, 93 deletions
diff --git a/llvm/include/llvm/ProfileData/InstrProf.h b/llvm/include/llvm/ProfileData/InstrProf.h index 77055ba8726..49780e4abab 100644 --- a/llvm/include/llvm/ProfileData/InstrProf.h +++ b/llvm/include/llvm/ProfileData/InstrProf.h @@ -16,8 +16,10 @@ #ifndef LLVM_PROFILEDATA_INSTRPROF_H_ #define LLVM_PROFILEDATA_INSTRPROF_H_ -#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/ErrorHandling.h" #include <cstdint> +#include <list> #include <system_error> #include <vector> @@ -25,25 +27,84 @@ namespace llvm { const std::error_category &instrprof_category(); enum class instrprof_error { - success = 0, - eof, - bad_magic, - bad_header, - unsupported_version, - unsupported_hash_type, - too_large, - truncated, - malformed, - unknown_function, - hash_mismatch, - count_mismatch, - counter_overflow + success = 0, + eof, + bad_magic, + bad_header, + unsupported_version, + unsupported_hash_type, + too_large, + truncated, + malformed, + unknown_function, + hash_mismatch, + count_mismatch, + counter_overflow, + value_site_count_mismatch }; inline std::error_code make_error_code(instrprof_error E) { return std::error_code(static_cast<int>(E), instrprof_category()); } +enum InstrProfValueKind : uint32_t { + IPVK_IndirectCallTarget = 0, + + IPVK_First = IPVK_IndirectCallTarget, + IPVK_Last = IPVK_IndirectCallTarget +}; + +struct InstrProfStringTable { + // Set of string values in profiling data. + StringSet<> StringValueSet; + InstrProfStringTable() { StringValueSet.clear(); } + // Get a pointer to internal storage of a string in set + const char *getStringData(StringRef Str) { + auto Result = StringValueSet.find(Str); + return (Result == StringValueSet.end()) ? nullptr : Result->first().data(); + } + // Insert a string to StringTable + const char *insertString(StringRef Str) { + auto Result = StringValueSet.insert(Str); + return Result.first->first().data(); + } +}; + +struct InstrProfValueSiteRecord { + /// Typedef for a single TargetValue-NumTaken pair. + typedef std::pair<uint64_t, uint64_t> ValueDataPair; + /// Value profiling data pairs at a given value site. + std::list<ValueDataPair> ValueData; + + InstrProfValueSiteRecord() { ValueData.clear(); } + + /// Sort ValueData ascending by TargetValue + void sortByTargetValues() { + ValueData.sort([](const ValueDataPair &left, const ValueDataPair &right) { + return left.first < right.first; + }); + } + + /// Merge data from another InstrProfValueSiteRecord + void mergeValueData(InstrProfValueSiteRecord &Input) { + this->sortByTargetValues(); + Input.sortByTargetValues(); + auto I = ValueData.begin(); + auto IE = ValueData.end(); + for (auto J = Input.ValueData.begin(), JE = Input.ValueData.end(); J != JE; + ++J) { + while (I != IE && I->first < J->first) + ++I; + if (I != IE && I->first == J->first) { + I->second += J->second; + ++I; + continue; + } + ValueData.insert(I, *J); + } + } +}; + /// Profiling information for a single function. struct InstrProfRecord { InstrProfRecord() {} @@ -52,6 +113,22 @@ struct InstrProfRecord { StringRef Name; uint64_t Hash; std::vector<uint64_t> Counts; + std::vector<InstrProfValueSiteRecord> IndirectCallSites; + + const std::vector<InstrProfValueSiteRecord> & + getValueSitesForKind(uint32_t ValueKind) const { + switch (ValueKind) { + case IPVK_IndirectCallTarget: + return IndirectCallSites; + } + llvm_unreachable("Unknown value kind!"); + } + + std::vector<InstrProfValueSiteRecord> & + getValueSitesForKind(uint32_t ValueKind) { + return const_cast<std::vector<InstrProfValueSiteRecord> &>( + this->getValueSitesForKind(ValueKind)); + } }; } // end namespace llvm diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h index f937e7d08d5..c0585d6f6d2 100644 --- a/llvm/include/llvm/ProfileData/InstrProfReader.h +++ b/llvm/include/llvm/ProfileData/InstrProfReader.h @@ -65,6 +65,9 @@ public: InstrProfIterator end() { return InstrProfIterator(); } protected: + /// String table for holding a unique copy of all the strings in the profile. + InstrProfStringTable StringTable; + /// Set the current std::error_code and return same. std::error_code error(std::error_code EC) { LastError = EC; @@ -195,6 +198,7 @@ class InstrProfLookupTrait { std::vector<InstrProfRecord> DataBuffer; IndexedInstrProf::HashT HashType; unsigned FormatVersion; + std::vector<std::pair<uint64_t, const char *>> HashKeys; public: InstrProfLookupTrait(IndexedInstrProf::HashT HashType, unsigned FormatVersion) @@ -209,9 +213,13 @@ public: static bool EqualKey(StringRef A, StringRef B) { return A == B; } static StringRef GetInternalKey(StringRef K) { return K; } + static StringRef GetExternalKey(StringRef K) { return K; } hash_value_type ComputeHash(StringRef K); + void setHashKeys(std::vector<std::pair<uint64_t, const char *>> HashKeys) { + this->HashKeys = std::move(HashKeys); + } static std::pair<offset_type, offset_type> ReadKeyDataLength(const unsigned char *&D) { using namespace support; @@ -224,6 +232,8 @@ public: return StringRef((const char *)D, N); } + bool ReadValueProfilingData(const unsigned char *&D, + const unsigned char *const End); data_type ReadData(StringRef K, const unsigned char *D, offset_type N); }; diff --git a/llvm/include/llvm/ProfileData/InstrProfWriter.h b/llvm/include/llvm/ProfileData/InstrProfWriter.h index ce0bb524249..da0d956e8a9 100644 --- a/llvm/include/llvm/ProfileData/InstrProfWriter.h +++ b/llvm/include/llvm/ProfileData/InstrProfWriter.h @@ -15,33 +15,32 @@ #ifndef LLVM_PROFILEDATA_INSTRPROFWRITER_H #define LLVM_PROFILEDATA_INSTRPROFWRITER_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringMap.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" -#include <vector> namespace llvm { /// Writer for instrumentation based profile data. class InstrProfWriter { public: - typedef SmallDenseMap<uint64_t, std::vector<uint64_t>, 1> CounterData; + typedef SmallDenseMap<uint64_t, InstrProfRecord, 1> ProfilingData; + private: - StringMap<CounterData> FunctionData; + InstrProfStringTable StringTable; + StringMap<ProfilingData> FunctionData; uint64_t MaxFunctionCount; public: InstrProfWriter() : MaxFunctionCount(0) {} + /// Update string entries in profile data with references to StringTable. + void updateStringTableReferences(InstrProfRecord &I); /// Add function counts for the given function. If there are already counts /// for this function and the hash and number of counts match, each counter is /// summed. - std::error_code addFunctionCounts(StringRef FunctionName, - uint64_t FunctionHash, - ArrayRef<uint64_t> Counters); + std::error_code addRecord(InstrProfRecord &&I); /// Write the profile to \c OS void write(raw_fd_ostream &OS); /// Write the profile, returning the raw data. For testing. diff --git a/llvm/lib/ProfileData/InstrProf.cpp b/llvm/lib/ProfileData/InstrProf.cpp index 92822a71402..9652ba88483 100644 --- a/llvm/lib/ProfileData/InstrProf.cpp +++ b/llvm/lib/ProfileData/InstrProf.cpp @@ -50,6 +50,8 @@ class InstrProfErrorCategoryType : public std::error_category { return "Function count mismatch"; case instrprof_error::counter_overflow: return "Counter overflow"; + case instrprof_error::value_site_count_mismatch: + return "Function's value site counts mismatch"; } llvm_unreachable("A value of instrprof_error has no message."); } diff --git a/llvm/lib/ProfileData/InstrProfIndexed.h b/llvm/lib/ProfileData/InstrProfIndexed.h index ebca7b22fbf..fe0b04ed008 100644 --- a/llvm/lib/ProfileData/InstrProfIndexed.h +++ b/llvm/lib/ProfileData/InstrProfIndexed.h @@ -47,7 +47,7 @@ static inline uint64_t ComputeHash(HashT Type, StringRef K) { } const uint64_t Magic = 0x8169666f72706cff; // "\xfflprofi\x81" -const uint64_t Version = 2; +const uint64_t Version = 3; const HashT HashType = HashT::MD5; } diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp index 8a529a000c5..062c337d4ee 100644 --- a/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/llvm/lib/ProfileData/InstrProfReader.cpp @@ -302,42 +302,102 @@ InstrProfLookupTrait::ComputeHash(StringRef K) { typedef InstrProfLookupTrait::data_type data_type; typedef InstrProfLookupTrait::offset_type offset_type; +bool InstrProfLookupTrait::ReadValueProfilingData( + const unsigned char *&D, const unsigned char *const End) { + + using namespace support; + // Read number of value kinds with value sites. + if (D + sizeof(uint64_t) > End) + return false; + uint64_t ValueKindCount = endian::readNext<uint64_t, little, unaligned>(D); + + 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); + + std::vector<InstrProfValueSiteRecord> &ValueSites = + DataBuffer.back().getValueSitesForKind(ValueKind); + ValueSites.reserve(ValueSiteCount); + 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; + + InstrProfValueSiteRecord VSiteRecord; + for (uint64_t VCount = 0; VCount < ValueDataCount; ++VCount) { + uint64_t Value = endian::readNext<uint64_t, little, unaligned>(D); + uint64_t NumTaken = endian::readNext<uint64_t, little, unaligned>(D); + switch (ValueKind) { + case IPVK_IndirectCallTarget: { + auto Result = + std::lower_bound(HashKeys.begin(), HashKeys.end(), Value, + [](const std::pair<uint64_t, const char *> &LHS, + uint64_t RHS) { return LHS.first < RHS; }); + assert(Result != HashKeys.end() && + "Hash does not match any known keys\n"); + Value = (uint64_t)Result->second; + break; + } + } + VSiteRecord.ValueData.push_back(std::make_pair(Value, NumTaken)); + } + ValueSites.push_back(std::move(VSiteRecord)); + } + } + return true; +} + data_type InstrProfLookupTrait::ReadData(StringRef K, const unsigned char *D, offset_type N) { - // Check if the data is corrupt. If so, don't try to read it. if (N % sizeof(uint64_t)) return data_type(); DataBuffer.clear(); - uint64_t NumCounts; - uint64_t NumEntries = N / sizeof(uint64_t); std::vector<uint64_t> CounterBuffer; - for (uint64_t I = 0; I < NumEntries; I += NumCounts) { - using namespace support; - // The function hash comes first. - uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D); - if (++I >= NumEntries) + using namespace support; + const unsigned char *End = D + N; + while (D < End) { + // Read hash + if (D + sizeof(uint64_t) >= End) return data_type(); + uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D); - // In v1, we have at least one count. - // Later, we have the number of counts. - NumCounts = (1 == FormatVersion) - ? NumEntries - I - : endian::readNext<uint64_t, little, unaligned>(D); - if (1 != FormatVersion) - ++I; - - // If we have more counts than data, this is bogus. - if (I + NumCounts > NumEntries) + // Initialize number of counters for FormatVersion == 1 + uint64_t CountsSize = N / sizeof(uint64_t) - 1; + // If format version is different then read number of counters + if (FormatVersion != 1) { + if (D + sizeof(uint64_t) > End) + return data_type(); + CountsSize = endian::readNext<uint64_t, little, unaligned>(D); + } + // Read counter values + if (D + CountsSize * sizeof(uint64_t) > End) return data_type(); CounterBuffer.clear(); - for (unsigned J = 0; J < NumCounts; ++J) + CounterBuffer.reserve(CountsSize); + for (uint64_t J = 0; J < CountsSize; ++J) CounterBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D)); DataBuffer.push_back(InstrProfRecord(K, Hash, std::move(CounterBuffer))); + + // Read value profiling data + if (FormatVersion > 2 && !ReadValueProfilingData(D, End)) { + DataBuffer.clear(); + return data_type(); + } } return DataBuffer; } @@ -384,6 +444,18 @@ std::error_code IndexedInstrProfReader::readHeader() { Index.reset(InstrProfReaderIndex::Create( Start + HashOffset, Cur, Start, InstrProfLookupTrait(HashType, FormatVersion))); + + // Form the map of hash values to const char* keys in profiling data. + std::vector<std::pair<uint64_t, const char *>> HashKeys; + for (auto Key : Index->keys()) { + const char *KeyTableRef = StringTable.insertString(Key); + HashKeys.push_back(std::make_pair(ComputeHash(HashType, Key), KeyTableRef)); + } + std::sort(HashKeys.begin(), HashKeys.end(), less_first()); + std::unique(HashKeys.begin(), HashKeys.end(), less_first()); + HashKeys.erase(std::unique(HashKeys.begin(), HashKeys.end()), HashKeys.end()); + // Set the hash key map for the InstrLookupTrait + Index->getInfoObj().setHashKeys(std::move(HashKeys)); // Set up our iterator for readNextRecord. RecordIterator = Index->data_begin(); diff --git a/llvm/lib/ProfileData/InstrProfWriter.cpp b/llvm/lib/ProfileData/InstrProfWriter.cpp index 2188543ed61..856194d7776 100644 --- a/llvm/lib/ProfileData/InstrProfWriter.cpp +++ b/llvm/lib/ProfileData/InstrProfWriter.cpp @@ -26,8 +26,8 @@ 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; @@ -45,8 +45,26 @@ public: LE.write<offset_type>(N); offset_type M = 0; - for (const auto &Counts : *V) - M += (2 + Counts.second.size()) * sizeof(uint64_t); + for (const auto &ProfileData : *V) { + M += sizeof(uint64_t); // The function hash + M += sizeof(uint64_t); // The size of the Counts vector + M += ProfileData.second.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) { + const std::vector<InstrProfValueSiteRecord> &ValueSites = + ProfileData.second.getValueSitesForKind(Kind); + if (ValueSites.empty()) + continue; + M += sizeof(uint64_t); // Value kind + M += sizeof(uint64_t); // The number of value sites for given value kind + for (InstrProfValueSiteRecord I : ValueSites) { + M += sizeof(uint64_t); // Number of value data pairs at a value site + M += 2 * sizeof(uint64_t) * I.ValueData.size(); // Value data pairs + } + } + } LE.write<offset_type>(M); return std::make_pair(N, M); @@ -60,52 +78,114 @@ public: offset_type) { using namespace llvm::support; endian::Writer<little> LE(Out); - - for (const auto &Counts : *V) { - LE.write<uint64_t>(Counts.first); - LE.write<uint64_t>(Counts.second.size()); - for (uint64_t I : Counts.second) + for (const auto &ProfileData : *V) { + LE.write<uint64_t>(ProfileData.first); // Function hash + LE.write<uint64_t>(ProfileData.second.Counts.size()); + for (uint64_t I : ProfileData.second.Counts) LE.write<uint64_t>(I); + + // Compute the number of value kinds with value sites. + uint64_t NumValueKinds = 0; + for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) + NumValueKinds += + !(ProfileData.second.getValueSitesForKind(Kind).empty()); + LE.write<uint64_t>(NumValueKinds); + + // Write value data + for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) { + const std::vector<InstrProfValueSiteRecord> &ValueSites = + ProfileData.second.getValueSitesForKind(Kind); + if (ValueSites.empty()) + continue; + LE.write<uint64_t>(Kind); // Write value kind + // Write number of value sites for current value kind + LE.write<uint64_t>(ValueSites.size()); + for (InstrProfValueSiteRecord I : ValueSites) { + // Write number of value data pairs at this value site + LE.write<uint64_t>(I.ValueData.size()); + for (auto V : I.ValueData) { + if (Kind == IPVK_IndirectCallTarget) + LE.write<uint64_t>(ComputeHash((const char *)V.first)); + else + LE.write<uint64_t>(V.first); + LE.write<uint64_t>(V.second); + } + } + } } } }; } -std::error_code -InstrProfWriter::addFunctionCounts(StringRef FunctionName, - uint64_t FunctionHash, - ArrayRef<uint64_t> Counters) { - auto &CounterData = FunctionData[FunctionName]; +static std::error_code combineInstrProfRecords(InstrProfRecord &Dest, + InstrProfRecord &Source, + uint64_t &MaxFunctionCount) { + // If the number of counters doesn't match we either have bad data + // or a hash collision. + if (Dest.Counts.size() != Source.Counts.size()) + return instrprof_error::count_mismatch; - auto Where = CounterData.find(FunctionHash); - if (Where == CounterData.end()) { - // 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; + for (size_t I = 0, E = Source.Counts.size(); I < E; ++I) { + if (Dest.Counts[I] + Source.Counts[I] < Dest.Counts[I]) + return instrprof_error::counter_overflow; + Dest.Counts[I] += Source.Counts[I]; } - // 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 (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) { - 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]; + std::vector<InstrProfValueSiteRecord> &SourceValueSites = + Source.getValueSitesForKind(Kind); + if (SourceValueSites.empty()) + continue; + + std::vector<InstrProfValueSiteRecord> &DestValueSites = + Dest.getValueSitesForKind(Kind); + + if (DestValueSites.empty()) { + DestValueSites.swap(SourceValueSites); + continue; + } + + if (DestValueSites.size() != SourceValueSites.size()) + return instrprof_error::value_site_count_mismatch; + for (size_t I = 0, E = SourceValueSites.size(); I < E; ++I) + DestValueSites[I].mergeValueData(SourceValueSites[I]); } + // We keep track of the max function count as we go for simplicity. - if (FoundCounters[0] > MaxFunctionCount) - MaxFunctionCount = FoundCounters[0]; + if (Dest.Counts[0] > MaxFunctionCount) + MaxFunctionCount = Dest.Counts[0]; return instrprof_error::success; } +void InstrProfWriter::updateStringTableReferences(InstrProfRecord &I) { + I.Name = StringTable.insertString(I.Name); + for (auto &VSite : I.IndirectCallSites) + for (auto &VData : VSite.ValueData) + VData.first = + (uint64_t)StringTable.insertString((const char *)VData.first); +} + +std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I) { + updateStringTableReferences(I); + auto &ProfileDataMap = FunctionData[I.Name]; + + auto Where = ProfileDataMap.find(I.Hash); + if (Where == ProfileDataMap.end()) { + // We've never seen a function with this name and hash, add it. + ProfileDataMap[I.Hash] = I; + + // We keep track of the max function count as we go for simplicity. + if (I.Counts[0] > MaxFunctionCount) + MaxFunctionCount = I.Counts[0]; + return instrprof_error::success; + } + + // We're updating a function we've seen before. + return combineInstrProfRecords(Where->second, I, MaxFunctionCount); +} + std::pair<uint64_t, uint64_t> InstrProfWriter::writeImpl(raw_ostream &OS) { OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator; diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index 23fa7b40f50..fdf22c3642f 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -58,9 +58,8 @@ static void mergeInstrProfile(const cl::list<std::string> &Inputs, exitWithError(ec.message(), Filename); auto Reader = std::move(ReaderOrErr.get()); - for (const auto &I : *Reader) - if (std::error_code EC = - Writer.addFunctionCounts(I.Name, I.Hash, I.Counts)) + for (auto &I : *Reader) + if (std::error_code EC = Writer.addRecord(std::move(I))) errs() << Filename << ": " << I.Name << ": " << EC.message() << "\n"; if (Reader->hasError()) exitWithError(Reader->getError().message(), Filename); @@ -134,8 +133,8 @@ static int merge_main(int argc, const char *argv[]) { } static int showInstrProfile(std::string Filename, bool ShowCounts, - bool ShowAllFunctions, std::string ShowFunction, - raw_fd_ostream &OS) { + bool ShowIndirectCallTargets, bool ShowAllFunctions, + std::string ShowFunction, raw_fd_ostream &OS) { auto ReaderOrErr = InstrProfReader::create(Filename); if (std::error_code EC = ReaderOrErr.getError()) exitWithError(EC.message(), Filename); @@ -162,6 +161,9 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, << " Hash: " << format("0x%016" PRIx64, Func.Hash) << "\n" << " Counters: " << Func.Counts.size() << "\n" << " Function count: " << Func.Counts[0] << "\n"; + if (ShowIndirectCallTargets) + OS << " Indirect Call Site Count: " << Func.IndirectCallSites.size() + << "\n"; } if (Show && ShowCounts) @@ -174,6 +176,16 @@ static int showInstrProfile(std::string Filename, bool ShowCounts, } if (Show && ShowCounts) OS << "]\n"; + + if (Show && ShowIndirectCallTargets) { + OS << " Indirect Target Results: \n"; + for (size_t I = 0, E = Func.IndirectCallSites.size(); I < E; ++I) { + for (auto V : Func.IndirectCallSites[I].ValueData) { + OS << "\t[ " << I << ", "; + OS << (const char *)V.first << ", " << V.second << " ]\n"; + } + } + } } if (Reader->hasError()) exitWithError(Reader->getError().message(), Filename); @@ -212,6 +224,9 @@ static int show_main(int argc, const char *argv[]) { cl::opt<bool> ShowCounts("counts", cl::init(false), cl::desc("Show counter values for shown functions")); + cl::opt<bool> ShowIndirectCallTargets( + "ic-targets", cl::init(false), + cl::desc("Show indirect call site target values for shown functions")); cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false), cl::desc("Details for every function")); cl::opt<std::string> ShowFunction("function", @@ -240,8 +255,8 @@ static int show_main(int argc, const char *argv[]) { errs() << "warning: -function argument ignored: showing all functions\n"; if (ProfileKind == instr) - return showInstrProfile(Filename, ShowCounts, ShowAllFunctions, - ShowFunction, OS); + return showInstrProfile(Filename, ShowCounts, ShowIndirectCallTargets, + ShowAllFunctions, ShowFunction, OS); else return showSampleProfile(Filename, ShowCounts, ShowAllFunctions, ShowFunction, OS); diff --git a/llvm/unittests/ProfileData/CoverageMappingTest.cpp b/llvm/unittests/ProfileData/CoverageMappingTest.cpp index a0995fbbc02..35b8626c494 100644 --- a/llvm/unittests/ProfileData/CoverageMappingTest.cpp +++ b/llvm/unittests/ProfileData/CoverageMappingTest.cpp @@ -188,7 +188,8 @@ TEST_F(CoverageMappingTest, expansion_gets_first_counter) { } TEST_F(CoverageMappingTest, basic_coverage_iteration) { - ProfileWriter.addFunctionCounts("func", 0x1234, {30, 20, 10, 0}); + InstrProfRecord Record("func", 0x1234, {30, 20, 10, 0}); + ProfileWriter.addRecord(std::move(Record)); readProfCounts(); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); @@ -238,7 +239,8 @@ TEST_F(CoverageMappingTest, uncovered_function_with_mapping) { } TEST_F(CoverageMappingTest, combine_regions) { - ProfileWriter.addFunctionCounts("func", 0x1234, {10, 20, 30}); + InstrProfRecord Record("func", 0x1234, {10, 20, 30}); + ProfileWriter.addRecord(std::move(Record)); readProfCounts(); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); @@ -256,7 +258,8 @@ TEST_F(CoverageMappingTest, combine_regions) { } TEST_F(CoverageMappingTest, dont_combine_expansions) { - ProfileWriter.addFunctionCounts("func", 0x1234, {10, 20}); + InstrProfRecord Record("func", 0x1234, {10, 20}); + ProfileWriter.addRecord(std::move(Record)); readProfCounts(); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); @@ -275,7 +278,8 @@ TEST_F(CoverageMappingTest, dont_combine_expansions) { } TEST_F(CoverageMappingTest, strip_filename_prefix) { - ProfileWriter.addFunctionCounts("file1:func", 0x1234, {10}); + InstrProfRecord Record("file1:func", 0x1234, {10}); + ProfileWriter.addRecord(std::move(Record)); readProfCounts(); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); diff --git a/llvm/unittests/ProfileData/InstrProfTest.cpp b/llvm/unittests/ProfileData/InstrProfTest.cpp index 2cedd593eb8..0e0141b80ea 100644 --- a/llvm/unittests/ProfileData/InstrProfTest.cpp +++ b/llvm/unittests/ProfileData/InstrProfTest.cpp @@ -50,7 +50,8 @@ TEST_F(InstrProfTest, write_and_read_empty_profile) { } TEST_F(InstrProfTest, write_and_read_one_function) { - Writer.addFunctionCounts("foo", 0x1234, {1, 2, 3, 4}); + InstrProfRecord Record("foo", 0x1234, {1, 2, 3, 4}); + Writer.addRecord(std::move(Record)); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); @@ -67,8 +68,10 @@ TEST_F(InstrProfTest, write_and_read_one_function) { } TEST_F(InstrProfTest, get_function_counts) { - Writer.addFunctionCounts("foo", 0x1234, {1, 2}); - Writer.addFunctionCounts("foo", 0x1235, {3, 4}); + InstrProfRecord Record1("foo", 0x1234, {1, 2}); + InstrProfRecord Record2("foo", 0x1235, {3, 4}); + Writer.addRecord(std::move(Record1)); + Writer.addRecord(std::move(Record2)); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); @@ -92,9 +95,12 @@ TEST_F(InstrProfTest, get_function_counts) { } TEST_F(InstrProfTest, get_max_function_count) { - Writer.addFunctionCounts("foo", 0x1234, {1ULL << 31, 2}); - Writer.addFunctionCounts("bar", 0, {1ULL << 63}); - Writer.addFunctionCounts("baz", 0x5678, {0, 0, 0, 0}); + InstrProfRecord Record1("foo", 0x1234, {1ULL << 31, 2}); + InstrProfRecord Record2("bar", 0, {1ULL << 63}); + InstrProfRecord Record3("baz", 0x5678, {0, 0, 0, 0}); + Writer.addRecord(std::move(Record1)); + Writer.addRecord(std::move(Record2)); + Writer.addRecord(std::move(Record3)); auto Profile = Writer.writeBuffer(); readProfile(std::move(Profile)); |