forked from OSchip/llvm-project
[PGO] Commonize (more) index profile file and buffer writer.
The file and buffer writer code are mostly shared except for the stream back-patching. This is because raw_string_ostream does not support seek like interface. The result is that the data patching code needs to be pushed to the caller which is not quite readable (passing around offset, value etc). This also makes future enhancement (which needs more patching) more difficult (and can make impl messy). In this patch, two types of streams needed by the writer are now unified with same set of interfaces under ProfOStream class. The patch method is added so that common implementation becomes cleaner. It also enables future enhancement. Should be NFC. llvm-svn: 257921
This commit is contained in:
parent
257a35368f
commit
b606638526
|
@ -24,6 +24,7 @@
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
/// Writer for instrumentation based profile data.
|
/// Writer for instrumentation based profile data.
|
||||||
|
class ProfOStream;
|
||||||
class InstrProfWriter {
|
class InstrProfWriter {
|
||||||
public:
|
public:
|
||||||
typedef SmallDenseMap<uint64_t, InstrProfRecord, 1> ProfilingData;
|
typedef SmallDenseMap<uint64_t, InstrProfRecord, 1> ProfilingData;
|
||||||
|
@ -53,7 +54,7 @@ public:
|
||||||
void setValueProfDataEndianness(support::endianness Endianness);
|
void setValueProfDataEndianness(support::endianness Endianness);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::pair<uint64_t, uint64_t> writeImpl(raw_ostream &OS);
|
void writeImpl(ProfOStream &OS);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
|
@ -20,6 +20,58 @@
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
|
// A struct to define how the data stream should be patched. For Indexed
|
||||||
|
// profiling, only uint64_t data type is needed.
|
||||||
|
struct PatchItem {
|
||||||
|
uint64_t Pos; // Where to patch.
|
||||||
|
uint64_t *D; // Pointer to an array of source data.
|
||||||
|
int N; // Number of elements in \c D array.
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
// A wrapper class to abstract writer stream with support of bytes
|
||||||
|
// back patching.
|
||||||
|
struct ProfOStream {
|
||||||
|
|
||||||
|
ProfOStream(llvm::raw_fd_ostream &FD) : IsFDOStream(true), OS(FD), LE(FD) {}
|
||||||
|
ProfOStream(llvm::raw_string_ostream &STR)
|
||||||
|
: IsFDOStream(false), OS(STR), LE(STR) {}
|
||||||
|
|
||||||
|
uint64_t tell() { return OS.tell(); }
|
||||||
|
void write(uint64_t V) { LE.write<uint64_t>(V); }
|
||||||
|
// \c patch can only be called when all data is written and flushed.
|
||||||
|
// For raw_string_ostream, the patch is done on the target string
|
||||||
|
// directly and it won't be reflected in the stream's internal buffer.
|
||||||
|
void patch(PatchItem *P, int NItems) {
|
||||||
|
using namespace support;
|
||||||
|
if (IsFDOStream) {
|
||||||
|
llvm::raw_fd_ostream &FDOStream = static_cast<llvm::raw_fd_ostream &>(OS);
|
||||||
|
for (int K = 0; K < NItems; K++) {
|
||||||
|
FDOStream.seek(P[K].Pos);
|
||||||
|
for (int I = 0; I < P[K].N; I++)
|
||||||
|
write(P[K].D[I]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
llvm::raw_string_ostream &SOStream =
|
||||||
|
static_cast<llvm::raw_string_ostream &>(OS);
|
||||||
|
std::string &Data = SOStream.str(); // with flush
|
||||||
|
for (int K = 0; K < NItems; K++) {
|
||||||
|
for (int I = 0; I < P[K].N; I++) {
|
||||||
|
uint64_t Bytes = endian::byte_swap<uint64_t, little>(P[K].D[I]);
|
||||||
|
Data.replace(P[K].Pos + I * sizeof(uint64_t), sizeof(uint64_t),
|
||||||
|
(const char *)&Bytes, sizeof(uint64_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If \c OS is an instance of \c raw_fd_ostream, this field will be
|
||||||
|
// true. Otherwise, \c OS will be an raw_string_ostream.
|
||||||
|
bool IsFDOStream;
|
||||||
|
raw_ostream &OS;
|
||||||
|
support::endian::Writer<support::little> LE;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static support::endianness ValueProfDataEndianness = support::little;
|
static support::endianness ValueProfDataEndianness = support::little;
|
||||||
|
|
||||||
|
@ -127,16 +179,11 @@ std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I,
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<uint64_t, uint64_t> InstrProfWriter::writeImpl(raw_ostream &OS) {
|
void InstrProfWriter::writeImpl(ProfOStream &OS) {
|
||||||
OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator;
|
OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator;
|
||||||
|
|
||||||
// Populate the hash table generator.
|
// Populate the hash table generator.
|
||||||
for (const auto &I : FunctionData)
|
for (const auto &I : FunctionData)
|
||||||
Generator.insert(I.getKey(), &I.getValue());
|
Generator.insert(I.getKey(), &I.getValue());
|
||||||
|
|
||||||
using namespace llvm::support;
|
|
||||||
endian::Writer<little> LE(OS);
|
|
||||||
|
|
||||||
// Write the header.
|
// Write the header.
|
||||||
IndexedInstrProf::Header Header;
|
IndexedInstrProf::Header Header;
|
||||||
Header.Magic = IndexedInstrProf::Magic;
|
Header.Magic = IndexedInstrProf::Magic;
|
||||||
|
@ -150,27 +197,34 @@ std::pair<uint64_t, uint64_t> InstrProfWriter::writeImpl(raw_ostream &OS) {
|
||||||
// to remember the offset of that field to allow back patching
|
// to remember the offset of that field to allow back patching
|
||||||
// later.
|
// later.
|
||||||
for (int I = 0; I < N - 1; I++)
|
for (int I = 0; I < N - 1; I++)
|
||||||
LE.write<uint64_t>(reinterpret_cast<uint64_t *>(&Header)[I]);
|
OS.write(reinterpret_cast<uint64_t *>(&Header)[I]);
|
||||||
|
|
||||||
// Save a space to write the hash table start location.
|
// Save a space to write the hash table start location.
|
||||||
uint64_t HashTableStartLoc = OS.tell();
|
uint64_t HashTableStartLoc = OS.tell();
|
||||||
// Reserve the space for HashOffset field.
|
// Reserve the space for HashOffset field.
|
||||||
LE.write<uint64_t>(0);
|
OS.write(0);
|
||||||
// Write the hash table.
|
// Write the hash table.
|
||||||
uint64_t HashTableStart = Generator.Emit(OS);
|
uint64_t HashTableStart = Generator.Emit(OS.OS);
|
||||||
|
|
||||||
return std::make_pair(HashTableStartLoc, HashTableStart);
|
// Now do the final patch:
|
||||||
|
PatchItem PatchItems[1] = {{HashTableStartLoc, &HashTableStart, 1}};
|
||||||
|
OS.patch(PatchItems, sizeof(PatchItems) / sizeof(*PatchItems));
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstrProfWriter::write(raw_fd_ostream &OS) {
|
void InstrProfWriter::write(raw_fd_ostream &OS) {
|
||||||
// Write the hash table.
|
// Write the hash table.
|
||||||
auto TableStart = writeImpl(OS);
|
ProfOStream POS(OS);
|
||||||
|
writeImpl(POS);
|
||||||
|
}
|
||||||
|
|
||||||
// Go back and fill in the hash table start.
|
std::unique_ptr<MemoryBuffer> InstrProfWriter::writeBuffer() {
|
||||||
using namespace support;
|
std::string Data;
|
||||||
OS.seek(TableStart.first);
|
llvm::raw_string_ostream OS(Data);
|
||||||
// Now patch the HashOffset field previously reserved.
|
ProfOStream POS(OS);
|
||||||
endian::Writer<little>(OS).write<uint64_t>(TableStart.second);
|
// Write the hash table.
|
||||||
|
writeImpl(POS);
|
||||||
|
// Return this in an aligned memory buffer.
|
||||||
|
return MemoryBuffer::getMemBufferCopy(Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *ValueProfKindStr[] = {
|
static const char *ValueProfKindStr[] = {
|
||||||
|
@ -227,20 +281,3 @@ void InstrProfWriter::writeText(raw_fd_ostream &OS) {
|
||||||
for (const auto &Func : I.getValue())
|
for (const auto &Func : I.getValue())
|
||||||
writeRecordInText(Func.second, Symtab, OS);
|
writeRecordInText(Func.second, Symtab, OS);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<MemoryBuffer> InstrProfWriter::writeBuffer() {
|
|
||||||
std::string Data;
|
|
||||||
llvm::raw_string_ostream OS(Data);
|
|
||||||
// Write the hash table.
|
|
||||||
auto TableStart = writeImpl(OS);
|
|
||||||
OS.flush();
|
|
||||||
|
|
||||||
// Go back and fill in the hash table start.
|
|
||||||
using namespace support;
|
|
||||||
uint64_t Bytes = endian::byte_swap<uint64_t, little>(TableStart.second);
|
|
||||||
Data.replace(TableStart.first, sizeof(uint64_t), (const char *)&Bytes,
|
|
||||||
sizeof(uint64_t));
|
|
||||||
|
|
||||||
// Return this in an aligned memory buffer.
|
|
||||||
return MemoryBuffer::getMemBufferCopy(Data);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue