1f8d79198SJustin Bogner //=-- InstrProfReader.cpp - Instrumented profiling reader -------------------=// 2f8d79198SJustin Bogner // 3f8d79198SJustin Bogner // The LLVM Compiler Infrastructure 4f8d79198SJustin Bogner // 5f8d79198SJustin Bogner // This file is distributed under the University of Illinois Open Source 6f8d79198SJustin Bogner // License. See LICENSE.TXT for details. 7f8d79198SJustin Bogner // 8f8d79198SJustin Bogner //===----------------------------------------------------------------------===// 9f8d79198SJustin Bogner // 10f8d79198SJustin Bogner // This file contains support for reading profiling data for clang's 11f8d79198SJustin Bogner // instrumentation based PGO and coverage. 12f8d79198SJustin Bogner // 13f8d79198SJustin Bogner //===----------------------------------------------------------------------===// 14f8d79198SJustin Bogner 15f8d79198SJustin Bogner #include "llvm/ProfileData/InstrProfReader.h" 16f8d79198SJustin Bogner #include "llvm/ProfileData/InstrProf.h" 17f8d79198SJustin Bogner 18f8d79198SJustin Bogner #include <cassert> 19f8d79198SJustin Bogner 20f8d79198SJustin Bogner using namespace llvm; 21f8d79198SJustin Bogner 22f8d79198SJustin Bogner error_code InstrProfReader::create(std::string Path, 23f8d79198SJustin Bogner std::unique_ptr<InstrProfReader> &Result) { 24f8d79198SJustin Bogner std::unique_ptr<MemoryBuffer> Buffer; 25f8d79198SJustin Bogner if (error_code EC = MemoryBuffer::getFileOrSTDIN(Path, Buffer)) 26f8d79198SJustin Bogner return EC; 27f8d79198SJustin Bogner 28f8d79198SJustin Bogner // Sanity check the file. 29f8d79198SJustin Bogner if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max()) 30f8d79198SJustin Bogner return instrprof_error::too_large; 31f8d79198SJustin Bogner 32*09a67f45SDuncan P. N. Exon Smith // Create the reader. 33*09a67f45SDuncan P. N. Exon Smith if (RawInstrProfReader::hasFormat(*Buffer)) 3424b4b653SDuncan P. N. Exon Smith Result.reset(new RawInstrProfReader(Buffer)); 3524b4b653SDuncan P. N. Exon Smith else 3624b4b653SDuncan P. N. Exon Smith Result.reset(new TextInstrProfReader(Buffer)); 37*09a67f45SDuncan P. N. Exon Smith 38*09a67f45SDuncan P. N. Exon Smith // Read the header and return the result. 39531bb481SDuncan P. N. Exon Smith return Result->readHeader(); 40f8d79198SJustin Bogner } 41f8d79198SJustin Bogner 42f8d79198SJustin Bogner void InstrProfIterator::Increment() { 43f8d79198SJustin Bogner if (Reader->readNextRecord(Record)) 44f8d79198SJustin Bogner *this = InstrProfIterator(); 45f8d79198SJustin Bogner } 46f8d79198SJustin Bogner 47f8d79198SJustin Bogner error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { 48f8d79198SJustin Bogner // Skip empty lines. 49f8d79198SJustin Bogner while (!Line.is_at_end() && Line->empty()) 50f8d79198SJustin Bogner ++Line; 51f8d79198SJustin Bogner // If we hit EOF while looking for a name, we're done. 52f8d79198SJustin Bogner if (Line.is_at_end()) 53f8d79198SJustin Bogner return error(instrprof_error::eof); 54f8d79198SJustin Bogner 55f8d79198SJustin Bogner // Read the function name. 56f8d79198SJustin Bogner Record.Name = *Line++; 57f8d79198SJustin Bogner 58f8d79198SJustin Bogner // Read the function hash. 59f8d79198SJustin Bogner if (Line.is_at_end()) 60f8d79198SJustin Bogner return error(instrprof_error::truncated); 61f8d79198SJustin Bogner if ((Line++)->getAsInteger(10, Record.Hash)) 62f8d79198SJustin Bogner return error(instrprof_error::malformed); 63f8d79198SJustin Bogner 64f8d79198SJustin Bogner // Read the number of counters. 65f8d79198SJustin Bogner uint64_t NumCounters; 66f8d79198SJustin Bogner if (Line.is_at_end()) 67f8d79198SJustin Bogner return error(instrprof_error::truncated); 68f8d79198SJustin Bogner if ((Line++)->getAsInteger(10, NumCounters)) 69f8d79198SJustin Bogner return error(instrprof_error::malformed); 70f8d79198SJustin Bogner 71f8d79198SJustin Bogner // Read each counter and fill our internal storage with the values. 72f8d79198SJustin Bogner Counts.clear(); 73f8d79198SJustin Bogner Counts.reserve(NumCounters); 74f8d79198SJustin Bogner for (uint64_t I = 0; I < NumCounters; ++I) { 75f8d79198SJustin Bogner if (Line.is_at_end()) 76f8d79198SJustin Bogner return error(instrprof_error::truncated); 77f8d79198SJustin Bogner uint64_t Count; 78f8d79198SJustin Bogner if ((Line++)->getAsInteger(10, Count)) 79f8d79198SJustin Bogner return error(instrprof_error::malformed); 80f8d79198SJustin Bogner Counts.push_back(Count); 81f8d79198SJustin Bogner } 82f8d79198SJustin Bogner // Give the record a reference to our internal counter storage. 83f8d79198SJustin Bogner Record.Counts = Counts; 84f8d79198SJustin Bogner 85f8d79198SJustin Bogner return success(); 86f8d79198SJustin Bogner } 8724b4b653SDuncan P. N. Exon Smith 8824b4b653SDuncan P. N. Exon Smith RawInstrProfReader::RawInstrProfReader(std::unique_ptr<MemoryBuffer> &DataBuffer) 8924b4b653SDuncan P. N. Exon Smith : DataBuffer(DataBuffer.release()) { } 9024b4b653SDuncan P. N. Exon Smith 91*09a67f45SDuncan P. N. Exon Smith static uint64_t getRawMagic() { 92*09a67f45SDuncan P. N. Exon Smith return 93*09a67f45SDuncan P. N. Exon Smith uint64_t('l') << 56 | 94*09a67f45SDuncan P. N. Exon Smith uint64_t('p') << 48 | 95*09a67f45SDuncan P. N. Exon Smith uint64_t('r') << 40 | 96*09a67f45SDuncan P. N. Exon Smith uint64_t('o') << 32 | 97*09a67f45SDuncan P. N. Exon Smith uint64_t('f') << 24 | 98*09a67f45SDuncan P. N. Exon Smith uint64_t('r') << 16 | 99*09a67f45SDuncan P. N. Exon Smith uint64_t('a') << 8 | 100*09a67f45SDuncan P. N. Exon Smith uint64_t('w'); 101*09a67f45SDuncan P. N. Exon Smith } 102*09a67f45SDuncan P. N. Exon Smith 103*09a67f45SDuncan P. N. Exon Smith bool RawInstrProfReader::hasFormat(const MemoryBuffer &DataBuffer) { 104*09a67f45SDuncan P. N. Exon Smith if (DataBuffer.getBufferSize() < sizeof(getRawMagic())) 105*09a67f45SDuncan P. N. Exon Smith return false; 106*09a67f45SDuncan P. N. Exon Smith const RawHeader *Header = (const RawHeader *)DataBuffer.getBufferStart(); 107*09a67f45SDuncan P. N. Exon Smith return getRawMagic() == Header->Magic || 108*09a67f45SDuncan P. N. Exon Smith sys::SwapByteOrder(getRawMagic()) == Header->Magic; 109*09a67f45SDuncan P. N. Exon Smith } 110*09a67f45SDuncan P. N. Exon Smith 11124b4b653SDuncan P. N. Exon Smith error_code RawInstrProfReader::readHeader() { 112*09a67f45SDuncan P. N. Exon Smith if (!hasFormat(*DataBuffer)) 113*09a67f45SDuncan P. N. Exon Smith return error(instrprof_error::bad_magic); 11424b4b653SDuncan P. N. Exon Smith if (DataBuffer->getBufferSize() < sizeof(RawHeader)) 115531bb481SDuncan P. N. Exon Smith return error(instrprof_error::bad_header); 116*09a67f45SDuncan P. N. Exon Smith const RawHeader *Header = (const RawHeader *)DataBuffer->getBufferStart(); 117*09a67f45SDuncan P. N. Exon Smith ShouldSwapBytes = Header->Magic != getRawMagic(); 11824b4b653SDuncan P. N. Exon Smith return readHeader(*Header); 11924b4b653SDuncan P. N. Exon Smith } 12024b4b653SDuncan P. N. Exon Smith 121*09a67f45SDuncan P. N. Exon Smith static uint64_t getRawVersion() { 122*09a67f45SDuncan P. N. Exon Smith return 1; 123*09a67f45SDuncan P. N. Exon Smith } 124*09a67f45SDuncan P. N. Exon Smith 12524b4b653SDuncan P. N. Exon Smith error_code RawInstrProfReader::readHeader(const RawHeader &Header) { 12624b4b653SDuncan P. N. Exon Smith if (swap(Header.Version) != getRawVersion()) 12724b4b653SDuncan P. N. Exon Smith return error(instrprof_error::unsupported_version); 12824b4b653SDuncan P. N. Exon Smith 12924b4b653SDuncan P. N. Exon Smith CountersDelta = swap(Header.CountersDelta); 13024b4b653SDuncan P. N. Exon Smith NamesDelta = swap(Header.NamesDelta); 13124b4b653SDuncan P. N. Exon Smith auto DataSize = swap(Header.DataSize); 13224b4b653SDuncan P. N. Exon Smith auto CountersSize = swap(Header.CountersSize); 13324b4b653SDuncan P. N. Exon Smith auto NamesSize = swap(Header.NamesSize); 13424b4b653SDuncan P. N. Exon Smith 13524b4b653SDuncan P. N. Exon Smith ptrdiff_t DataOffset = sizeof(RawHeader); 13624b4b653SDuncan P. N. Exon Smith ptrdiff_t CountersOffset = DataOffset + sizeof(ProfileData) * DataSize; 13724b4b653SDuncan P. N. Exon Smith ptrdiff_t NamesOffset = CountersOffset + sizeof(uint64_t) * CountersSize; 13824b4b653SDuncan P. N. Exon Smith size_t FileSize = NamesOffset + sizeof(char) * NamesSize; 13924b4b653SDuncan P. N. Exon Smith 14024b4b653SDuncan P. N. Exon Smith if (FileSize != DataBuffer->getBufferSize()) 141531bb481SDuncan P. N. Exon Smith return error(instrprof_error::bad_header); 14224b4b653SDuncan P. N. Exon Smith 14324b4b653SDuncan P. N. Exon Smith Data = (ProfileData *)(DataBuffer->getBufferStart() + DataOffset); 14424b4b653SDuncan P. N. Exon Smith DataEnd = Data + DataSize; 14524b4b653SDuncan P. N. Exon Smith CountersStart = (uint64_t *)(DataBuffer->getBufferStart() + CountersOffset); 14624b4b653SDuncan P. N. Exon Smith NamesStart = DataBuffer->getBufferStart() + NamesOffset; 14724b4b653SDuncan P. N. Exon Smith 14824b4b653SDuncan P. N. Exon Smith return success(); 14924b4b653SDuncan P. N. Exon Smith } 15024b4b653SDuncan P. N. Exon Smith 15124b4b653SDuncan P. N. Exon Smith error_code RawInstrProfReader::readNextRecord(InstrProfRecord &Record) { 15224b4b653SDuncan P. N. Exon Smith if (Data == DataEnd) 15324b4b653SDuncan P. N. Exon Smith return error(instrprof_error::eof); 15424b4b653SDuncan P. N. Exon Smith 15524b4b653SDuncan P. N. Exon Smith // Get the raw data. 15624b4b653SDuncan P. N. Exon Smith StringRef RawName(getName(Data->NamePtr), swap(Data->NameSize)); 15724b4b653SDuncan P. N. Exon Smith auto RawCounts = makeArrayRef(getCounter(Data->CounterPtr), 15824b4b653SDuncan P. N. Exon Smith swap(Data->NumCounters)); 15924b4b653SDuncan P. N. Exon Smith 16024b4b653SDuncan P. N. Exon Smith // Check bounds. 16124b4b653SDuncan P. N. Exon Smith if (RawName.data() < NamesStart || 16224b4b653SDuncan P. N. Exon Smith RawName.data() + RawName.size() > DataBuffer->getBufferEnd() || 16324b4b653SDuncan P. N. Exon Smith RawCounts.data() < CountersStart || 16424b4b653SDuncan P. N. Exon Smith RawCounts.data() + RawCounts.size() > (uint64_t *)NamesStart) 16524b4b653SDuncan P. N. Exon Smith return error(instrprof_error::malformed); 16624b4b653SDuncan P. N. Exon Smith 16724b4b653SDuncan P. N. Exon Smith // Store the data in Record, byte-swapping as necessary. 16824b4b653SDuncan P. N. Exon Smith Record.Hash = swap(Data->FuncHash); 16924b4b653SDuncan P. N. Exon Smith Record.Name = RawName; 17024b4b653SDuncan P. N. Exon Smith if (ShouldSwapBytes) { 17124b4b653SDuncan P. N. Exon Smith Counts.clear(); 17224b4b653SDuncan P. N. Exon Smith Counts.reserve(RawCounts.size()); 17324b4b653SDuncan P. N. Exon Smith for (uint64_t Count : RawCounts) 17424b4b653SDuncan P. N. Exon Smith Counts.push_back(swap(Count)); 17524b4b653SDuncan P. N. Exon Smith Record.Counts = Counts; 17624b4b653SDuncan P. N. Exon Smith } else 17724b4b653SDuncan P. N. Exon Smith Record.Counts = RawCounts; 17824b4b653SDuncan P. N. Exon Smith 17924b4b653SDuncan P. N. Exon Smith // Iterate. 18024b4b653SDuncan P. N. Exon Smith ++Data; 18124b4b653SDuncan P. N. Exon Smith return success(); 18224b4b653SDuncan P. N. Exon Smith } 183