forked from OSchip/llvm-project
[PGO] Value profiling text format reader/writer support
This patch adds the missing functionality in parsable text format support for value profiling. Differential Revision: http://reviews.llvm.org/D15212 llvm-svn: 255523
This commit is contained in:
parent
bbfc7219ef
commit
e3bf4fd394
|
@ -106,8 +106,13 @@ private:
|
|||
/// Iterator over the profile data.
|
||||
line_iterator Line;
|
||||
|
||||
// String table for holding a unique copy of all the strings in the profile.
|
||||
InstrProfStringTable StringTable;
|
||||
|
||||
TextInstrProfReader(const TextInstrProfReader &) = delete;
|
||||
TextInstrProfReader &operator=(const TextInstrProfReader &) = delete;
|
||||
std::error_code readValueProfileData(InstrProfRecord &Record);
|
||||
|
||||
public:
|
||||
TextInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer_)
|
||||
: DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#') {}
|
||||
|
|
|
@ -109,6 +109,68 @@ bool TextInstrProfReader::hasFormat(const MemoryBuffer &Buffer) {
|
|||
[](char c) { return ::isprint(c) || ::isspace(c); });
|
||||
}
|
||||
|
||||
std::error_code
|
||||
TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) {
|
||||
|
||||
#define CHECK_LINE_END(Line) \
|
||||
if (Line.is_at_end()) \
|
||||
return error(instrprof_error::truncated);
|
||||
#define READ_NUM(Str, Dst) \
|
||||
if ((Str).getAsInteger(10, (Dst))) \
|
||||
return error(instrprof_error::malformed);
|
||||
#define VP_READ_ADVANCE(Val) \
|
||||
CHECK_LINE_END(Line); \
|
||||
uint32_t Val; \
|
||||
READ_NUM((*Line), (Val)); \
|
||||
Line++;
|
||||
|
||||
if (Line.is_at_end())
|
||||
return success();
|
||||
uint32_t NumValueKinds;
|
||||
if (Line->getAsInteger(10, NumValueKinds)) {
|
||||
// No value profile data
|
||||
return success();
|
||||
}
|
||||
if (NumValueKinds == 0 || NumValueKinds > IPVK_Last + 1)
|
||||
return error(instrprof_error::malformed);
|
||||
Line++;
|
||||
|
||||
for (uint32_t VK = 0; VK < NumValueKinds; VK++) {
|
||||
VP_READ_ADVANCE(ValueKind);
|
||||
if (ValueKind > IPVK_Last)
|
||||
return error(instrprof_error::malformed);
|
||||
VP_READ_ADVANCE(NumValueSites);
|
||||
if (!NumValueSites)
|
||||
continue;
|
||||
|
||||
Record.reserveSites(VK, NumValueSites);
|
||||
for (uint32_t S = 0; S < NumValueSites; S++) {
|
||||
VP_READ_ADVANCE(NumValueData);
|
||||
|
||||
std::vector<InstrProfValueData> CurrentValues;
|
||||
for (uint32_t V = 0; V < NumValueData; V++) {
|
||||
CHECK_LINE_END(Line);
|
||||
std::pair<StringRef, StringRef> VD = Line->split(':');
|
||||
uint64_t TakenCount, Value;
|
||||
READ_NUM(VD.second, TakenCount);
|
||||
if (VK == IPVK_IndirectCallTarget)
|
||||
Value = (uint64_t)StringTable.insertString(VD.first);
|
||||
else {
|
||||
READ_NUM(VD.first, Value);
|
||||
}
|
||||
CurrentValues.push_back({Value, TakenCount});
|
||||
Line++;
|
||||
}
|
||||
Record.addValueData(VK, S, CurrentValues.data(), NumValueData, nullptr);
|
||||
}
|
||||
}
|
||||
return success();
|
||||
|
||||
#undef CHECK_LINE_END
|
||||
#undef READ_NUM
|
||||
#undef VP_READ_ADVANCE
|
||||
}
|
||||
|
||||
std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
|
||||
// Skip empty lines and comments.
|
||||
while (!Line.is_at_end() && (Line->empty() || Line->startswith("#")))
|
||||
|
@ -147,6 +209,10 @@ std::error_code TextInstrProfReader::readNextRecord(InstrProfRecord &Record) {
|
|||
Record.Counts.push_back(Count);
|
||||
}
|
||||
|
||||
// Check if value profile data exists and read it if so.
|
||||
if (std::error_code EC = readValueProfileData(Record))
|
||||
return EC;
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
|
|
|
@ -172,15 +172,47 @@ void InstrProfWriter::write(raw_fd_ostream &OS) {
|
|||
endian::Writer<little>(OS).write<uint64_t>(TableStart.second);
|
||||
}
|
||||
|
||||
static const char *ValueProfKindStr[] = {
|
||||
#define VALUE_PROF_KIND(Enumerator, Value) #Enumerator,
|
||||
#include "llvm/ProfileData/InstrProfData.inc"
|
||||
};
|
||||
|
||||
void InstrProfWriter::writeRecordInText(const InstrProfRecord &Func,
|
||||
raw_fd_ostream &OS) {
|
||||
OS << Func.Name << "\n";
|
||||
OS << "# Func Hash:\n" << Func.Hash << "\n";
|
||||
OS << "# Num Counters:\n" <<Func.Counts.size() << "\n";
|
||||
OS << "# Num Counters:\n" << Func.Counts.size() << "\n";
|
||||
OS << "# Counter Values:\n";
|
||||
for (uint64_t Count : Func.Counts)
|
||||
OS << Count << "\n";
|
||||
|
||||
uint32_t NumValueKinds = Func.getNumValueKinds();
|
||||
if (!NumValueKinds) {
|
||||
OS << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
OS << "# Num Value Kinds:\n" << Func.getNumValueKinds() << "\n";
|
||||
for (uint32_t VK = 0; VK < IPVK_Last + 1; VK++) {
|
||||
uint32_t NS = Func.getNumValueSites(VK);
|
||||
if (!NS)
|
||||
continue;
|
||||
OS << "# ValueKind = " << ValueProfKindStr[VK] << ":\n" << VK << "\n";
|
||||
OS << "# NumValueSites:\n" << NS << "\n";
|
||||
for (uint32_t S = 0; S < NS; S++) {
|
||||
uint32_t ND = Func.getNumValueDataForSite(VK, S);
|
||||
OS << ND << "\n";
|
||||
std::unique_ptr<InstrProfValueData[]> VD = Func.getValueForSite(VK, S);
|
||||
for (uint32_t I = 0; I < ND; I++) {
|
||||
if (VK == IPVK_IndirectCallTarget)
|
||||
OS << reinterpret_cast<const char *>(VD[I].Value) << ":"
|
||||
<< VD[I].Count << "\n";
|
||||
else
|
||||
OS << VD[I].Value << ":" << VD[I].Count << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
foo
|
||||
# Func Hash:
|
||||
10
|
||||
# Num Counters:
|
||||
2
|
||||
# Counter Values:
|
||||
999000
|
||||
359800
|
||||
|
||||
foo2
|
||||
# Func Hash:
|
||||
10
|
||||
# Num Counters:
|
||||
2
|
||||
# Counter Values:
|
||||
1001000
|
||||
360200
|
||||
|
||||
main
|
||||
# Func Hash:
|
||||
16650
|
||||
# Num Counters:
|
||||
4
|
||||
# Counter Values:
|
||||
2
|
||||
2000
|
||||
2000000
|
||||
999000
|
||||
# NumValueKinds
|
||||
1
|
||||
# Value Kind IPVK_IndirectCallTarget
|
||||
0
|
||||
# NumSites
|
||||
3
|
||||
# Values for each site
|
||||
0
|
||||
2
|
||||
# !!!! Malformed Value/Count pair
|
||||
foo+100
|
||||
foo2:1000
|
||||
1
|
||||
foo2:20000
|
|
@ -0,0 +1,32 @@
|
|||
foo
|
||||
# Func Hash:
|
||||
10
|
||||
# Num Counters:
|
||||
2
|
||||
# Counter Values:
|
||||
999000
|
||||
359800
|
||||
|
||||
main
|
||||
# Func Hash:
|
||||
16650
|
||||
# Num Counters:
|
||||
4
|
||||
# Counter Values:
|
||||
2
|
||||
2000
|
||||
2000000
|
||||
999000
|
||||
# NumValueKinds
|
||||
1
|
||||
# Value Kind IPVK_IndirectCallTarget
|
||||
0
|
||||
# NumSites
|
||||
3
|
||||
# Values for each site
|
||||
0
|
||||
# !! Malformed value site, missing one value
|
||||
2
|
||||
foo:100
|
||||
1
|
||||
foo2:20000
|
|
@ -0,0 +1,36 @@
|
|||
foo
|
||||
# Func Hash:
|
||||
10
|
||||
# Num Counters:
|
||||
2
|
||||
# Counter Values:
|
||||
999000
|
||||
359800
|
||||
|
||||
foo2
|
||||
# Func Hash:
|
||||
10
|
||||
# Num Counters:
|
||||
2
|
||||
# Counter Values:
|
||||
1001000
|
||||
360200
|
||||
|
||||
main
|
||||
# Func Hash:
|
||||
16650
|
||||
# Num Counters:
|
||||
4
|
||||
# Counter Values:
|
||||
2
|
||||
2000
|
||||
2000000
|
||||
999000
|
||||
# NumValueKinds
|
||||
1
|
||||
# Value Kind IPVK_IndirectCallTarget
|
||||
0
|
||||
# NumSites
|
||||
3
|
||||
# Values for each site
|
||||
0
|
|
@ -18,3 +18,12 @@ NO-COUNTS: error: {{.*}}no-counts.proftext: Malformed instrumentation profile da
|
|||
RUN: not llvm-profdata show %p/Inputs/text-format-errors.text.bin 2>&1 | FileCheck %s --check-prefix=BINARY
|
||||
BINARY: error: {{.+}}: Unrecognized instrumentation profile encoding format
|
||||
BINARY: Perhaps you forgot to use the -sample option?
|
||||
|
||||
5- Detect malformed value profile data
|
||||
RUN: not llvm-profdata show %p/Inputs/vp-malform.proftext 2>&1 | FileCheck %s --check-prefix=VP
|
||||
RUN: not llvm-profdata show %p/Inputs/vp-malform2.proftext 2>&1 | FileCheck %s --check-prefix=VP
|
||||
VP: Malformed instrumentation profile data
|
||||
|
||||
6- Detect truncated value profile data
|
||||
RUN: not llvm-profdata show %p/Inputs/vp-truncate.proftext 2>&1 | FileCheck %s --check-prefix=VPTRUNC
|
||||
VPTRUNC: Truncated profile data
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
# RUN: llvm-profdata show -ic-targets -all-functions %s | FileCheck %s --check-prefix=IC
|
||||
# RUN: llvm-profdata show -ic-targets -counts -text -all-functions %s | FileCheck %s --check-prefix=ICTEXT
|
||||
# RUN: llvm-profdata merge -o %t.profdata %s
|
||||
# RUN: llvm-profdata show -ic-targets -all-functions %t.profdata | FileCheck %s --check-prefix=IC
|
||||
|
||||
foo
|
||||
# Func Hash:
|
||||
10
|
||||
# Num Counters:
|
||||
2
|
||||
# Counter Values:
|
||||
999000
|
||||
359800
|
||||
|
||||
foo2
|
||||
# Func Hash:
|
||||
10
|
||||
# Num Counters:
|
||||
2
|
||||
# Counter Values:
|
||||
1001000
|
||||
360200
|
||||
|
||||
main
|
||||
# Func Hash:
|
||||
16650
|
||||
# Num Counters:
|
||||
4
|
||||
# Counter Values:
|
||||
2
|
||||
2000
|
||||
2000000
|
||||
999000
|
||||
# NumValueKinds
|
||||
1
|
||||
# Value Kind IPVK_IndirectCallTarget
|
||||
0
|
||||
# NumSites
|
||||
3
|
||||
# Values for each site
|
||||
0
|
||||
2
|
||||
foo:100
|
||||
foo2:1000
|
||||
1
|
||||
foo2:20000
|
||||
|
||||
#IC: Indirect Call Site Count: 3
|
||||
#IC-NEXT: Indirect Target Results:
|
||||
#IC-NEXT: [ 1, foo, 100 ]
|
||||
#IC-NEXT: [ 1, foo2, 1000 ]
|
||||
#IC-NEXT: [ 2, foo2, 20000 ]
|
||||
|
||||
#ICTEXT: foo:100
|
||||
#ICTEXT-NEXT: foo2:1000
|
||||
#ICTEXT-NEXT: 1
|
||||
#ICTEXT-NEXT: foo2:20000
|
||||
# RUN: llvm-profdata show -ic-targets -all-functions %s | FileCheck %s --check-prefix=IC
|
||||
# RUN: llvm-profdata show -ic-targets -counts -text -all-functions %s | FileCheck %s --check-prefix=ICTEXT
|
||||
# RUN: llvm-profdata merge -o %t.profdata %s
|
||||
# RUN: llvm-profdata show -ic-targets -all-functions %t.profdata | FileCheck %s --check-prefix=IC
|
Loading…
Reference in New Issue