@@ -1249,14 +1249,14 @@ Error IndexedInstrProfReader::readHeader() {
12491249
12501250 // Read the first 64-bit word, which may be RecordTableOffset in
12511251 // memprof::MemProfVersion0 or the MemProf version number in
1252- // memprof::MemProfVersion1.
1252+ // memprof::MemProfVersion1 and above .
12531253 const uint64_t FirstWord =
12541254 support::endian::readNext<uint64_t , llvm::endianness::little>(Ptr);
12551255
12561256 memprof::IndexedVersion Version = memprof::Version0;
1257- if (FirstWord == memprof::Version1) {
1257+ if (FirstWord == memprof::Version1 || FirstWord == memprof::Version2 ) {
12581258 // Everything is good. We can proceed to deserialize the rest.
1259- Version = memprof::Version1 ;
1259+ Version = static_cast < memprof::IndexedVersion>(FirstWord) ;
12601260 } else if (FirstWord >= 24 ) {
12611261 // This is a heuristic/hack to detect memprof::MemProfVersion0,
12621262 // which does not have a version field in the header.
@@ -1286,6 +1286,18 @@ Error IndexedInstrProfReader::readHeader() {
12861286 const uint64_t FrameTableOffset =
12871287 support::endian::readNext<uint64_t , llvm::endianness::little>(Ptr);
12881288
1289+ // The offset in the stream right before invoking
1290+ // CallStackTableGenerator.Emit.
1291+ uint64_t CallStackPayloadOffset = 0 ;
1292+ // The value returned from CallStackTableGenerator.Emit.
1293+ uint64_t CallStackTableOffset = 0 ;
1294+ if (Version >= memprof::Version2) {
1295+ CallStackPayloadOffset =
1296+ support::endian::readNext<uint64_t , llvm::endianness::little>(Ptr);
1297+ CallStackTableOffset =
1298+ support::endian::readNext<uint64_t , llvm::endianness::little>(Ptr);
1299+ }
1300+
12891301 // Read the schema.
12901302 auto SchemaOr = memprof::readMemProfSchema (Ptr);
12911303 if (!SchemaOr)
@@ -1296,20 +1308,30 @@ Error IndexedInstrProfReader::readHeader() {
12961308 MemProfRecordTable.reset (MemProfRecordHashTable::Create (
12971309 /* Buckets=*/ Start + RecordTableOffset,
12981310 /* Payload=*/ Ptr,
1299- /* Base=*/ Start, memprof::RecordLookupTrait (memprof::Version1 , Schema)));
1311+ /* Base=*/ Start, memprof::RecordLookupTrait (Version , Schema)));
13001312
13011313 // Initialize the frame table reader with the payload and bucket offsets.
13021314 MemProfFrameTable.reset (MemProfFrameHashTable::Create (
13031315 /* Buckets=*/ Start + FrameTableOffset,
13041316 /* Payload=*/ Start + FramePayloadOffset,
13051317 /* Base=*/ Start, memprof::FrameLookupTrait ()));
13061318
1319+ if (Version >= memprof::Version2)
1320+ MemProfCallStackTable.reset (MemProfCallStackHashTable::Create (
1321+ /* Buckets=*/ Start + CallStackTableOffset,
1322+ /* Payload=*/ Start + CallStackPayloadOffset,
1323+ /* Base=*/ Start, memprof::CallStackLookupTrait ()));
1324+
13071325#ifdef EXPENSIVE_CHECKS
13081326 // Go through all the records and verify that CSId has been correctly
13091327 // populated. Do this only under EXPENSIVE_CHECKS. Otherwise, we
13101328 // would defeat the purpose of OnDiskIterableChainedHashTable.
1311- for (const auto &Record : MemProfRecordTable->data ())
1312- verifyIndexedMemProfRecord (Record);
1329+ // Note that we can compare CSId against actual call stacks only for
1330+ // Version0 and Version1 because IndexedAllocationInfo::CallStack and
1331+ // IndexedMemProfRecord::CallSites are not populated in Version2.
1332+ if (Version <= memprof::Version1)
1333+ for (const auto &Record : MemProfRecordTable->data ())
1334+ verifyIndexedMemProfRecord (Record);
13131335#endif
13141336 }
13151337
@@ -1502,14 +1524,44 @@ IndexedInstrProfReader::getMemProfRecord(const uint64_t FuncNameHash) {
15021524 return *FrIter;
15031525 };
15041526
1505- memprof::MemProfRecord Record (*Iter, IdToFrameCallback);
1527+ // Setup a callback to convert call stack ids to call stacks using the on-disk
1528+ // hash table.
1529+ std::optional<memprof::CallStackId> LastUnmappedCSId;
1530+ auto CSIdToCallStackCallback = [&](memprof::CallStackId CSId) {
1531+ llvm::SmallVector<memprof::Frame> Frames;
1532+ auto CSIter = MemProfCallStackTable->find (CSId);
1533+ if (CSIter == MemProfCallStackTable->end ()) {
1534+ LastUnmappedCSId = CSId;
1535+ } else {
1536+ const llvm::SmallVector<memprof::FrameId> &CS = *CSIter;
1537+ Frames.reserve (CS.size ());
1538+ for (memprof::FrameId Id : CS)
1539+ Frames.push_back (IdToFrameCallback (Id));
1540+ }
1541+ return Frames;
1542+ };
1543+
1544+ const memprof::IndexedMemProfRecord IndexedRecord = *Iter;
1545+ memprof::MemProfRecord Record;
1546+ if (MemProfCallStackTable)
1547+ Record = IndexedRecord.toMemProfRecord (CSIdToCallStackCallback);
1548+ else
1549+ Record = memprof::MemProfRecord (IndexedRecord, IdToFrameCallback);
15061550
15071551 // Check that all frame ids were successfully converted to frames.
15081552 if (LastUnmappedFrameId) {
15091553 return make_error<InstrProfError>(instrprof_error::hash_mismatch,
15101554 " memprof frame not found for frame id " +
15111555 Twine (*LastUnmappedFrameId));
15121556 }
1557+
1558+ // Check that all call stack ids were successfully converted to call stacks.
1559+ if (LastUnmappedCSId) {
1560+ return make_error<InstrProfError>(
1561+ instrprof_error::hash_mismatch,
1562+ " memprof call stack not found for call stack id " +
1563+ Twine (*LastUnmappedCSId));
1564+ }
15131565 return Record;
15141566}
15151567
0 commit comments