llvm.org GIT mirror llvm / bcd8e0a
[PGO] Make indexed value profile data more compact - Make indexed value profile data more compact by peeling out the per-site value count field into its own smaller sized array. - Introduced formal data structure definitions to specify value profile data layout in indexed format. Previously the layout of the data is only assumed in the client code (scattered in three different places : size computation, EmitData, and ReadData - The new data structure serves as a central place for layout documentation. - Add interfaces to force BE output for value profile data (testing purpose) - Add byte swap unit tests Differential Revision: http://reviews.llvm.org/D14401 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252563 91177308-0d34-0410-b5e6-96231b3b80d8 Xinliang David Li 3 years ago
7 changed file(s) with 455 addition(s) and 92 deletion(s). Raw diff Collapse all Expand all
2020 #include "llvm/IR/GlobalValue.h"
2121 #include "llvm/Support/Endian.h"
2222 #include "llvm/Support/ErrorHandling.h"
23 #include "llvm/Support/ErrorOr.h"
2324 #include "llvm/Support/MD5.h"
2425 #include
2526 #include
317318 return NumValueKinds;
318319 }
319320
321 uint32_t InstrProfRecord::getNumValueData(uint32_t ValueKind) const {
322 uint32_t N = 0;
323 const std::vector &SiteRecords =
324 getValueSitesForKind(ValueKind);
325 for (auto &SR : SiteRecords) {
326 N += SR.ValueData.size();
327 }
328 return N;
329 }
330
320331 uint32_t InstrProfRecord::getNumValueSites(uint32_t ValueKind) const {
321332 return getValueSitesForKind(ValueKind).size();
322333 }
418429 const uint64_t Version = 3;
419430 const HashT HashType = HashT::MD5;
420431
432 // This structure defines the file header of the LLVM profile
433 // data file in indexed-format.
421434 struct Header {
422435 uint64_t Magic;
423436 uint64_t Version;
424437 uint64_t MaxFunctionCount;
425438 uint64_t HashType;
426439 uint64_t HashOffset;
440 };
441
442 inline support::endianness getHostEndianness() {
443 return sys::IsLittleEndianHost ? support::little : support::big;
444 }
445
446 /// This is the header of the data structure that defines the on-disk
447 /// layout of the value profile data of a particular kind for one function.
448 struct ValueProfRecord {
449 // The kind of the value profile record.
450 uint32_t Kind;
451 // The number of value profile sites. It is guaranteed to be non-zero;
452 // otherwise the record for this kind won't be emitted.
453 uint32_t NumValueSites;
454 // The first element of the array that stores the number of profiled
455 // values for each value site. The size of the array is NumValueSites.
456 // Since NumValueSites is greater than zero, there is at least one
457 // element in the array.
458 uint8_t SiteCountArray[1];
459
460 // The fake declaration is for documentation purpose only.
461 // Align the start of next field to be on 8 byte boundaries.
462 // uint8_t Padding[X];
463
464 // The array of value profile data. The size of the array is the sum
465 // of all elements in SiteCountArray[].
466 // InstrProfValueData ValueData[];
467
468 /// Return the \c ValueProfRecord header size including the padding bytes.
469 static uint32_t getHeaderSize(uint32_t NumValueSites);
470 /// Return the total size of the value profile record including the
471 /// header and the value data.
472 static uint32_t getSize(uint32_t NumValueSites, uint32_t NumValueData);
473 /// Return the total size of the value profile record including the
474 /// header and the value data.
475 uint32_t getSize() const { return getSize(NumValueSites, getNumValueData()); }
476 /// Use this method to advance to the next \c ValueProfRecord.
477 ValueProfRecord *getNext();
478 /// Return the pointer to the first value profile data.
479 InstrProfValueData *getValueData();
480 /// Return the number of value sites.
481 uint32_t getNumValueSites() const { return NumValueSites; }
482 /// Return the number of value data.
483 uint32_t getNumValueData() const;
484 /// Read data from this record and save it to Record.
485 void deserializeTo(InstrProfRecord &Record,
486 InstrProfRecord::ValueMapType *VMap);
487 /// Extract data from \c Record and serialize into this instance.
488 void serializeFrom(const InstrProfRecord &Record, uint32_t ValueKind,
489 uint32_t NumValueSites);
490 /// In-place byte swap:
491 /// Do byte swap for this instance. \c Old is the original order before
492 /// the swap, and \c New is the New byte order.
493 void swapBytes(support::endianness Old, support::endianness New);
494 };
495
496 /// Per-function header/control data structure for value profiling
497 /// data in indexed format.
498 struct ValueProfData {
499 // Total size in bytes including this field. It must be a multiple
500 // of sizeof(uint64_t).
501 uint32_t TotalSize;
502 // The number of value profile kinds that has value profile data.
503 // In this implementation, a value profile kind is considered to
504 // have profile data if the number of value profile sites for the
505 // kind is not zero. More aggressively, the implemnetation can
506 // choose to check the actual data value: if none of the value sites
507 // has any profiled values, the kind can be skipped.
508 uint32_t NumValueKinds;
509
510 // Following are a sequence of variable length records. The prefix/header
511 // of each record is defined by ValueProfRecord type. The number of
512 // records is NumValueKinds.
513 // ValueProfRecord Record_1;
514 // ValueProfRecord Record_N;
515
516 /// Return the total size in bytes of the on-disk value profile data
517 /// given the data stored in Record.
518 static uint32_t getSize(const InstrProfRecord &Record);
519 /// Return a pointer to \c ValueProfData instance ready to be streamed.
520 static std::unique_ptr
521 serializeFrom(const InstrProfRecord &Record);
522 /// Return a pointer to \c ValueProfileData instance ready to be read.
523 /// All data in the instance are properly byte swapped. The input
524 /// data is assumed to be in little endian order.
525 static ErrorOr>
526 getValueProfData(const unsigned char *D, const unsigned char *const BufferEnd,
527 support::endianness SrcDataEndianness);
528 /// Swap byte order from \c Endianness order to host byte order.
529 void swapBytesToHost(support::endianness Endianness);
530 /// Swap byte order from host byte order to \c Endianness order.
531 void swapBytesFromHost(support::endianness Endianness);
532 /// Return the total size of \c ValueProfileData.
533 uint32_t getSize() const { return TotalSize; }
534 /// Read data from this data and save it to \c Record.
535 void deserializeTo(InstrProfRecord &Record,
536 InstrProfRecord::ValueMapType *VMap);
537 /// Return the first \c ValueProfRecord instance.
538 ValueProfRecord *getFirstValueProfRecord();
427539 };
428540
429541 } // end namespace IndexedInstrProf
457569 uint64_t('R') << 8 | uint64_t(129);
458570 }
459571
572 // Per-function profile data header/control structure.
460573 // The definition should match the structure defined in
461574 // compiler-rt/lib/profile/InstrProfiling.h.
462575 // It should also match the synthesized type in
463576 // Transforms/Instrumentation/InstrProfiling.cpp:getOrCreateRegionCounters.
464
465577 template struct ProfileData {
466578 #define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Type Name;
467579 #include "llvm/ProfileData/InstrProfData.inc"
468580 };
469581
582 // File header structure of the LLVM profile data in raw format.
470583 // The definition should match the header referenced in
471584 // compiler-rt/lib/profile/InstrProfilingFile.c and
472585 // InstrProfilingBuffer.c.
473
474586 struct Header {
475587 const uint64_t Magic;
476588 const uint64_t Version;
485597
486598 namespace coverage {
487599
600 // Profile coverage map has the following layout:
601 // [CoverageMapFileHeader]
602 // [ArrayStart]
603 // [CovMapFunctionRecord]
604 // [CovMapFunctionRecord]
605 // ...
606 // [ArrayEnd]
607 // [Encoded Region Mapping Data]
488608 LLVM_PACKED_START
489609 template struct CovMapFunctionRecord {
490610 #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name;
185185 std::vector DataBuffer;
186186 IndexedInstrProf::HashT HashType;
187187 unsigned FormatVersion;
188 // Endianness of the input value profile data.
189 // It should be LE by default, but can be changed
190 // for testing purpose.
191 support::endianness ValueProfDataEndianness;
188192 std::vector> HashKeys;
189193
190194 public:
191195 InstrProfLookupTrait(IndexedInstrProf::HashT HashType, unsigned FormatVersion)
192 : HashType(HashType), FormatVersion(FormatVersion) {}
196 : HashType(HashType), FormatVersion(FormatVersion),
197 ValueProfDataEndianness(support::little) {}
193198
194199 typedef ArrayRef data_type;
195200
222227 bool ReadValueProfilingData(const unsigned char *&D,
223228 const unsigned char *const End);
224229 data_type ReadData(StringRef K, const unsigned char *D, offset_type N);
230
231 // Used for testing purpose only.
232 void setValueProfDataEndianness(support::endianness Endianness) {
233 ValueProfDataEndianness = Endianness;
234 }
225235 };
226236
227237 class InstrProfReaderIndex {
250260
251261 void advanceToNextKey() { RecordIterator++; }
252262 bool atEnd() const { return RecordIterator == Index->data_end(); }
263 // Used for testing purpose only.
264 void setValueProfDataEndianness(support::endianness Endianness) {
265 Index->getInfoObj().setValueProfDataEndianness(Endianness);
266 }
253267 };
254268
255269 /// Reader for the indexed binary instrprof format.
294308
295309 static ErrorOr>
296310 create(std::unique_ptr Buffer);
311
312 // Used for testing purpose only.
313 void setValueProfDataEndianness(support::endianness Endianness) {
314 Index.setValueProfDataEndianness(Endianness);
315 }
297316 };
298317
299318 } // end namespace llvm
4545 /// Write the profile, returning the raw data. For testing.
4646 std::unique_ptr writeBuffer();
4747
48 // Internal interface for testing purpose only.
49 void setValueProfDataEndianness(support::endianness Endianness);
50
4851 private:
4952 std::pair writeImpl(raw_ostream &OS);
5053 };
127127 GlobalVariable *createPGOFuncNameVar(Function &F, StringRef FuncName) {
128128 return createPGOFuncNameVar(*F.getParent(), F.getLinkage(), FuncName);
129129 }
130 }
130
131 namespace IndexedInstrProf {
132
133 uint32_t ValueProfRecord::getHeaderSize(uint32_t NumValueSites) {
134 uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) +
135 sizeof(uint8_t) * NumValueSites;
136 // Round the size to multiple of 8 bytes.
137 Size = (Size + 7) & ~7;
138 return Size;
139 }
140
141 uint32_t ValueProfRecord::getSize(uint32_t NumValueSites,
142 uint32_t NumValueData) {
143 return getHeaderSize(NumValueSites) +
144 sizeof(InstrProfValueData) * NumValueData;
145 }
146
147 void ValueProfRecord::deserializeTo(InstrProfRecord &Record,
148 InstrProfRecord::ValueMapType *VMap) {
149 Record.reserveSites(Kind, NumValueSites);
150
151 InstrProfValueData *ValueData = this->getValueData();
152 for (uint64_t VSite = 0; VSite < NumValueSites; ++VSite) {
153 uint8_t ValueDataCount = this->SiteCountArray[VSite];
154 Record.addValueData(Kind, VSite, ValueData, ValueDataCount, VMap);
155 ValueData += ValueDataCount;
156 }
157 }
158
159 void ValueProfRecord::serializeFrom(const InstrProfRecord &Record,
160 uint32_t ValueKind,
161 uint32_t NumValueSites) {
162 Kind = ValueKind;
163 this->NumValueSites = NumValueSites;
164 InstrProfValueData *DstVD = getValueData();
165 for (uint32_t S = 0; S < NumValueSites; S++) {
166 uint32_t ND = Record.getNumValueDataForSite(ValueKind, S);
167 SiteCountArray[S] = ND;
168 std::unique_ptr SrcVD =
169 Record.getValueForSite(ValueKind, S);
170 for (uint32_t I = 0; I < ND; I++) {
171 DstVD[I] = SrcVD[I];
172 switch (ValueKind) {
173 case IPVK_IndirectCallTarget:
174 DstVD[I].Value = ComputeHash(HashType, (const char *)DstVD[I].Value);
175 break;
176 default:
177 llvm_unreachable("value kind not handled !");
178 }
179 }
180 DstVD += ND;
181 }
182 }
183
184 template static T swapToHostOrder(T v, support::endianness Orig) {
185 if (Orig == getHostEndianness())
186 return v;
187 sys::swapByteOrder(v);
188 return v;
189 }
190
191 // For writing/serializing, Old is the host endianness, and New is
192 // byte order intended on disk. For Reading/deserialization, Old
193 // is the on-disk source endianness, and New is the host endianness.
194 void ValueProfRecord::swapBytes(support::endianness Old,
195 support::endianness New) {
196 using namespace support;
197 if (Old == New)
198 return;
199
200 if (getHostEndianness() != Old) {
201 sys::swapByteOrder(NumValueSites);
202 sys::swapByteOrder(Kind);
203 }
204 uint32_t ND = getNumValueData();
205 InstrProfValueData *VD = getValueData();
206
207 // No need to swap byte array: SiteCountArrray.
208 for (uint32_t I = 0; I < ND; I++) {
209 sys::swapByteOrder(VD[I].Value);
210 sys::swapByteOrder(VD[I].Count);
211 }
212 if (getHostEndianness() == Old) {
213 sys::swapByteOrder(NumValueSites);
214 sys::swapByteOrder(Kind);
215 }
216 }
217
218 uint32_t ValueProfData::getSize(const InstrProfRecord &Record) {
219 uint32_t TotalSize = sizeof(ValueProfData);
220 uint32_t NumValueKinds = Record.getNumValueKinds();
221 if (NumValueKinds == 0)
222 return TotalSize;
223
224 for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; Kind++) {
225 uint32_t NumValueSites = Record.getNumValueSites(Kind);
226 if (!NumValueSites)
227 continue;
228 TotalSize +=
229 ValueProfRecord::getSize(NumValueSites, Record.getNumValueData(Kind));
230 }
231 return TotalSize;
232 }
233
234 void ValueProfData::deserializeTo(InstrProfRecord &Record,
235 InstrProfRecord::ValueMapType *VMap) {
236 if (NumValueKinds == 0)
237 return;
238
239 ValueProfRecord *VR = getFirstValueProfRecord();
240 for (uint32_t K = 0; K < NumValueKinds; K++) {
241 VR->deserializeTo(Record, VMap);
242 VR = VR->getNext();
243 }
244 }
245
246 std::unique_ptr
247 ValueProfData::serializeFrom(const InstrProfRecord &Record) {
248 uint32_t TotalSize = getSize(Record);
249 std::unique_ptr VPD(
250 reinterpret_cast(new char[TotalSize]));
251
252 VPD->TotalSize = TotalSize;
253 VPD->NumValueKinds = Record.getNumValueKinds();
254 ValueProfRecord *VR = VPD->getFirstValueProfRecord();
255 for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; Kind++) {
256 uint32_t NumValueSites = Record.getNumValueSites(Kind);
257 if (!NumValueSites)
258 continue;
259 VR->serializeFrom(Record, Kind, NumValueSites);
260 VR = VR->getNext();
261 }
262 return VPD;
263 }
264
265 ErrorOr>
266 ValueProfData::getValueProfData(const unsigned char *D,
267 const unsigned char *const BufferEnd,
268 support::endianness Endianness) {
269 using namespace support;
270 if (D + sizeof(ValueProfData) > BufferEnd)
271 return instrprof_error::truncated;
272
273 uint32_t TotalSize = swapToHostOrder(
274 reinterpret_cast(D)[0], Endianness);
275 uint32_t NumValueKinds = swapToHostOrder(
276 reinterpret_cast(D)[1], Endianness);
277
278 if (D + TotalSize > BufferEnd)
279 return instrprof_error::too_large;
280 if (NumValueKinds > IPVK_Last + 1)
281 return instrprof_error::malformed;
282 // Total size needs to be mulltiple of quadword size.
283 if (TotalSize % sizeof(uint64_t))
284 return instrprof_error::malformed;
285
286 std::unique_ptr VPD(
287 reinterpret_cast(new char[TotalSize]));
288 memcpy(VPD.get(), D, TotalSize);
289 // Byte swap.
290 VPD->swapBytesToHost(Endianness);
291
292 // Data integrety check:
293 ValueProfRecord *VR = VPD->getFirstValueProfRecord();
294 for (uint32_t K = 0; K < VPD->NumValueKinds; K++) {
295 if (VR->Kind > IPVK_Last)
296 return instrprof_error::malformed;
297 VR = VR->getNext();
298 if ((char *)VR - (char *)VPD.get() > TotalSize)
299 return instrprof_error::malformed;
300 }
301
302 D += TotalSize;
303 return std::move(VPD);
304 }
305
306 void ValueProfData::swapBytesToHost(support::endianness Endianness) {
307 using namespace support;
308 if (Endianness == getHostEndianness())
309 return;
310
311 sys::swapByteOrder(TotalSize);
312 sys::swapByteOrder(NumValueKinds);
313
314 ValueProfRecord *VR = getFirstValueProfRecord();
315 for (uint32_t K = 0; K < NumValueKinds; K++) {
316 VR->swapBytes(Endianness, getHostEndianness());
317 VR = VR->getNext();
318 }
319 }
320
321 void ValueProfData::swapBytesFromHost(support::endianness Endianness) {
322 using namespace support;
323 if (Endianness == getHostEndianness())
324 return;
325
326 ValueProfRecord *VR = getFirstValueProfRecord();
327 for (uint32_t K = 0; K < NumValueKinds; K++) {
328 ValueProfRecord *NVR = VR->getNext();
329 VR->swapBytes(getHostEndianness(), Endianness);
330 VR = NVR;
331 }
332 sys::swapByteOrder(TotalSize);
333 sys::swapByteOrder(NumValueKinds);
334 }
335
336 ValueProfRecord *ValueProfData::getFirstValueProfRecord() {
337 return reinterpret_cast((char *)this +
338 sizeof(ValueProfData));
339 }
340
341 uint32_t ValueProfRecord::getNumValueData() const {
342 uint32_t NumValueData = 0;
343 for (uint32_t I = 0; I < NumValueSites; I++)
344 NumValueData += SiteCountArray[I];
345 return NumValueData;
346 }
347
348 ValueProfRecord *ValueProfRecord::getNext() {
349 return reinterpret_cast((char *)this + getSize());
350 }
351
352 InstrProfValueData *ValueProfRecord::getValueData() {
353 return reinterpret_cast((char *)this +
354 getHeaderSize(NumValueSites));
355 }
356
357 } // End of IndexedInstrProf namespace.
358 }
297297
298298 bool InstrProfLookupTrait::ReadValueProfilingData(
299299 const unsigned char *&D, const unsigned char *const End) {
300
301 using namespace support;
302 // Read number of value kinds with value sites.
303 if (D + sizeof(uint64_t) > End)
300 ErrorOr> VDataPtrOrErr =
301 IndexedInstrProf::ValueProfData::getValueProfData(
302 D, End, ValueProfDataEndianness);
303
304 if (VDataPtrOrErr.getError())
304305 return false;
305 uint64_t ValueKindCount = endian::readNext(D);
306
307 InstrProfRecord &ProfRecord = DataBuffer.back();
308 for (uint32_t Kind = 0; Kind < ValueKindCount; ++Kind) {
309
310 // Read value kind and number of value sites for kind.
311 if (D + 2 * sizeof(uint64_t) > End)
312 return false;
313
314 uint64_t ValueKind = endian::readNext(D);
315 uint64_t ValueSiteCount = endian::readNext(D);
316
317 ProfRecord.reserveSites(ValueKind, ValueSiteCount);
318
319 for (uint64_t VSite = 0; VSite < ValueSiteCount; ++VSite) {
320 // Read number of value data pairs at value site.
321 if (D + sizeof(uint64_t) > End)
322 return false;
323
324 uint64_t ValueDataCount =
325 endian::readNext(D);
326
327 // Check if there are as many ValueDataPairs as ValueDataCount in memory.
328 if (D + (ValueDataCount << 1) * sizeof(uint64_t) > End)
329 return false;
330
331 std::unique_ptr VDataPtr(
332 ValueDataCount == 0 ? nullptr
333 : new InstrProfValueData[ValueDataCount]);
334
335 for (uint64_t VCount = 0; VCount < ValueDataCount; ++VCount) {
336 VDataPtr[VCount].Value =
337 endian::readNext(D);
338 VDataPtr[VCount].Count =
339 endian::readNext(D);
340 }
341 ProfRecord.addValueData(ValueKind, VSite, VDataPtr.get(), ValueDataCount,
342 &HashKeys);
343 }
344 }
306
307 VDataPtrOrErr.get()->deserializeTo(DataBuffer.back(), &HashKeys);
308 D += VDataPtrOrErr.get()->TotalSize;
309
345310 return true;
346311 }
347312
1919 using namespace llvm;
2020
2121 namespace {
22 static support::endianness ValueProfDataEndianness = support::little;
23
2224 class InstrProfRecordTrait {
2325 public:
2426 typedef StringRef key_type;
5052 M += ProfRecord.Counts.size() * sizeof(uint64_t);
5153
5254 // Value data
53 M += sizeof(uint64_t); // Number of value kinds with value sites.
54 for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
55 uint32_t NumValueSites = ProfRecord.getNumValueSites(Kind);
56 if (NumValueSites == 0)
57 continue;
58 M += sizeof(uint64_t); // Value kind
59 M += sizeof(uint64_t); // The number of value sites for given value kind
60 for (uint32_t I = 0; I < NumValueSites; I++) {
61 M += sizeof(uint64_t); // Number of value data pairs at a value site
62 uint64_t NumValueDataForSite =
63 ProfRecord.getNumValueDataForSite(Kind, I);
64 M += 2 * sizeof(uint64_t) * NumValueDataForSite; // Value data pairs
65 }
66 }
55 M += IndexedInstrProf::ValueProfData::getSize(ProfileData.second);
6756 }
6857 LE.write(M);
6958
8675 for (uint64_t I : ProfRecord.Counts)
8776 LE.write(I);
8877
89 // Compute the number of value kinds with value sites.
90 uint64_t NumValueKinds = ProfRecord.getNumValueKinds();
91 LE.write(NumValueKinds);
92
9378 // Write value data
94 for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
95 uint32_t NumValueSites = ProfRecord.getNumValueSites(Kind);
96 if (NumValueSites == 0)
97 continue;
98 LE.write(Kind); // Write value kind
99 // Write number of value sites for current value kind
100 LE.write(NumValueSites);
101
102 for (uint32_t I = 0; I < NumValueSites; I++) {
103 // Write number of value data pairs at this value site
104 uint64_t NumValueDataForSite =
105 ProfRecord.getNumValueDataForSite(Kind, I);
106 LE.write(NumValueDataForSite);
107 std::unique_ptr VD =
108 ProfRecord.getValueForSite(Kind, I);
109
110 for (uint32_t V = 0; V < NumValueDataForSite; V++) {
111 if (Kind == IPVK_IndirectCallTarget)
112 LE.write(ComputeHash((const char *)VD[V].Value));
113 else
114 LE.write(VD[V].Value);
115 LE.write(VD[V].Count);
116 }
117 }
118 }
79 std::unique_ptr VDataPtr =
80 IndexedInstrProf::ValueProfData::serializeFrom(ProfileData.second);
81 uint32_t S = VDataPtr->getSize();
82 VDataPtr->swapBytesFromHost(ValueProfDataEndianness);
83 Out.write((const char *)VDataPtr.get(), S);
11984 }
12085 }
12186 };
145110 MaxFunctionCount = Dest.Counts[0];
146111
147112 return instrprof_error::success;
113 }
114
115 // Internal interface for testing purpose only.
116 void InstrProfWriter::setValueProfDataEndianness(
117 support::endianness Endianness) {
118 ValueProfDataEndianness = Endianness;
148119 }
149120
150121 void InstrProfWriter::updateStringTableReferences(InstrProfRecord &I) {
132132 {(uint64_t) "callee2", 2},
133133 {(uint64_t) "callee3", 3}};
134134 Record1.addValueData(IPVK_IndirectCallTarget, 0, VD0, 3, nullptr);
135 // No valeu profile data at the second site.
135 // No value profile data at the second site.
136136 Record1.addValueData(IPVK_IndirectCallTarget, 1, nullptr, 0, nullptr);
137137 InstrProfValueData VD2[] = {{(uint64_t) "callee1", 1},
138138 {(uint64_t) "callee2", 2}};
165165 ASSERT_EQ(StringRef((const char *)VD[0].Value, 7), StringRef("callee3"));
166166 ASSERT_EQ(StringRef((const char *)VD[1].Value, 7), StringRef("callee2"));
167167 ASSERT_EQ(StringRef((const char *)VD[2].Value, 7), StringRef("callee1"));
168 }
169
170 TEST_F(InstrProfTest, get_icall_data_read_write_big_endian) {
171 InstrProfRecord Record1("caller", 0x1234, {1, 2});
172 InstrProfRecord Record2("callee1", 0x1235, {3, 4});
173 InstrProfRecord Record3("callee2", 0x1235, {3, 4});
174 InstrProfRecord Record4("callee3", 0x1235, {3, 4});
175
176 // 4 value sites.
177 Record1.reserveSites(IPVK_IndirectCallTarget, 4);
178 InstrProfValueData VD0[] = {{(uint64_t) "callee1", 1},
179 {(uint64_t) "callee2", 2},
180 {(uint64_t) "callee3", 3}};
181 Record1.addValueData(IPVK_IndirectCallTarget, 0, VD0, 3, nullptr);
182 // No value profile data at the second site.
183 Record1.addValueData(IPVK_IndirectCallTarget, 1, nullptr, 0, nullptr);
184 InstrProfValueData VD2[] = {{(uint64_t) "callee1", 1},
185 {(uint64_t) "callee2", 2}};
186 Record1.addValueData(IPVK_IndirectCallTarget, 2, VD2, 2, nullptr);
187 InstrProfValueData VD3[] = {{(uint64_t) "callee1", 1}};
188 Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, nullptr);
189
190 Writer.addRecord(std::move(Record1));
191 Writer.addRecord(std::move(Record2));
192 Writer.addRecord(std::move(Record3));
193 Writer.addRecord(std::move(Record4));
194
195 // Set big endian output.
196 Writer.setValueProfDataEndianness(support::big);
197
198 auto Profile = Writer.writeBuffer();
199 readProfile(std::move(Profile));
200
201 // Set big endian input.
202 Reader->setValueProfDataEndianness(support::big);
203
204 ErrorOr R = Reader->getInstrProfRecord("caller", 0x1234);
205 ASSERT_TRUE(NoError(R.getError()));
206 ASSERT_EQ(4U, R.get().getNumValueSites(IPVK_IndirectCallTarget));
207 ASSERT_EQ(3U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 0));
208 ASSERT_EQ(0U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 1));
209 ASSERT_EQ(2U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 2));
210 ASSERT_EQ(1U, R.get().getNumValueDataForSite(IPVK_IndirectCallTarget, 3));
211
212 std::unique_ptr VD =
213 R.get().getValueForSite(IPVK_IndirectCallTarget, 0);
214 // Now sort the target acording to frequency.
215 std::sort(&VD[0], &VD[3],
216 [](const InstrProfValueData &VD1, const InstrProfValueData &VD2) {
217 return VD1.Count > VD2.Count;
218 });
219 ASSERT_EQ(StringRef((const char *)VD[0].Value, 7), StringRef("callee3"));
220 ASSERT_EQ(StringRef((const char *)VD[1].Value, 7), StringRef("callee2"));
221 ASSERT_EQ(StringRef((const char *)VD[2].Value, 7), StringRef("callee1"));
222
223 // Restore little endian default:
224 Writer.setValueProfDataEndianness(support::little);
168225 }
169226
170227 TEST_F(InstrProfTest, get_icall_data_merge1) {