llvm.org GIT mirror llvm / 61c7e68
[PGO] Value profiling (index format) code cleanup and testing 1. Added a set of public interfaces in InstrProfRecord class to access (read/write) value profile data. 2. Changed IndexedProfile reader and writer code to use the newly defined interfaces and hide implementation details. 3. Added a couple of unittests for value profiling: - Test new interfaces to get and set value profile data - Test value profile data merging with various scenarios. No functional change is expected. The new interfaces will also make it possible to change on-disk format of value prof data to be more compact (to be submitted). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@251771 91177308-0d34-0410-b5e6-96231b3b80d8 Xinliang David Li 3 years ago
6 changed file(s) with 420 addition(s) and 95 deletion(s). Raw diff Collapse all Expand all
158158 }
159159 };
160160
161 struct InstrProfValueData {
162 // Profiled value.
163 uint64_t Value;
164 // Number of times the value appears in the training run.
165 uint64_t Count;
166 };
167
161168 struct InstrProfValueSiteRecord {
162 /// Typedef for a single TargetValue-NumTaken pair.
163 typedef std::pair ValueDataPair;
164169 /// Value profiling data pairs at a given value site.
165 std::list<ValueDataPair> ValueData;
170 std::list<InstrProfValueData> ValueData;
166171
167172 InstrProfValueSiteRecord() { ValueData.clear(); }
168
169 /// Sort ValueData ascending by TargetValue
173 template
174 InstrProfValueSiteRecord(InputIterator F, InputIterator L)
175 : ValueData(F, L) {}
176
177 /// Sort ValueData ascending by Value
170178 void sortByTargetValues() {
171 ValueData.sort([](const ValueDataPair &left, const ValueDataPair &right) {
172 return left.first < right.first;
173 });
179 ValueData.sort(
180 [](const InstrProfValueData &left, const InstrProfValueData &right) {
181 return left.Value < right.Value;
182 });
174183 }
175184
176185 /// Merge data from another InstrProfValueSiteRecord
181190 auto IE = ValueData.end();
182191 for (auto J = Input.ValueData.begin(), JE = Input.ValueData.end(); J != JE;
183192 ++J) {
184 while (I != IE && I->first < J->first)
185 ++I;
186 if (I != IE && I->first == J->first) {
187 I->second += J->second;
193 while (I != IE && I->Value < J->Value) ++I;
194 if (I != IE && I->Value == J->Value) {
195 I->Count += J->Count;
188196 ++I;
189197 continue;
190198 }
201209 StringRef Name;
202210 uint64_t Hash;
203211 std::vector Counts;
212
213 typedef std::vector> ValueMapType;
214
215 /// Return the number of value profile kinds with non-zero number
216 /// of profile sites.
217 inline uint32_t getNumValueKinds() const;
218 /// Return the number of instrumented sites for ValueKind.
219 inline uint32_t getNumValueSites(uint32_t ValueKind) const;
220 /// Return the total number of ValueData for ValueKind.
221 inline uint32_t getNumValueData(uint32_t ValueKind) const;
222 /// Return the number of value data collected for ValueKind at profiling
223 /// site: Site.
224 inline uint32_t getNumValueDataForSite(uint32_t ValueKind,
225 uint32_t Site) const;
226 inline std::unique_ptr getValueForSite(
227 uint32_t ValueKind, uint32_t Site) const;
228 /// Reserve space for NumValueSites sites.
229 inline void reserveSites(uint32_t ValueKind, uint32_t NumValueSites);
230 /// Add ValueData for ValueKind at value Site.
231 inline void addValueData(uint32_t ValueKind, uint32_t Site,
232 InstrProfValueData *VData, uint32_t N,
233 ValueMapType *HashKeys);
234 /// Merge Value Profile ddata from Src record to this record for ValueKind.
235 inline instrprof_error mergeValueProfData(uint32_t ValueKind,
236 InstrProfRecord &Src);
237
238 /// Used by InstrProfWriter: update the value strings to commoned strings in
239 /// the writer instance.
240 inline void updateStrings(InstrProfStringTable *StrTab);
241
242 private:
204243 std::vector IndirectCallSites;
205
206244 const std::vector &
207245 getValueSitesForKind(uint32_t ValueKind) const {
208246 switch (ValueKind) {
209247 case IPVK_IndirectCallTarget:
210248 return IndirectCallSites;
249 default:
250 llvm_unreachable("Unknown value kind!");
211251 }
212 llvm_unreachable("Unknown value kind!");
252 return IndirectCallSites;
213253 }
214254
215255 std::vector &
218258 const_cast(this)
219259 ->getValueSitesForKind(ValueKind));
220260 }
221 };
261 // Map indirect call target name hash to name string.
262 uint64_t remapValue(uint64_t Value, uint32_t ValueKind,
263 ValueMapType *HashKeys) {
264 if (!HashKeys) return Value;
265 switch (ValueKind) {
266 case IPVK_IndirectCallTarget: {
267 auto Result =
268 std::lower_bound(HashKeys->begin(), HashKeys->end(), Value,
269 [](const std::pair &LHS,
270 uint64_t RHS) { return LHS.first < RHS; });
271 assert(Result != HashKeys->end() &&
272 "Hash does not match any known keys\n");
273 Value = (uint64_t)Result->second;
274 break;
275 }
276 }
277 return Value;
278 }
279 };
280
281 uint32_t InstrProfRecord::getNumValueKinds() const {
282 uint32_t NumValueKinds = 0;
283 for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
284 NumValueKinds += !(getValueSitesForKind(Kind).empty());
285 return NumValueKinds;
286 }
287
288 uint32_t InstrProfRecord::getNumValueSites(uint32_t ValueKind) const {
289 return getValueSitesForKind(ValueKind).size();
290 }
291
292 uint32_t InstrProfRecord::getNumValueDataForSite(uint32_t ValueKind,
293 uint32_t Site) const {
294 return getValueSitesForKind(ValueKind)[Site].ValueData.size();
295 }
296
297 std::unique_ptr InstrProfRecord::getValueForSite(
298 uint32_t ValueKind, uint32_t Site) const {
299 uint32_t N = getNumValueDataForSite(ValueKind, Site);
300 if (N == 0) return std::unique_ptr(nullptr);
301
302 std::unique_ptr VD(new InstrProfValueData[N]);
303 uint32_t I = 0;
304 for (auto V : getValueSitesForKind(ValueKind)[Site].ValueData) {
305 VD[I] = V;
306 I++;
307 }
308 assert(I == N);
309
310 return std::move(VD);
311 }
312
313 void InstrProfRecord::addValueData(uint32_t ValueKind, uint32_t Site,
314 InstrProfValueData *VData, uint32_t N,
315 ValueMapType *HashKeys) {
316 for (uint32_t I = 0; I < N; I++) {
317 VData[I].Value = remapValue(VData[I].Value, ValueKind, HashKeys);
318 }
319 std::vector &ValueSites =
320 getValueSitesForKind(ValueKind);
321 if (N == 0)
322 ValueSites.push_back(InstrProfValueSiteRecord());
323 else
324 ValueSites.emplace_back(VData, VData + N);
325 }
326
327 void InstrProfRecord::reserveSites(uint32_t ValueKind, uint32_t NumValueSites) {
328 std::vector &ValueSites =
329 getValueSitesForKind(ValueKind);
330 ValueSites.reserve(NumValueSites);
331 }
332
333 instrprof_error InstrProfRecord::mergeValueProfData(uint32_t ValueKind,
334 InstrProfRecord &Src) {
335 uint32_t ThisNumValueSites = getNumValueSites(ValueKind);
336 uint32_t OtherNumValueSites = Src.getNumValueSites(ValueKind);
337 if (ThisNumValueSites != OtherNumValueSites)
338 return instrprof_error::value_site_count_mismatch;
339 std::vector &ThisSiteRecords =
340 getValueSitesForKind(ValueKind);
341 std::vector &OtherSiteRecords =
342 Src.getValueSitesForKind(ValueKind);
343 for (uint32_t I = 0; I < ThisNumValueSites; I++)
344 ThisSiteRecords[I].mergeValueData(OtherSiteRecords[I]);
345 return instrprof_error::success;
346 }
347
348 void InstrProfRecord::updateStrings(InstrProfStringTable *StrTab) {
349 if (!StrTab) return;
350
351 Name = StrTab->insertString(Name);
352 for (auto &VSite : IndirectCallSites)
353 for (auto &VData : VSite.ValueData)
354 VData.Value = (uint64_t)StrTab->insertString((const char *)VData.Value);
355 }
222356
223357 namespace IndexedInstrProf {
224358 enum class HashT : uint32_t {
277277 /// Read a single record.
278278 std::error_code readNextRecord(InstrProfRecord &Record) override;
279279
280 /// Return the pointer to InstrProfRecord associated with FuncName
281 /// and FuncHash
282 ErrorOr getInstrProfRecord(StringRef FuncName,
283 uint64_t FuncHash);
284
280285 /// Fill Counts with the profile data for the given function name.
281286 std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncHash,
282287 std::vector &Counts);
304304 return false;
305305 uint64_t ValueKindCount = endian::readNext(D);
306306
307 InstrProfRecord &ProfRecord = DataBuffer.back();
307308 for (uint32_t Kind = 0; Kind < ValueKindCount; ++Kind) {
308309
309310 // Read value kind and number of value sites for kind.
310311 if (D + 2 * sizeof(uint64_t) > End)
311312 return false;
313
312314 uint64_t ValueKind = endian::readNext(D);
313315 uint64_t ValueSiteCount = endian::readNext(D);
314316
315 std::vector &ValueSites =
316 DataBuffer.back().getValueSitesForKind(ValueKind);
317 ValueSites.reserve(ValueSiteCount);
317 ProfRecord.reserveSites(ValueKind, ValueSiteCount);
318
318319 for (uint64_t VSite = 0; VSite < ValueSiteCount; ++VSite) {
319320 // Read number of value data pairs at value site.
320321 if (D + sizeof(uint64_t) > End)
321322 return false;
323
322324 uint64_t ValueDataCount =
323325 endian::readNext(D);
324326
326328 if (D + (ValueDataCount << 1) * sizeof(uint64_t) > End)
327329 return false;
328330
329 InstrProfValueSiteRecord VSiteRecord;
331 std::unique_ptr VDataPtr(
332 ValueDataCount == 0 ? nullptr
333 : new InstrProfValueData[ValueDataCount]);
334
330335 for (uint64_t VCount = 0; VCount < ValueDataCount; ++VCount) {
331 uint64_t Value = endian::readNext(D);
332 uint64_t NumTaken = endian::readNext(D);
333 switch (ValueKind) {
334 case IPVK_IndirectCallTarget: {
335 auto Result =
336 std::lower_bound(HashKeys.begin(), HashKeys.end(), Value,
337 [](const std::pair &LHS,
338 uint64_t RHS) { return LHS.first < RHS; });
339 assert(Result != HashKeys.end() &&
340 "Hash does not match any known keys\n");
341 Value = (uint64_t)Result->second;
342 break;
343 }
344 }
345 VSiteRecord.ValueData.push_back(std::make_pair(Value, NumTaken));
336 VDataPtr[VCount].Value =
337 endian::readNext(D);
338 VDataPtr[VCount].Count =
339 endian::readNext(D);
346340 }
347 ValueSites.push_back(std::move(VSiteRecord));
341 ProfRecord.addValueData(ValueKind, VSite, VDataPtr.get(), ValueDataCount,
342 &HashKeys);
348343 }
349344 }
350345 return true;
384379 for (uint64_t J = 0; J < CountsSize; ++J)
385380 CounterBuffer.push_back(endian::readNext(D));
386381
387 DataBuffer.push_back(InstrProfRecord(K, Hash, std::move(CounterBuffer)));
382 DataBuffer.emplace_back(K, Hash, std::move(CounterBuffer));
388383
389384 // Read value profiling data.
390385 if (FormatVersion > 2 && !ReadValueProfilingData(D, End)) {
487482 return success();
488483 }
489484
490 std::error_code IndexedInstrProfReader::getFunctionCounts(
491 StringRef FuncName, uint64_t FuncHash, std::vector &Counts) {
485 ErrorOr IndexedInstrProfReader::getInstrProfRecord(
486 StringRef FuncName, uint64_t FuncHash) {
492487 ArrayRef Data;
493
494488 std::error_code EC = Index.getRecords(FuncName, Data);
495489 if (EC != instrprof_error::success) return EC;
496
497490 // Found it. Look for counters with the right hash.
498491 for (unsigned I = 0, E = Data.size(); I < E; ++I) {
499492 // Check for a match and fill the vector if there is one.
500493 if (Data[I].Hash == FuncHash) {
501 Counts = Data[I].Counts;
502 return success();
494 return std::move(Data[I]);
503495 }
504496 }
505497 return error(instrprof_error::hash_mismatch);
498 }
499
500 std::error_code IndexedInstrProfReader::getFunctionCounts(
501 StringRef FuncName, uint64_t FuncHash, std::vector &Counts) {
502 ErrorOr Record = getInstrProfRecord(FuncName, FuncHash);
503 if (std::error_code EC = Record.getError()) return EC;
504
505 Counts = Record.get().Counts;
506 return success();
506507 }
507508
508509 std::error_code IndexedInstrProfReader::readNextRecord(
4444
4545 offset_type M = 0;
4646 for (const auto &ProfileData : *V) {
47 const InstrProfRecord &ProfRecord = ProfileData.second;
4748 M += sizeof(uint64_t); // The function hash
4849 M += sizeof(uint64_t); // The size of the Counts vector
49 M += ProfileData.second.Counts.size() * sizeof(uint64_t);
50 M += ProfRecord.Counts.size() * sizeof(uint64_t);
5051
5152 // Value data
5253 M += sizeof(uint64_t); // Number of value kinds with value sites.
5354 for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
54 const std::vector &ValueSites =
55 ProfileData.second.getValueSitesForKind(Kind);
56 if (ValueSites.empty())
57 continue;
55 uint32_t NumValueSites = ProfRecord.getNumValueSites(Kind);
56 if (NumValueSites == 0) continue;
5857 M += sizeof(uint64_t); // Value kind
5958 M += sizeof(uint64_t); // The number of value sites for given value kind
60 for (InstrProfValueSiteRecord I : ValueSites) {
59 for (uint32_t I = 0; I < NumValueSites; I++) {
6160 M += sizeof(uint64_t); // Number of value data pairs at a value site
62 M += 2 * sizeof(uint64_t) * I.ValueData.size(); // Value data pairs
61 uint64_t NumValueDataForSite =
62 ProfRecord.getNumValueDataForSite(Kind, I);
63 M += 2 * sizeof(uint64_t) * NumValueDataForSite; // Value data pairs
6364 }
6465 }
6566 }
7778 using namespace llvm::support;
7879 endian::Writer LE(Out);
7980 for (const auto &ProfileData : *V) {
81 const InstrProfRecord &ProfRecord = ProfileData.second;
82
8083 LE.write(ProfileData.first); // Function hash
81 LE.write(ProfileData.second.Counts.size());
82 for (uint64_t I : ProfileData.second.Counts)
83 LE.write(I);
84 LE.write(ProfRecord.Counts.size());
85 for (uint64_t I : ProfRecord.Counts) LE.write(I);
8486
8587 // Compute the number of value kinds with value sites.
86 uint64_t NumValueKinds = 0;
87 for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
88 NumValueKinds +=
89 !(ProfileData.second.getValueSitesForKind(Kind).empty());
88 uint64_t NumValueKinds = ProfRecord.getNumValueKinds();
9089 LE.write(NumValueKinds);
9190
9291 // Write value data
9392 for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
94 const std::vector &ValueSites =
95 ProfileData.second.getValueSitesForKind(Kind);
96 if (ValueSites.empty())
97 continue;
93 uint32_t NumValueSites = ProfRecord.getNumValueSites(Kind);
94 if (NumValueSites == 0) continue;
9895 LE.write(Kind); // Write value kind
9996 // Write number of value sites for current value kind
100 LE.write(ValueSites.size());
101 for (InstrProfValueSiteRecord I : ValueSites) {
97 LE.write(NumValueSites);
98
99 for (uint32_t I = 0; I < NumValueSites; I++) {
102100 // Write number of value data pairs at this value site
103 LE.write(I.ValueData.size());
104 for (auto V : I.ValueData) {
101 uint64_t NumValueDataForSite =
102 ProfRecord.getNumValueDataForSite(Kind, I);
103 LE.write(NumValueDataForSite);
104 std::unique_ptr VD =
105 ProfRecord.getValueForSite(Kind, I);
106
107 for (uint32_t V = 0; V < NumValueDataForSite; V++) {
105108 if (Kind == IPVK_IndirectCallTarget)
106 LE.write(ComputeHash((const char *)V.first));
109 LE.write(ComputeHash((const char *)VD[V].Value));
107110 else
108 LE.write(V.first);
109 LE.write(V.second);
111 LE.write(VD[V].Value);
112 LE.write(VD[V].Count);
110113 }
111114 }
112115 }
130133 }
131134
132135 for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
133
134 std::vector &SourceValueSites =
135 Source.getValueSitesForKind(Kind);
136 if (SourceValueSites.empty())
137 continue;
138
139 std::vector &DestValueSites =
140 Dest.getValueSitesForKind(Kind);
141
142 if (DestValueSites.empty()) {
143 DestValueSites.swap(SourceValueSites);
144 continue;
145 }
146
147 if (DestValueSites.size() != SourceValueSites.size())
148 return instrprof_error::value_site_count_mismatch;
149 for (size_t I = 0, E = SourceValueSites.size(); I < E; ++I)
150 DestValueSites[I].mergeValueData(SourceValueSites[I]);
136 if (std::error_code EC = Dest.mergeValueProfData(Kind, Source)) return EC;
151137 }
152138
153139 // We keep track of the max function count as we go for simplicity.
158144 }
159145
160146 void InstrProfWriter::updateStringTableReferences(InstrProfRecord &I) {
161 I.Name = StringTable.insertString(I.Name);
162 for (auto &VSite : I.IndirectCallSites)
163 for (auto &VData : VSite.ValueData)
164 VData.first =
165 (uint64_t)StringTable.insertString((const char *)VData.first);
147 I.updateStrings(&StringTable);
166148 }
167149
168150 std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I) {
167167 << " Counters: " << Func.Counts.size() << "\n"
168168 << " Function count: " << Func.Counts[0] << "\n";
169169 if (ShowIndirectCallTargets)
170 OS << " Indirect Call Site Count: " << Func.IndirectCallSites.size()
171 << "\n";
170 OS << " Indirect Call Site Count: "
171 << Func.getNumValueSites(IPVK_IndirectCallTarget) << "\n";
172172 }
173173
174174 if (Show && ShowCounts)
183183 OS << "]\n";
184184
185185 if (Show && ShowIndirectCallTargets) {
186 uint32_t NS = Func.getNumValueSites(IPVK_IndirectCallTarget);
186187 OS << " Indirect Target Results: \n";
187 for (size_t I = 0, E = Func.IndirectCallSites.size(); I < E; ++I) {
188 for (auto V : Func.IndirectCallSites[I].ValueData) {
188 for (size_t I = 0; I < NS; ++I) {
189 uint32_t NV = Func.getNumValueDataForSite(IPVK_IndirectCallTarget, I);
190 std::unique_ptr VD =
191 Func.getValueForSite(IPVK_IndirectCallTarget, I);
192 for (uint32_t V = 0; V < NV; V++) {
189193 OS << "\t[ " << I << ", ";
190 OS << (const char *)V.first << ", " << V.second << " ]\n";
194 OS << (const char *)VD[V].Value << ", " << VD[V].Count << " ]\n";
191195 }
192196 }
193197 }
6666 ASSERT_TRUE(++I == E);
6767 }
6868
69 TEST_F(InstrProfTest, get_instr_prof_record) {
70 InstrProfRecord Record1("foo", 0x1234, {1, 2});
71 InstrProfRecord Record2("foo", 0x1235, {3, 4});
72 Writer.addRecord(std::move(Record1));
73 Writer.addRecord(std::move(Record2));
74 auto Profile = Writer.writeBuffer();
75 readProfile(std::move(Profile));
76
77 ErrorOr R = Reader->getInstrProfRecord("foo", 0x1234);
78 ASSERT_TRUE(NoError(R.getError()));
79 ASSERT_EQ(2U, R.get().Counts.size());
80 ASSERT_EQ(1U, R.get().Counts[0]);
81 ASSERT_EQ(2U, R.get().Counts[1]);
82
83 R = Reader->getInstrProfRecord("foo", 0x1235);
84 ASSERT_TRUE(NoError(R.getError()));
85 ASSERT_EQ(2U, R.get().Counts.size());
86 ASSERT_EQ(3U, R.get().Counts[0]);
87 ASSERT_EQ(4U, R.get().Counts[1]);
88
89 R = Reader->getInstrProfRecord("foo", 0x5678);
90 ASSERT_TRUE(ErrorEquals(instrprof_error::hash_mismatch, R.getError()));
91
92 R = Reader->getInstrProfRecord("bar", 0x1234);
93 ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, R.getError()));
94 }
95
6996 TEST_F(InstrProfTest, get_function_counts) {
7097 InstrProfRecord Record1("foo", 0x1234, {1, 2});
7198 InstrProfRecord Record2("foo", 0x1235, {3, 4});
93120 ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, EC));
94121 }
95122
123 TEST_F(InstrProfTest, get_icall_data_read_write) {
124 InstrProfRecord Record1("caller", 0x1234, {1, 2});
125 InstrProfRecord Record2("callee1", 0x1235, {3, 4});
126 InstrProfRecord Record3("callee2", 0x1235, {3, 4});
127 InstrProfRecord Record4("callee3", 0x1235, {3, 4});
128
129 // 4 value sites.
130 Record1.reserveSites(IPVK_IndirectCallTarget, 4);
131 InstrProfValueData VD0[] = {{(uint64_t) "callee1", 1},
132 {(uint64_t) "callee2", 2},
133 {(uint64_t) "callee3", 3}};
134 Record1.addValueData(IPVK_IndirectCallTarget, 0, VD0, 3, 0);
135 // No valeu profile data at the second site.
136 Record1.addValueData(IPVK_IndirectCallTarget, 1, 0, 0, 0);
137 InstrProfValueData VD2[] = {{(uint64_t) "callee1", 1},
138 {(uint64_t) "callee2", 2}};
139 Record1.addValueData(IPVK_IndirectCallTarget, 2, VD2, 2, 0);
140 InstrProfValueData VD3[] = {{(uint64_t) "callee1", 1}};
141 Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, 0);
142
143 Writer.addRecord(std::move(Record1));
144 Writer.addRecord(std::move(Record2));
145 Writer.addRecord(std::move(Record3));
146 Writer.addRecord(std::move(Record4));
147 auto Profile = Writer.writeBuffer();
148 readProfile(std::move(Profile));
149
150 ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234);
151 ASSERT_TRUE(NoError(R.getError()));
152 ASSERT_EQ(4U, R.get().getNumValueSites(IPVK_IndirectCallTarget));
153 ASSERT_EQ(3U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 0));
154 ASSERT_EQ(0U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 1));
155 ASSERT_EQ(2U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 2));
156 ASSERT_EQ(1U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 3));
157
158 std::unique_ptr VD =
159 R.get().getValueForSite(IPVK_IndirectCallTarget, 0);
160 // Now sort the target acording to frequency.
161 std::sort(&VD[0], &VD[3],
162 [](const InstrProfValueData &VD1, const InstrProfValueData &VD2) {
163 return VD1.Count > VD2.Count;
164 });
165 ASSERT_EQ(StringRef((const char *)VD[0].Value, 7), StringRef("callee3"));
166 ASSERT_EQ(StringRef((const char *)VD[1].Value, 7), StringRef("callee2"));
167 ASSERT_EQ(StringRef((const char *)VD[2].Value, 7), StringRef("callee1"));
168 }
169
170 TEST_F(InstrProfTest, get_icall_data_merge1) {
171 InstrProfRecord Record11("caller", 0x1234, {1, 2});
172 InstrProfRecord Record12("caller", 0x1234, {1, 2});
173 InstrProfRecord Record2("callee1", 0x1235, {3, 4});
174 InstrProfRecord Record3("callee2", 0x1235, {3, 4});
175 InstrProfRecord Record4("callee3", 0x1235, {3, 4});
176 InstrProfRecord Record5("callee3", 0x1235, {3, 4});
177 InstrProfRecord Record6("callee4", 0x1235, {3, 5});
178
179 // 5 value sites.
180 Record11.reserveSites(IPVK_IndirectCallTarget, 5);
181 InstrProfValueData VD0[] = {{(uint64_t) "callee1", 1},
182 {(uint64_t) "callee2", 2},
183 {(uint64_t) "callee3", 3},
184 {(uint64_t) "callee4", 4}};
185 Record11.addValueData(IPVK_IndirectCallTarget, 0, VD0, 4, 0);
186
187 // No valeu profile data at the second site.
188 Record11.addValueData(IPVK_IndirectCallTarget, 1, 0, 0, 0);
189
190 InstrProfValueData VD2[] = {{(uint64_t) "callee1", 1},
191 {(uint64_t) "callee2", 2},
192 {(uint64_t) "callee3", 3}};
193 Record11.addValueData(IPVK_IndirectCallTarget, 2, VD2, 3, 0);
194
195 InstrProfValueData VD3[] = {{(uint64_t) "callee1", 1}};
196 Record11.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, 0);
197
198 InstrProfValueData VD4[] = {{(uint64_t) "callee1", 1},
199 {(uint64_t) "callee2", 2},
200 {(uint64_t) "callee3", 3}};
201 Record11.addValueData(IPVK_IndirectCallTarget, 4, VD4, 3, 0);
202
203 // A differnt record for the same caller.
204 Record12.reserveSites(IPVK_IndirectCallTarget, 5);
205 InstrProfValueData VD02[] = {{(uint64_t) "callee2", 5},
206 {(uint64_t) "callee3", 3}};
207 Record12.addValueData(IPVK_IndirectCallTarget, 0, VD02, 2, 0);
208
209 // No valeu profile data at the second site.
210 Record12.addValueData(IPVK_IndirectCallTarget, 1, 0, 0, 0);
211
212 InstrProfValueData VD22[] = {{(uint64_t) "callee2", 1},
213 {(uint64_t) "callee3", 3},
214 {(uint64_t) "callee4", 4}};
215 Record12.addValueData(IPVK_IndirectCallTarget, 2, VD22, 3, 0);
216
217 Record12.addValueData(IPVK_IndirectCallTarget, 3, 0, 0, 0);
218
219 InstrProfValueData VD42[] = {{(uint64_t) "callee1", 1},
220 {(uint64_t) "callee2", 2},
221 {(uint64_t) "callee3", 3}};
222 Record12.addValueData(IPVK_IndirectCallTarget, 4, VD42, 3, 0);
223
224 Writer.addRecord(std::move(Record11));
225 // Merge profile data.
226 Writer.addRecord(std::move(Record12));
227
228 Writer.addRecord(std::move(Record2));
229 Writer.addRecord(std::move(Record3));
230 Writer.addRecord(std::move(Record4));
231 Writer.addRecord(std::move(Record5));
232 Writer.addRecord(std::move(Record6));
233 auto Profile = Writer.writeBuffer();
234 readProfile(std::move(Profile));
235
236 ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234);
237 ASSERT_TRUE(NoError(R.getError()));
238 ASSERT_EQ(5U, R.get().getNumValueSites(IPVK_IndirectCallTarget));
239 ASSERT_EQ(4U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 0));
240 ASSERT_EQ(0U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 1));
241 ASSERT_EQ(4U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 2));
242 ASSERT_EQ(1U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 3));
243 ASSERT_EQ(3U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 4));
244
245 std::unique_ptr VD =
246 R.get().getValueForSite(IPVK_IndirectCallTarget, 0);
247 // Now sort the target acording to frequency.
248 std::sort(&VD[0], &VD[4],
249 [](const InstrProfValueData &VD1, const InstrProfValueData &VD2) {
250 return VD1.Count > VD2.Count;
251 });
252 ASSERT_EQ(StringRef((const char *)VD[0].Value, 7), StringRef("callee2"));
253 ASSERT_EQ(7U, VD[0].Count);
254 ASSERT_EQ(StringRef((const char *)VD[1].Value, 7), StringRef("callee3"));
255 ASSERT_EQ(6U, VD[1].Count);
256 ASSERT_EQ(StringRef((const char *)VD[2].Value, 7), StringRef("callee4"));
257 ASSERT_EQ(4U, VD[2].Count);
258 ASSERT_EQ(StringRef((const char *)VD[3].Value, 7), StringRef("callee1"));
259 ASSERT_EQ(1U, VD[3].Count);
260
261 std::unique_ptr VD_2(
262 R.get().getValueForSite(IPVK_IndirectCallTarget, 2));
263 std::sort(&VD_2[0], &VD_2[4],
264 [](const InstrProfValueData &VD1, const InstrProfValueData &VD2) {
265 return VD1.Count > VD2.Count;
266 });
267 ASSERT_EQ(StringRef((const char *)VD_2[0].Value, 7), StringRef("callee3"));
268 ASSERT_EQ(6U, VD_2[0].Count);
269 ASSERT_EQ(StringRef((const char *)VD_2[1].Value, 7), StringRef("callee4"));
270 ASSERT_EQ(4U, VD_2[1].Count);
271 ASSERT_EQ(StringRef((const char *)VD_2[2].Value, 7), StringRef("callee2"));
272 ASSERT_EQ(3U, VD_2[2].Count);
273 ASSERT_EQ(StringRef((const char *)VD_2[3].Value, 7), StringRef("callee1"));
274 ASSERT_EQ(1U, VD_2[3].Count);
275
276 std::unique_ptr VD_3(
277 R.get().getValueForSite(IPVK_IndirectCallTarget, 3));
278 ASSERT_EQ(StringRef((const char *)VD_3[0].Value, 7), StringRef("callee1"));
279 ASSERT_EQ(1U, VD_3[0].Count);
280
281 std::unique_ptr VD_4(
282 R.get().getValueForSite(IPVK_IndirectCallTarget, 4));
283 std::sort(&VD_4[0], &VD_4[3],
284 [](const InstrProfValueData &VD1, const InstrProfValueData &VD2) {
285 return VD1.Count > VD2.Count;
286 });
287 ASSERT_EQ(StringRef((const char *)VD_4[0].Value, 7), StringRef("callee3"));
288 ASSERT_EQ(6U, VD_4[0].Count);
289 ASSERT_EQ(StringRef((const char *)VD_4[1].Value, 7), StringRef("callee2"));
290 ASSERT_EQ(4U, VD_4[1].Count);
291 ASSERT_EQ(StringRef((const char *)VD_4[2].Value, 7), StringRef("callee1"));
292 ASSERT_EQ(2U, VD_4[2].Count);
293 }
294
96295 TEST_F(InstrProfTest, get_max_function_count) {
97296 InstrProfRecord Record1("foo", 0x1234, {1ULL << 31, 2});
98297 InstrProfRecord Record2("bar", 0, {1ULL << 63});