Please use GitHub pull requests for new patches. Avoid migrating existing patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
llvm/lib/ProfileData/SampleProfWriter.cpp
Show All 34 Lines | |||||
#include <set> | #include <set> | ||||
#include <system_error> | #include <system_error> | ||||
#include <utility> | #include <utility> | ||||
#include <vector> | #include <vector> | ||||
using namespace llvm; | using namespace llvm; | ||||
using namespace sampleprof; | using namespace sampleprof; | ||||
namespace llvm { | |||||
namespace support { | |||||
namespace endian { | |||||
namespace { | |||||
// Adapter class to llvm::support::endian::Writer for pwrite(). | |||||
struct SeekableWriter { | |||||
raw_pwrite_stream &OS; | |||||
endianness Endian; | |||||
SeekableWriter(raw_pwrite_stream &OS, endianness Endian) | |||||
: OS(OS), Endian(Endian) {} | |||||
template <typename ValueType> | |||||
snehasish: I think this should be ValueType based on the guidance here:
https://llvm. | |||||
void pwrite(ValueType Val, size_t Offset) { | |||||
std::string StringBuf; | |||||
raw_string_ostream SStream(StringBuf); | |||||
Writer(SStream, Endian).write(Val); | |||||
OS.pwrite(StringBuf.data(), StringBuf.size(), Offset); | |||||
} | |||||
}; | |||||
} // namespace | |||||
} // namespace endian | |||||
} // namespace support | |||||
} // namespace llvm | |||||
std::error_code | std::error_code | ||||
SampleProfileWriter::writeFuncProfiles(const SampleProfileMap &ProfileMap) { | SampleProfileWriter::writeFuncProfiles(const SampleProfileMap &ProfileMap) { | ||||
std::vector<NameFunctionSamples> V; | std::vector<NameFunctionSamples> V; | ||||
sortFuncProfiles(ProfileMap, V); | sortFuncProfiles(ProfileMap, V); | ||||
for (const auto &I : V) { | for (const auto &I : V) { | ||||
if (std::error_code EC = writeSample(*I.second)) | if (std::error_code EC = writeSample(*I.second)) | ||||
return EC; | return EC; | ||||
} | } | ||||
Show All 37 Lines | std::error_code SampleProfileWriterExtBinaryBase::compressAndOutput() { | ||||
SmallVector<uint8_t, 128> CompressedStrings; | SmallVector<uint8_t, 128> CompressedStrings; | ||||
compression::zlib::compress(arrayRefFromStringRef(UncompressedStrings), | compression::zlib::compress(arrayRefFromStringRef(UncompressedStrings), | ||||
CompressedStrings, | CompressedStrings, | ||||
compression::zlib::BestSizeCompression); | compression::zlib::BestSizeCompression); | ||||
encodeULEB128(UncompressedStrings.size(), OS); | encodeULEB128(UncompressedStrings.size(), OS); | ||||
encodeULEB128(CompressedStrings.size(), OS); | encodeULEB128(CompressedStrings.size(), OS); | ||||
OS << toStringRef(CompressedStrings); | OS << toStringRef(CompressedStrings); | ||||
UncompressedStrings.clear(); | UncompressedStrings.clear(); | ||||
return sampleprof_error::success; | return sampleprof_error::success; | ||||
Not Done ReplyInline ActionsFYI, OriginalFunctionCount was unused but fixed in rG9f4a9d3f4450 chapuni: FYI, OriginalFunctionCount was unused but fixed in rG9f4a9d3f4450 | |||||
} | } | ||||
Not Done ReplyInline ActionsIterationCount is used only here. chapuni: IterationCount is used only here. | |||||
/// Add a new section into section header table given the section type | /// Add a new section into section header table given the section type | ||||
/// \p Type, its position \p LayoutIdx in SectionHdrLayout and the | /// \p Type, its position \p LayoutIdx in SectionHdrLayout and the | ||||
/// location \p SectionStart where the section should be written to. | /// location \p SectionStart where the section should be written to. | ||||
std::error_code SampleProfileWriterExtBinaryBase::addNewSection( | std::error_code SampleProfileWriterExtBinaryBase::addNewSection( | ||||
SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) { | SecType Type, uint32_t LayoutIdx, uint64_t SectionStart) { | ||||
assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range"); | assert(LayoutIdx < SectionHdrLayout.size() && "LayoutIdx out of range"); | ||||
const auto &Entry = SectionHdrLayout[LayoutIdx]; | const auto &Entry = SectionHdrLayout[LayoutIdx]; | ||||
assert(Entry.Type == Type && "Unexpected section type"); | assert(Entry.Type == Type && "Unexpected section type"); | ||||
▲ Show 20 Lines • Show All 422 Lines • ▼ Show 20 Lines | |||||
SampleProfileWriterBinary::writeContextIdx(const SampleContext &Context) { | SampleProfileWriterBinary::writeContextIdx(const SampleContext &Context) { | ||||
assert(!Context.hasContext() && "cs profile is not supported"); | assert(!Context.hasContext() && "cs profile is not supported"); | ||||
return writeNameIdx(Context.getName()); | return writeNameIdx(Context.getName()); | ||||
} | } | ||||
std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { | std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) { | ||||
auto &NTable = getNameTable(); | auto &NTable = getNameTable(); | ||||
const auto &Ret = NTable.find(FName); | const auto &Ret = NTable.find(FName); | ||||
if (Ret == NTable.end()) | if (Ret == NTable.end()) | ||||
Not Done ReplyInline Actionsunneeded change davidxl: unneeded change | |||||
return sampleprof_error::truncated_name_table; | return sampleprof_error::truncated_name_table; | ||||
encodeULEB128(Ret->second, *OutputStream); | encodeULEB128(Ret->second, *OutputStream); | ||||
return sampleprof_error::success; | return sampleprof_error::success; | ||||
} | } | ||||
void SampleProfileWriterBinary::addName(StringRef FName) { | void SampleProfileWriterBinary::addName(StringRef FName) { | ||||
auto &NTable = getNameTable(); | auto &NTable = getNameTable(); | ||||
NTable.insert(std::make_pair(FName, 0)); | NTable.insert(std::make_pair(FName, 0)); | ||||
Not Done ReplyInline Actionsunneeded change. davidxl: unneeded change. | |||||
} | } | ||||
void SampleProfileWriterBinary::addContext(const SampleContext &Context) { | void SampleProfileWriterBinary::addContext(const SampleContext &Context) { | ||||
addName(Context.getName()); | addName(Context.getName()); | ||||
} | } | ||||
void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { | void SampleProfileWriterBinary::addNames(const FunctionSamples &S) { | ||||
// Add all the names in indirect call targets. | // Add all the names in indirect call targets. | ||||
Show All 9 Lines | for (const auto &FS : J.second) { | ||||
const FunctionSamples &CalleeSamples = FS.second; | const FunctionSamples &CalleeSamples = FS.second; | ||||
addName(CalleeSamples.getName()); | addName(CalleeSamples.getName()); | ||||
addNames(CalleeSamples); | addNames(CalleeSamples); | ||||
} | } | ||||
} | } | ||||
void SampleProfileWriterExtBinaryBase::addContext( | void SampleProfileWriterExtBinaryBase::addContext( | ||||
const SampleContext &Context) { | const SampleContext &Context) { | ||||
if (Context.hasContext()) { | if (Context.hasContext()) { | ||||
Not Done ReplyInline ActionsThe clear call changes the behavior. Why is it needed? davidxl: The clear call changes the behavior. Why is it needed? | |||||
Name table should only contains names exist in the current ProfileMap. The original implementation adds to the name table when writing a new profile, and the old names are never cleared, which is actually a bug. (However SampleProfileWriter is single use, an instance never calls write twice, so this bug was not showing up until this new feature) huangjd: Name table should only contains names exist in the current ProfileMap. The original… | |||||
for (auto &Callsite : Context.getContextFrames()) | for (auto &Callsite : Context.getContextFrames()) | ||||
SampleProfileWriterBinary::addName(Callsite.FuncName); | SampleProfileWriterBinary::addName(Callsite.FuncName); | ||||
CSNameTable.insert(std::make_pair(Context, 0)); | CSNameTable.insert(std::make_pair(Context, 0)); | ||||
} else { | } else { | ||||
SampleProfileWriterBinary::addName(Context.getName()); | SampleProfileWriterBinary::addName(Context.getName()); | ||||
} | } | ||||
} | } | ||||
Show All 20 Lines | std::error_code SampleProfileWriterBinary::writeNameTable() { | ||||
} | } | ||||
return sampleprof_error::success; | return sampleprof_error::success; | ||||
} | } | ||||
std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { | std::error_code SampleProfileWriterCompactBinary::writeFuncOffsetTable() { | ||||
auto &OS = *OutputStream; | auto &OS = *OutputStream; | ||||
// Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. | // Fill the slot remembered by TableOffset with the offset of FuncOffsetTable. | ||||
auto &OFS = static_cast<raw_fd_ostream &>(OS); | |||||
uint64_t FuncOffsetTableStart = OS.tell(); | uint64_t FuncOffsetTableStart = OS.tell(); | ||||
if (OFS.seek(TableOffset) == (uint64_t)-1) | support::endian::SeekableWriter Writer(static_cast<raw_pwrite_stream &>(OS), | ||||
return sampleprof_error::ostream_seek_unsupported; | support::little); | ||||
support::endian::Writer Writer(*OutputStream, support::little); | Writer.pwrite(FuncOffsetTableStart, TableOffset); | ||||
Writer.write(FuncOffsetTableStart); | |||||
if (OFS.seek(FuncOffsetTableStart) == (uint64_t)-1) | |||||
return sampleprof_error::ostream_seek_unsupported; | |||||
// Write out the table size. | // Write out the table size. | ||||
encodeULEB128(FuncOffsetTable.size(), OS); | encodeULEB128(FuncOffsetTable.size(), OS); | ||||
// Write out FuncOffsetTable. | // Write out FuncOffsetTable. | ||||
for (auto Entry : FuncOffsetTable) { | for (auto Entry : FuncOffsetTable) { | ||||
if (std::error_code EC = writeNameIdx(Entry.first)) | if (std::error_code EC = writeNameIdx(Entry.first)) | ||||
return EC; | return EC; | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | for (uint32_t i = 0; i < SectionHdrLayout.size(); i++) { | ||||
Writer.write(static_cast<uint64_t>(-1)); | Writer.write(static_cast<uint64_t>(-1)); | ||||
Writer.write(static_cast<uint64_t>(-1)); | Writer.write(static_cast<uint64_t>(-1)); | ||||
Writer.write(static_cast<uint64_t>(-1)); | Writer.write(static_cast<uint64_t>(-1)); | ||||
Writer.write(static_cast<uint64_t>(-1)); | Writer.write(static_cast<uint64_t>(-1)); | ||||
} | } | ||||
} | } | ||||
std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { | std::error_code SampleProfileWriterExtBinaryBase::writeSecHdrTable() { | ||||
auto &OFS = static_cast<raw_fd_ostream &>(*OutputStream); | |||||
uint64_t Saved = OutputStream->tell(); | |||||
// Set OutputStream to the location saved in SecHdrTableOffset. | |||||
if (OFS.seek(SecHdrTableOffset) == (uint64_t)-1) | |||||
return sampleprof_error::ostream_seek_unsupported; | |||||
support::endian::Writer Writer(*OutputStream, support::little); | |||||
assert(SecHdrTable.size() == SectionHdrLayout.size() && | assert(SecHdrTable.size() == SectionHdrLayout.size() && | ||||
"SecHdrTable entries doesn't match SectionHdrLayout"); | "SecHdrTable entries doesn't match SectionHdrLayout"); | ||||
SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1); | SmallVector<uint32_t, 16> IndexMap(SecHdrTable.size(), -1); | ||||
for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) { | for (uint32_t TableIdx = 0; TableIdx < SecHdrTable.size(); TableIdx++) { | ||||
IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx; | IndexMap[SecHdrTable[TableIdx].LayoutIndex] = TableIdx; | ||||
} | } | ||||
// Write the section header table in the order specified in | // Write the section header table in the order specified in | ||||
// SectionHdrLayout. SectionHdrLayout specifies the sections | // SectionHdrLayout. SectionHdrLayout specifies the sections | ||||
// order in which profile reader expect to read, so the section | // order in which profile reader expect to read, so the section | ||||
// header table should be written in the order in SectionHdrLayout. | // header table should be written in the order in SectionHdrLayout. | ||||
// Note that the section order in SecHdrTable may be different | // Note that the section order in SecHdrTable may be different | ||||
// from the order in SectionHdrLayout, for example, SecFuncOffsetTable | // from the order in SectionHdrLayout, for example, SecFuncOffsetTable | ||||
// needs to be computed after SecLBRProfile (the order in SecHdrTable), | // needs to be computed after SecLBRProfile (the order in SecHdrTable), | ||||
// but it needs to be read before SecLBRProfile (the order in | // but it needs to be read before SecLBRProfile (the order in | ||||
// SectionHdrLayout). So we use IndexMap above to switch the order. | // SectionHdrLayout). So we use IndexMap above to switch the order. | ||||
support::endian::SeekableWriter Writer( | |||||
static_cast<raw_pwrite_stream &>(*OutputStream), support::little); | |||||
for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size(); | for (uint32_t LayoutIdx = 0; LayoutIdx < SectionHdrLayout.size(); | ||||
LayoutIdx++) { | LayoutIdx++) { | ||||
assert(IndexMap[LayoutIdx] < SecHdrTable.size() && | assert(IndexMap[LayoutIdx] < SecHdrTable.size() && | ||||
"Incorrect LayoutIdx in SecHdrTable"); | "Incorrect LayoutIdx in SecHdrTable"); | ||||
auto Entry = SecHdrTable[IndexMap[LayoutIdx]]; | auto Entry = SecHdrTable[IndexMap[LayoutIdx]]; | ||||
Writer.write(static_cast<uint64_t>(Entry.Type)); | Writer.pwrite(static_cast<uint64_t>(Entry.Type), | ||||
Writer.write(static_cast<uint64_t>(Entry.Flags)); | SecHdrTableOffset + 4 * LayoutIdx * sizeof(uint64_t)); | ||||
Writer.write(static_cast<uint64_t>(Entry.Offset)); | Writer.pwrite(static_cast<uint64_t>(Entry.Flags), | ||||
Writer.write(static_cast<uint64_t>(Entry.Size)); | SecHdrTableOffset + (4 * LayoutIdx + 1) * sizeof(uint64_t)); | ||||
Writer.pwrite(static_cast<uint64_t>(Entry.Offset), | |||||
SecHdrTableOffset + (4 * LayoutIdx + 2) * sizeof(uint64_t)); | |||||
Writer.pwrite(static_cast<uint64_t>(Entry.Size), | |||||
SecHdrTableOffset + (4 * LayoutIdx + 3) * sizeof(uint64_t)); | |||||
} | } | ||||
// Reset OutputStream. | |||||
if (OFS.seek(Saved) == (uint64_t)-1) | |||||
return sampleprof_error::ostream_seek_unsupported; | |||||
return sampleprof_error::success; | return sampleprof_error::success; | ||||
} | } | ||||
std::error_code SampleProfileWriterExtBinaryBase::writeHeader( | std::error_code SampleProfileWriterExtBinaryBase::writeHeader( | ||||
const SampleProfileMap &ProfileMap) { | const SampleProfileMap &ProfileMap) { | ||||
auto &OS = *OutputStream; | auto &OS = *OutputStream; | ||||
FileStart = OS.tell(); | FileStart = OS.tell(); | ||||
writeMagicIdent(Format); | writeMagicIdent(Format); | ||||
▲ Show 20 Lines • Show All 160 Lines • Show Last 20 Lines |
I think this should be ValueType based on the guidance here:
https://llvm.org/docs/CodingStandards.html#name-types-functions-variables-and-enumerators-properly