}
};
+struct InstrProfValueData {
+ // Profiled value.
+ uint64_t Value;
+ // Number of times the value appears in the training run.
+ uint64_t Count;
+};
+
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;
+ std::list<InstrProfValueData> ValueData;
InstrProfValueSiteRecord() { ValueData.clear(); }
+ template <class InputIterator>
+ InstrProfValueSiteRecord(InputIterator F, InputIterator L)
+ : ValueData(F, L) {}
- /// Sort ValueData ascending by TargetValue
+ /// Sort ValueData ascending by Value
void sortByTargetValues() {
- ValueData.sort([](const ValueDataPair &left, const ValueDataPair &right) {
- return left.first < right.first;
- });
+ ValueData.sort(
+ [](const InstrProfValueData &left, const InstrProfValueData &right) {
+ return left.Value < right.Value;
+ });
}
/// Merge data from another InstrProfValueSiteRecord
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;
+ while (I != IE && I->Value < J->Value) ++I;
+ if (I != IE && I->Value == J->Value) {
+ I->Count += J->Count;
++I;
continue;
}
StringRef Name;
uint64_t Hash;
std::vector<uint64_t> Counts;
- std::vector<InstrProfValueSiteRecord> IndirectCallSites;
+ typedef std::vector<std::pair<uint64_t, const char *>> ValueMapType;
+
+ /// Return the number of value profile kinds with non-zero number
+ /// of profile sites.
+ inline uint32_t getNumValueKinds() const;
+ /// Return the number of instrumented sites for ValueKind.
+ inline uint32_t getNumValueSites(uint32_t ValueKind) const;
+ /// Return the total number of ValueData for ValueKind.
+ inline uint32_t getNumValueData(uint32_t ValueKind) const;
+ /// Return the number of value data collected for ValueKind at profiling
+ /// site: Site.
+ inline uint32_t getNumValueDataForSite(uint32_t ValueKind,
+ uint32_t Site) const;
+ inline std::unique_ptr<InstrProfValueData[]> getValueForSite(
+ uint32_t ValueKind, uint32_t Site) const;
+ /// Reserve space for NumValueSites sites.
+ inline void reserveSites(uint32_t ValueKind, uint32_t NumValueSites);
+ /// Add ValueData for ValueKind at value Site.
+ inline void addValueData(uint32_t ValueKind, uint32_t Site,
+ InstrProfValueData *VData, uint32_t N,
+ ValueMapType *HashKeys);
+ /// Merge Value Profile ddata from Src record to this record for ValueKind.
+ inline instrprof_error mergeValueProfData(uint32_t ValueKind,
+ InstrProfRecord &Src);
+
+ /// Used by InstrProfWriter: update the value strings to commoned strings in
+ /// the writer instance.
+ inline void updateStrings(InstrProfStringTable *StrTab);
+
+ private:
+ std::vector<InstrProfValueSiteRecord> IndirectCallSites;
const std::vector<InstrProfValueSiteRecord> &
getValueSitesForKind(uint32_t ValueKind) const {
switch (ValueKind) {
case IPVK_IndirectCallTarget:
return IndirectCallSites;
+ default:
+ llvm_unreachable("Unknown value kind!");
}
- llvm_unreachable("Unknown value kind!");
+ return IndirectCallSites;
}
std::vector<InstrProfValueSiteRecord> &
const_cast<const InstrProfRecord *>(this)
->getValueSitesForKind(ValueKind));
}
+ // Map indirect call target name hash to name string.
+ uint64_t remapValue(uint64_t Value, uint32_t ValueKind,
+ ValueMapType *HashKeys) {
+ if (!HashKeys) return Value;
+ 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;
+ }
+ }
+ return Value;
+ }
};
+uint32_t InstrProfRecord::getNumValueKinds() const {
+ uint32_t NumValueKinds = 0;
+ for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
+ NumValueKinds += !(getValueSitesForKind(Kind).empty());
+ return NumValueKinds;
+}
+
+uint32_t InstrProfRecord::getNumValueSites(uint32_t ValueKind) const {
+ return getValueSitesForKind(ValueKind).size();
+}
+
+uint32_t InstrProfRecord::getNumValueDataForSite(uint32_t ValueKind,
+ uint32_t Site) const {
+ return getValueSitesForKind(ValueKind)[Site].ValueData.size();
+}
+
+std::unique_ptr<InstrProfValueData[]> InstrProfRecord::getValueForSite(
+ uint32_t ValueKind, uint32_t Site) const {
+ uint32_t N = getNumValueDataForSite(ValueKind, Site);
+ if (N == 0) return std::unique_ptr<InstrProfValueData[]>(nullptr);
+
+ std::unique_ptr<InstrProfValueData[]> VD(new InstrProfValueData[N]);
+ uint32_t I = 0;
+ for (auto V : getValueSitesForKind(ValueKind)[Site].ValueData) {
+ VD[I] = V;
+ I++;
+ }
+ assert(I == N);
+
+ return std::move(VD);
+}
+
+void InstrProfRecord::addValueData(uint32_t ValueKind, uint32_t Site,
+ InstrProfValueData *VData, uint32_t N,
+ ValueMapType *HashKeys) {
+ for (uint32_t I = 0; I < N; I++) {
+ VData[I].Value = remapValue(VData[I].Value, ValueKind, HashKeys);
+ }
+ std::vector<InstrProfValueSiteRecord> &ValueSites =
+ getValueSitesForKind(ValueKind);
+ if (N == 0)
+ ValueSites.push_back(InstrProfValueSiteRecord());
+ else
+ ValueSites.emplace_back(VData, VData + N);
+}
+
+void InstrProfRecord::reserveSites(uint32_t ValueKind, uint32_t NumValueSites) {
+ std::vector<InstrProfValueSiteRecord> &ValueSites =
+ getValueSitesForKind(ValueKind);
+ ValueSites.reserve(NumValueSites);
+}
+
+instrprof_error InstrProfRecord::mergeValueProfData(uint32_t ValueKind,
+ InstrProfRecord &Src) {
+ uint32_t ThisNumValueSites = getNumValueSites(ValueKind);
+ uint32_t OtherNumValueSites = Src.getNumValueSites(ValueKind);
+ if (ThisNumValueSites != OtherNumValueSites)
+ return instrprof_error::value_site_count_mismatch;
+ std::vector<InstrProfValueSiteRecord> &ThisSiteRecords =
+ getValueSitesForKind(ValueKind);
+ std::vector<InstrProfValueSiteRecord> &OtherSiteRecords =
+ Src.getValueSitesForKind(ValueKind);
+ for (uint32_t I = 0; I < ThisNumValueSites; I++)
+ ThisSiteRecords[I].mergeValueData(OtherSiteRecords[I]);
+ return instrprof_error::success;
+}
+
+void InstrProfRecord::updateStrings(InstrProfStringTable *StrTab) {
+ if (!StrTab) return;
+
+ Name = StrTab->insertString(Name);
+ for (auto &VSite : IndirectCallSites)
+ for (auto &VData : VSite.ValueData)
+ VData.Value = (uint64_t)StrTab->insertString((const char *)VData.Value);
+}
+
namespace IndexedInstrProf {
enum class HashT : uint32_t {
MD5,
/// Read a single record.
std::error_code readNextRecord(InstrProfRecord &Record) override;
+ /// Return the pointer to InstrProfRecord associated with FuncName
+ /// and FuncHash
+ ErrorOr<InstrProfRecord> getInstrProfRecord(StringRef FuncName,
+ uint64_t FuncHash);
+
/// Fill Counts with the profile data for the given function name.
std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
std::vector<uint64_t> &Counts);
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);
- std::vector<InstrProfValueSiteRecord> &ValueSites =
- DataBuffer.back().getValueSitesForKind(ValueKind);
- ValueSites.reserve(ValueSiteCount);
+ ProfRecord.reserveSites(ValueKind, 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);
if (D + (ValueDataCount << 1) * sizeof(uint64_t) > End)
return false;
- InstrProfValueSiteRecord VSiteRecord;
+ std::unique_ptr<InstrProfValueData[]> VDataPtr(
+ ValueDataCount == 0 ? nullptr
+ : new InstrProfValueData[ValueDataCount]);
+
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));
+ VDataPtr[VCount].Value =
+ endian::readNext<uint64_t, little, unaligned>(D);
+ VDataPtr[VCount].Count =
+ endian::readNext<uint64_t, little, unaligned>(D);
}
- ValueSites.push_back(std::move(VSiteRecord));
+ ProfRecord.addValueData(ValueKind, VSite, VDataPtr.get(), ValueDataCount,
+ &HashKeys);
}
}
return true;
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)));
+ DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer));
// Read value profiling data.
if (FormatVersion > 2 && !ReadValueProfilingData(D, End)) {
return success();
}
-std::error_code IndexedInstrProfReader::getFunctionCounts(
- StringRef FuncName, uint64_t FuncHash, std::vector<uint64_t> &Counts) {
+ErrorOr<InstrProfRecord> IndexedInstrProfReader::getInstrProfRecord(
+ StringRef FuncName, uint64_t FuncHash) {
ArrayRef<InstrProfRecord> Data;
-
std::error_code EC = Index.getRecords(FuncName, Data);
if (EC != instrprof_error::success) return EC;
-
// Found it. Look for counters with the right hash.
for (unsigned I = 0, E = Data.size(); I < E; ++I) {
// Check for a match and fill the vector if there is one.
if (Data[I].Hash == FuncHash) {
- Counts = Data[I].Counts;
- return success();
+ return std::move(Data[I]);
}
}
return error(instrprof_error::hash_mismatch);
}
+std::error_code IndexedInstrProfReader::getFunctionCounts(
+ StringRef FuncName, uint64_t FuncHash, std::vector<uint64_t> &Counts) {
+ ErrorOr<InstrProfRecord> Record = getInstrProfRecord(FuncName, FuncHash);
+ if (std::error_code EC = Record.getError()) return EC;
+
+ Counts = Record.get().Counts;
+ return success();
+}
+
std::error_code IndexedInstrProfReader::readNextRecord(
InstrProfRecord &Record) {
static unsigned RecordIndex = 0;
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 += ProfileData.second.Counts.size() * sizeof(uint64_t);
+ 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) {
- const std::vector<InstrProfValueSiteRecord> &ValueSites =
- ProfileData.second.getValueSitesForKind(Kind);
- if (ValueSites.empty())
- continue;
+ 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 (InstrProfValueSiteRecord I : ValueSites) {
+ for (uint32_t I = 0; I < NumValueSites; I++) {
M += sizeof(uint64_t); // Number of value data pairs at a value site
- M += 2 * sizeof(uint64_t) * I.ValueData.size(); // Value data pairs
+ uint64_t NumValueDataForSite =
+ ProfRecord.getNumValueDataForSite(Kind, I);
+ M += 2 * sizeof(uint64_t) * NumValueDataForSite; // Value data pairs
}
}
}
using namespace llvm::support;
endian::Writer<little> LE(Out);
for (const auto &ProfileData : *V) {
+ const InstrProfRecord &ProfRecord = ProfileData.second;
+
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);
+ LE.write<uint64_t>(ProfRecord.Counts.size());
+ for (uint64_t I : ProfRecord.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());
+ uint64_t NumValueKinds = ProfRecord.getNumValueKinds();
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;
+ 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>(ValueSites.size());
- for (InstrProfValueSiteRecord I : ValueSites) {
+ LE.write<uint64_t>(NumValueSites);
+
+ for (uint32_t I = 0; I < NumValueSites; I++) {
// Write number of value data pairs at this value site
- LE.write<uint64_t>(I.ValueData.size());
- for (auto V : I.ValueData) {
+ 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 *)V.first));
+ LE.write<uint64_t>(ComputeHash((const char *)VD[V].Value));
else
- LE.write<uint64_t>(V.first);
- LE.write<uint64_t>(V.second);
+ LE.write<uint64_t>(VD[V].Value);
+ LE.write<uint64_t>(VD[V].Count);
}
}
}
}
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
-
- 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]);
+ if (std::error_code EC = Dest.mergeValueProfData(Kind, Source)) return EC;
}
// We keep track of the max function count as we go for simplicity.
}
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);
+ I.updateStrings(&StringTable);
}
std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I) {
<< " Counters: " << Func.Counts.size() << "\n"
<< " Function count: " << Func.Counts[0] << "\n";
if (ShowIndirectCallTargets)
- OS << " Indirect Call Site Count: " << Func.IndirectCallSites.size()
- << "\n";
+ OS << " Indirect Call Site Count: "
+ << Func.getNumValueSites(IPVK_IndirectCallTarget) << "\n";
}
if (Show && ShowCounts)
OS << "]\n";
if (Show && ShowIndirectCallTargets) {
+ uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget);
OS << " Indirect Target Results: \n";
- for (size_t I = 0, E = Func.IndirectCallSites.size(); I < E; ++I) {
- for (auto V : Func.IndirectCallSites[I].ValueData) {
+ for (size_t I = 0; I < NS; ++I) {
+ uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I);
+ std::unique_ptr<InstrProfValueData[]> VD =
+ Func.getValueForSite(IPVK_IndirectCallTarget, I);
+ for (uint32_t V = 0; V < NV; V++) {
OS << "\t[ " << I << ", ";
- OS << (const char *)V.first << ", " << V.second << " ]\n";
+ OS << (const char *)VD[V].Value << ", " << VD[V].Count << " ]\n";
}
}
}
ASSERT_TRUE(++I == E);
}
+TEST_F(InstrProfTest, get_instr_prof_record) {
+ 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));
+
+ ErrorOr<InstrProfRecord> R = Reader->getInstrProfRecord("foo", 0x1234);
+ ASSERT_TRUE(NoError(R.getError()));
+ ASSERT_EQ(2U, R.get().Counts.size());
+ ASSERT_EQ(1U, R.get().Counts[0]);
+ ASSERT_EQ(2U, R.get().Counts[1]);
+
+ R = Reader->getInstrProfRecord("foo", 0x1235);
+ ASSERT_TRUE(NoError(R.getError()));
+ ASSERT_EQ(2U, R.get().Counts.size());
+ ASSERT_EQ(3U, R.get().Counts[0]);
+ ASSERT_EQ(4U, R.get().Counts[1]);
+
+ R = Reader->getInstrProfRecord("foo", 0x5678);
+ ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, R.getError()));
+
+ R = Reader->getInstrProfRecord("bar", 0x1234);
+ ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, R.getError()));
+}
+
TEST_F(InstrProfTest, get_function_counts) {
InstrProfRecord Record1("foo", 0x1234, {1, 2});
InstrProfRecord Record2("foo", 0x1235, {3, 4});
ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, EC));
}
+TEST_F(InstrProfTest, get_icall_data_read_write) {
+ InstrProfRecord Record1("caller", 0x1234, {1, 2});
+ InstrProfRecord Record2("callee1", 0x1235, {3, 4});
+ InstrProfRecord Record3("callee2", 0x1235, {3, 4});
+ InstrProfRecord Record4("callee3", 0x1235, {3, 4});
+
+ // 4 value sites.
+ Record1.reserveSites(IPVK_IndirectCallTarget, 4);
+ InstrProfValueData VD0[] = {{(uint64_t) "callee1", 1},
+ {(uint64_t) "callee2", 2},
+ {(uint64_t) "callee3", 3}};
+ Record1.addValueData(IPVK_IndirectCallTarget, 0, VD0, 3, 0);
+ // No valeu profile data at the second site.
+ Record1.addValueData(IPVK_IndirectCallTarget, 1, 0, 0, 0);
+ InstrProfValueData VD2[] = {{(uint64_t) "callee1", 1},
+ {(uint64_t) "callee2", 2}};
+ Record1.addValueData(IPVK_IndirectCallTarget, 2, VD2, 2, 0);
+ InstrProfValueData VD3[] = {{(uint64_t) "callee1", 1}};
+ Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, 0);
+
+ Writer.addRecord(std::move(Record1));
+ Writer.addRecord(std::move(Record2));
+ Writer.addRecord(std::move(Record3));
+ Writer.addRecord(std::move(Record4));
+ auto Profile = Writer.writeBuffer();
+ readProfile(std::move(Profile));
+
+ ErrorOr<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
+ ASSERT_TRUE(NoError(R.getError()));
+ ASSERT_EQ(4U, R.get().getNumValueSites(IPVK_IndirectCallTarget));
+ ASSERT_EQ(3U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 0));
+ ASSERT_EQ(0U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 1));
+ ASSERT_EQ(2U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 2));
+ ASSERT_EQ(1U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 3));
+
+ std::unique_ptr<InstrProfValueData[]> VD =
+ R.get().getValueForSite(IPVK_IndirectCallTarget, 0);
+ // Now sort the target acording to frequency.
+ std::sort(&VD[0], &VD[3],
+ [](const InstrProfValueData &VD1, const InstrProfValueData &VD2) {
+ return VD1.Count > VD2.Count;
+ });
+ ASSERT_EQ(StringRef((const char *)VD[0].Value, 7), StringRef("callee3"));
+ ASSERT_EQ(StringRef((const char *)VD[1].Value, 7), StringRef("callee2"));
+ ASSERT_EQ(StringRef((const char *)VD[2].Value, 7), StringRef("callee1"));
+}
+
+TEST_F(InstrProfTest, get_icall_data_merge1) {
+ InstrProfRecord Record11("caller", 0x1234, {1, 2});
+ InstrProfRecord Record12("caller", 0x1234, {1, 2});
+ InstrProfRecord Record2("callee1", 0x1235, {3, 4});
+ InstrProfRecord Record3("callee2", 0x1235, {3, 4});
+ InstrProfRecord Record4("callee3", 0x1235, {3, 4});
+ InstrProfRecord Record5("callee3", 0x1235, {3, 4});
+ InstrProfRecord Record6("callee4", 0x1235, {3, 5});
+
+ // 5 value sites.
+ Record11.reserveSites(IPVK_IndirectCallTarget, 5);
+ InstrProfValueData VD0[] = {{(uint64_t) "callee1", 1},
+ {(uint64_t) "callee2", 2},
+ {(uint64_t) "callee3", 3},
+ {(uint64_t) "callee4", 4}};
+ Record11.addValueData(IPVK_IndirectCallTarget, 0, VD0, 4, 0);
+
+ // No valeu profile data at the second site.
+ Record11.addValueData(IPVK_IndirectCallTarget, 1, 0, 0, 0);
+
+ InstrProfValueData VD2[] = {{(uint64_t) "callee1", 1},
+ {(uint64_t) "callee2", 2},
+ {(uint64_t) "callee3", 3}};
+ Record11.addValueData(IPVK_IndirectCallTarget, 2, VD2, 3, 0);
+
+ InstrProfValueData VD3[] = {{(uint64_t) "callee1", 1}};
+ Record11.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, 0);
+
+ InstrProfValueData VD4[] = {{(uint64_t) "callee1", 1},
+ {(uint64_t) "callee2", 2},
+ {(uint64_t) "callee3", 3}};
+ Record11.addValueData(IPVK_IndirectCallTarget, 4, VD4, 3, 0);
+
+ // A differnt record for the same caller.
+ Record12.reserveSites(IPVK_IndirectCallTarget, 5);
+ InstrProfValueData VD02[] = {{(uint64_t) "callee2", 5},
+ {(uint64_t) "callee3", 3}};
+ Record12.addValueData(IPVK_IndirectCallTarget, 0, VD02, 2, 0);
+
+ // No valeu profile data at the second site.
+ Record12.addValueData(IPVK_IndirectCallTarget, 1, 0, 0, 0);
+
+ InstrProfValueData VD22[] = {{(uint64_t) "callee2", 1},
+ {(uint64_t) "callee3", 3},
+ {(uint64_t) "callee4", 4}};
+ Record12.addValueData(IPVK_IndirectCallTarget, 2, VD22, 3, 0);
+
+ Record12.addValueData(IPVK_IndirectCallTarget, 3, 0, 0, 0);
+
+ InstrProfValueData VD42[] = {{(uint64_t) "callee1", 1},
+ {(uint64_t) "callee2", 2},
+ {(uint64_t) "callee3", 3}};
+ Record12.addValueData(IPVK_IndirectCallTarget, 4, VD42, 3, 0);
+
+ Writer.addRecord(std::move(Record11));
+ // Merge profile data.
+ Writer.addRecord(std::move(Record12));
+
+ Writer.addRecord(std::move(Record2));
+ Writer.addRecord(std::move(Record3));
+ Writer.addRecord(std::move(Record4));
+ Writer.addRecord(std::move(Record5));
+ Writer.addRecord(std::move(Record6));
+ auto Profile = Writer.writeBuffer();
+ readProfile(std::move(Profile));
+
+ ErrorOr<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
+ ASSERT_TRUE(NoError(R.getError()));
+ ASSERT_EQ(5U, R.get().getNumValueSites(IPVK_IndirectCallTarget));
+ ASSERT_EQ(4U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 0));
+ ASSERT_EQ(0U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 1));
+ ASSERT_EQ(4U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 2));
+ ASSERT_EQ(1U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 3));
+ ASSERT_EQ(3U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 4));
+
+ std::unique_ptr<InstrProfValueData[]> VD =
+ R.get().getValueForSite(IPVK_IndirectCallTarget, 0);
+ // Now sort the target acording to frequency.
+ std::sort(&VD[0], &VD[4],
+ [](const InstrProfValueData &VD1, const InstrProfValueData &VD2) {
+ return VD1.Count > VD2.Count;
+ });
+ ASSERT_EQ(StringRef((const char *)VD[0].Value, 7), StringRef("callee2"));
+ ASSERT_EQ(7U, VD[0].Count);
+ ASSERT_EQ(StringRef((const char *)VD[1].Value, 7), StringRef("callee3"));
+ ASSERT_EQ(6U, VD[1].Count);
+ ASSERT_EQ(StringRef((const char *)VD[2].Value, 7), StringRef("callee4"));
+ ASSERT_EQ(4U, VD[2].Count);
+ ASSERT_EQ(StringRef((const char *)VD[3].Value, 7), StringRef("callee1"));
+ ASSERT_EQ(1U, VD[3].Count);
+
+ std::unique_ptr<InstrProfValueData[]> VD_2(
+ R.get().getValueForSite(IPVK_IndirectCallTarget, 2));
+ std::sort(&VD_2[0], &VD_2[4],
+ [](const InstrProfValueData &VD1, const InstrProfValueData &VD2) {
+ return VD1.Count > VD2.Count;
+ });
+ ASSERT_EQ(StringRef((const char *)VD_2[0].Value, 7), StringRef("callee3"));
+ ASSERT_EQ(6U, VD_2[0].Count);
+ ASSERT_EQ(StringRef((const char *)VD_2[1].Value, 7), StringRef("callee4"));
+ ASSERT_EQ(4U, VD_2[1].Count);
+ ASSERT_EQ(StringRef((const char *)VD_2[2].Value, 7), StringRef("callee2"));
+ ASSERT_EQ(3U, VD_2[2].Count);
+ ASSERT_EQ(StringRef((const char *)VD_2[3].Value, 7), StringRef("callee1"));
+ ASSERT_EQ(1U, VD_2[3].Count);
+
+ std::unique_ptr<InstrProfValueData[]> VD_3(
+ R.get().getValueForSite(IPVK_IndirectCallTarget, 3));
+ ASSERT_EQ(StringRef((const char *)VD_3[0].Value, 7), StringRef("callee1"));
+ ASSERT_EQ(1U, VD_3[0].Count);
+
+ std::unique_ptr<InstrProfValueData[]> VD_4(
+ R.get().getValueForSite(IPVK_IndirectCallTarget, 4));
+ std::sort(&VD_4[0], &VD_4[3],
+ [](const InstrProfValueData &VD1, const InstrProfValueData &VD2) {
+ return VD1.Count > VD2.Count;
+ });
+ ASSERT_EQ(StringRef((const char *)VD_4[0].Value, 7), StringRef("callee3"));
+ ASSERT_EQ(6U, VD_4[0].Count);
+ ASSERT_EQ(StringRef((const char *)VD_4[1].Value, 7), StringRef("callee2"));
+ ASSERT_EQ(4U, VD_4[1].Count);
+ ASSERT_EQ(StringRef((const char *)VD_4[2].Value, 7), StringRef("callee1"));
+ ASSERT_EQ(2U, VD_4[2].Count);
+}
+
TEST_F(InstrProfTest, get_max_function_count) {
InstrProfRecord Record1("foo", 0x1234, {1ULL << 31, 2});
InstrProfRecord Record2("bar", 0, {1ULL << 63});