forked from OSchip/llvm-project
[CSSPGO] llvm-profdata support for CS profile.
Context-sensitive AutoFDO profile has a different name scheme where full calling contexts are encoded as function names. When processing CS proifle, llvm-profdata should use full contexts instead of leaf function names. Reviewed By: wmi, wenlei, wlei Differential Revision: https://reviews.llvm.org/D97998
This commit is contained in:
parent
c41ae246ac
commit
e68fafa49f
|
@ -11,3 +11,12 @@
|
||||||
; CHECK-NEXT: 7711 (2.17%) 610 610 _Z3fooi
|
; CHECK-NEXT: 7711 (2.17%) 610 610 _Z3fooi
|
||||||
; CHECK-NEXT: 6948 (1.95%) 3507 470 Func5
|
; CHECK-NEXT: 6948 (1.95%) 3507 470 Func5
|
||||||
; CHECK-NEXT: 1523 (0.43%) 563 169 Func1
|
; CHECK-NEXT: 1523 (0.43%) 563 169 Func1
|
||||||
|
|
||||||
|
|
||||||
|
; RUN: llvm-profdata show --sample --hot-func-list %S/Inputs/cs-sample.proftext | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=CS
|
||||||
|
|
||||||
|
; CS:2 out of 8 functions with profile (25.00%) are considered hot functions (max sample >= 23324).
|
||||||
|
; CS-NEXT:1968152 out of 1968919 profile counts (99.96%) are from hot functions.
|
||||||
|
; CS-NEXT: Total sample (%) Max sample Entry sample Function name
|
||||||
|
; CS-NEXT: 1467299 (74.52%) 287884 11 main:3 @ _Z5funcAi:1 @ _Z8funcLeafi
|
||||||
|
; CS-NEXT: 500853 (25.44%) 74946 20 main:3.1 @ _Z5funcBi:1 @ _Z8funcLeafi
|
||||||
|
|
|
@ -116,3 +116,25 @@
|
||||||
|
|
||||||
; RUN: llvm-profdata overlap --sample %S/Inputs/sample-overlap-0.proftext %S/Inputs/sample-overlap-5.proftext | FileCheck %s --check-prefix=OVERLAP5 --match-full-lines --strict-whitespace
|
; RUN: llvm-profdata overlap --sample %S/Inputs/sample-overlap-0.proftext %S/Inputs/sample-overlap-5.proftext | FileCheck %s --check-prefix=OVERLAP5 --match-full-lines --strict-whitespace
|
||||||
; OVERLAP5:Sum of sample counts for profile {{.*}}/Inputs/sample-overlap-5.proftext is 0.
|
; OVERLAP5:Sum of sample counts for profile {{.*}}/Inputs/sample-overlap-5.proftext is 0.
|
||||||
|
|
||||||
|
|
||||||
|
; RUN: llvm-profdata overlap --sample %S/Inputs/cs-sample.proftext %S/Inputs/cs-sample.proftext | FileCheck %s --check-prefix=CS --match-full-lines --strict-whitespace
|
||||||
|
; CS:Program level:
|
||||||
|
; CS: Whole program profile similarity: 100.000%
|
||||||
|
; CS: Whole program sample overlap: 100.000%
|
||||||
|
; CS: percentage of samples unique in base profile: 0.000%
|
||||||
|
; CS: percentage of samples unique in test profile: 0.000%
|
||||||
|
; CS: total samples in base profile: 772562
|
||||||
|
; CS: total samples in test profile: 772562
|
||||||
|
; CS: Function overlap: 100.000%
|
||||||
|
; CS: overlap functions: 8
|
||||||
|
; CS: functions unique in base profile: 0
|
||||||
|
; CS: functions unique in test profile: 0
|
||||||
|
; CS: Hot-function overlap: 100.000%
|
||||||
|
; CS: overlap hot functions: 2
|
||||||
|
; CS: hot functions unique in base profile: 0
|
||||||
|
; CS: hot functions unique in test profile: 0
|
||||||
|
; CS: Hot-block overlap: 100.000%
|
||||||
|
; CS: overlap hot blocks: 6
|
||||||
|
; CS: hot blocks unique in base profile: 0
|
||||||
|
; CS: hot blocks unique in test profile: 0
|
||||||
|
|
|
@ -672,6 +672,7 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
|
||||||
LLVMContext Context;
|
LLVMContext Context;
|
||||||
sampleprof::ProfileSymbolList WriterList;
|
sampleprof::ProfileSymbolList WriterList;
|
||||||
Optional<bool> ProfileIsProbeBased;
|
Optional<bool> ProfileIsProbeBased;
|
||||||
|
Optional<bool> ProfileIsCS;
|
||||||
for (const auto &Input : Inputs) {
|
for (const auto &Input : Inputs) {
|
||||||
auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context);
|
auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context);
|
||||||
if (std::error_code EC = ReaderOrErr.getError()) {
|
if (std::error_code EC = ReaderOrErr.getError()) {
|
||||||
|
@ -692,11 +693,14 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
|
||||||
}
|
}
|
||||||
|
|
||||||
StringMap<FunctionSamples> &Profiles = Reader->getProfiles();
|
StringMap<FunctionSamples> &Profiles = Reader->getProfiles();
|
||||||
if (ProfileIsProbeBased &&
|
if (ProfileIsProbeBased.hasValue() &&
|
||||||
ProfileIsProbeBased != FunctionSamples::ProfileIsProbeBased)
|
ProfileIsProbeBased != FunctionSamples::ProfileIsProbeBased)
|
||||||
exitWithError(
|
exitWithError(
|
||||||
"cannot merge probe-based profile with non-probe-based profile");
|
"cannot merge probe-based profile with non-probe-based profile");
|
||||||
ProfileIsProbeBased = FunctionSamples::ProfileIsProbeBased;
|
ProfileIsProbeBased = FunctionSamples::ProfileIsProbeBased;
|
||||||
|
if (ProfileIsCS.hasValue() && ProfileIsCS != FunctionSamples::ProfileIsCS)
|
||||||
|
exitWithError("cannot merge CS profile with non-CS profile");
|
||||||
|
ProfileIsCS = FunctionSamples::ProfileIsCS;
|
||||||
for (StringMap<FunctionSamples>::iterator I = Profiles.begin(),
|
for (StringMap<FunctionSamples>::iterator I = Profiles.begin(),
|
||||||
E = Profiles.end();
|
E = Profiles.end();
|
||||||
I != E; ++I) {
|
I != E; ++I) {
|
||||||
|
@ -1557,14 +1561,15 @@ void SampleOverlapAggregator::computeSampleProfileOverlap(raw_fd_ostream &OS) {
|
||||||
StringMap<const FunctionSamples *> BaseFuncProf;
|
StringMap<const FunctionSamples *> BaseFuncProf;
|
||||||
const auto &BaseProfiles = BaseReader->getProfiles();
|
const auto &BaseProfiles = BaseReader->getProfiles();
|
||||||
for (const auto &BaseFunc : BaseProfiles) {
|
for (const auto &BaseFunc : BaseProfiles) {
|
||||||
BaseFuncProf.try_emplace(BaseFunc.second.getName(), &(BaseFunc.second));
|
BaseFuncProf.try_emplace(BaseFunc.second.getNameWithContext(),
|
||||||
|
&(BaseFunc.second));
|
||||||
}
|
}
|
||||||
ProfOverlap.UnionCount = BaseFuncProf.size();
|
ProfOverlap.UnionCount = BaseFuncProf.size();
|
||||||
|
|
||||||
const auto &TestProfiles = TestReader->getProfiles();
|
const auto &TestProfiles = TestReader->getProfiles();
|
||||||
for (const auto &TestFunc : TestProfiles) {
|
for (const auto &TestFunc : TestProfiles) {
|
||||||
SampleOverlapStats FuncOverlap;
|
SampleOverlapStats FuncOverlap;
|
||||||
FuncOverlap.TestName = TestFunc.second.getName();
|
FuncOverlap.TestName = TestFunc.second.getNameWithContext();
|
||||||
assert(TestStats.count(FuncOverlap.TestName) &&
|
assert(TestStats.count(FuncOverlap.TestName) &&
|
||||||
"TestStats should have records for all functions in test profile "
|
"TestStats should have records for all functions in test profile "
|
||||||
"except inlinees");
|
"except inlinees");
|
||||||
|
@ -1591,7 +1596,7 @@ void SampleOverlapAggregator::computeSampleProfileOverlap(raw_fd_ostream &OS) {
|
||||||
|
|
||||||
// Two functions match with each other. Compute function-level overlap and
|
// Two functions match with each other. Compute function-level overlap and
|
||||||
// aggregate them into profile-level overlap.
|
// aggregate them into profile-level overlap.
|
||||||
FuncOverlap.BaseName = Match->second->getName();
|
FuncOverlap.BaseName = Match->second->getNameWithContext();
|
||||||
assert(BaseStats.count(FuncOverlap.BaseName) &&
|
assert(BaseStats.count(FuncOverlap.BaseName) &&
|
||||||
"BaseStats should have records for all functions in base profile "
|
"BaseStats should have records for all functions in base profile "
|
||||||
"except inlinees");
|
"except inlinees");
|
||||||
|
@ -1640,10 +1645,11 @@ void SampleOverlapAggregator::computeSampleProfileOverlap(raw_fd_ostream &OS) {
|
||||||
|
|
||||||
// Traverse through functions in base profile but not in test profile.
|
// Traverse through functions in base profile but not in test profile.
|
||||||
for (const auto &F : BaseFuncProf) {
|
for (const auto &F : BaseFuncProf) {
|
||||||
assert(BaseStats.count(F.second->getName()) &&
|
assert(BaseStats.count(F.second->getNameWithContext()) &&
|
||||||
"BaseStats should have records for all functions in base profile "
|
"BaseStats should have records for all functions in base profile "
|
||||||
"except inlinees");
|
"except inlinees");
|
||||||
const FuncSampleStats &FuncStats = BaseStats[F.second->getName()];
|
const FuncSampleStats &FuncStats =
|
||||||
|
BaseStats[F.second->getNameWithContext()];
|
||||||
++ProfOverlap.BaseUniqueCount;
|
++ProfOverlap.BaseUniqueCount;
|
||||||
ProfOverlap.BaseUniqueSample += FuncStats.SampleSum;
|
ProfOverlap.BaseUniqueSample += FuncStats.SampleSum;
|
||||||
|
|
||||||
|
@ -1674,7 +1680,7 @@ void SampleOverlapAggregator::initializeSampleProfileOverlap() {
|
||||||
FuncSampleStats FuncStats;
|
FuncSampleStats FuncStats;
|
||||||
getFuncSampleStats(I.second, FuncStats, BaseHotThreshold);
|
getFuncSampleStats(I.second, FuncStats, BaseHotThreshold);
|
||||||
ProfOverlap.BaseSample += FuncStats.SampleSum;
|
ProfOverlap.BaseSample += FuncStats.SampleSum;
|
||||||
BaseStats.try_emplace(I.second.getName(), FuncStats);
|
BaseStats.try_emplace(I.second.getNameWithContext(), FuncStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &TestProf = TestReader->getProfiles();
|
const auto &TestProf = TestReader->getProfiles();
|
||||||
|
@ -1683,7 +1689,7 @@ void SampleOverlapAggregator::initializeSampleProfileOverlap() {
|
||||||
FuncSampleStats FuncStats;
|
FuncSampleStats FuncStats;
|
||||||
getFuncSampleStats(I.second, FuncStats, TestHotThreshold);
|
getFuncSampleStats(I.second, FuncStats, TestHotThreshold);
|
||||||
ProfOverlap.TestSample += FuncStats.SampleSum;
|
ProfOverlap.TestSample += FuncStats.SampleSum;
|
||||||
TestStats.try_emplace(I.second.getName(), FuncStats);
|
TestStats.try_emplace(I.second.getNameWithContext(), FuncStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfOverlap.BaseName = StringRef(BaseFilename);
|
ProfOverlap.BaseName = StringRef(BaseFilename);
|
||||||
|
@ -1842,6 +1848,8 @@ std::error_code SampleOverlapAggregator::loadProfiles() {
|
||||||
if (BaseReader->profileIsProbeBased() != TestReader->profileIsProbeBased())
|
if (BaseReader->profileIsProbeBased() != TestReader->profileIsProbeBased())
|
||||||
exitWithError(
|
exitWithError(
|
||||||
"cannot compare probe-based profile with non-probe-based profile");
|
"cannot compare probe-based profile with non-probe-based profile");
|
||||||
|
if (BaseReader->profileIsCS() != TestReader->profileIsCS())
|
||||||
|
exitWithError("cannot compare CS profile with non-CS profile");
|
||||||
|
|
||||||
// Load BaseHotThreshold and TestHotThreshold as 99-percentile threshold in
|
// Load BaseHotThreshold and TestHotThreshold as 99-percentile threshold in
|
||||||
// profile summary.
|
// profile summary.
|
||||||
|
@ -1897,21 +1905,24 @@ static int overlap_main(int argc, const char *argv[]) {
|
||||||
cl::opt<std::string> Output("output", cl::value_desc("output"), cl::init("-"),
|
cl::opt<std::string> Output("output", cl::value_desc("output"), cl::init("-"),
|
||||||
cl::desc("Output file"));
|
cl::desc("Output file"));
|
||||||
cl::alias OutputA("o", cl::desc("Alias for --output"), cl::aliasopt(Output));
|
cl::alias OutputA("o", cl::desc("Alias for --output"), cl::aliasopt(Output));
|
||||||
cl::opt<bool> IsCS("cs", cl::init(false),
|
cl::opt<bool> IsCS(
|
||||||
cl::desc("For context sensitive counts"));
|
"cs", cl::init(false),
|
||||||
|
cl::desc("For context sensitive PGO counts. Does not work with CSSPGO."));
|
||||||
cl::opt<unsigned long long> ValueCutoff(
|
cl::opt<unsigned long long> ValueCutoff(
|
||||||
"value-cutoff", cl::init(-1),
|
"value-cutoff", cl::init(-1),
|
||||||
cl::desc(
|
cl::desc(
|
||||||
"Function level overlap information for every function in test "
|
"Function level overlap information for every function (with calling "
|
||||||
|
"context for csspgo) in test "
|
||||||
"profile with max count value greater then the parameter value"));
|
"profile with max count value greater then the parameter value"));
|
||||||
cl::opt<std::string> FuncNameFilter(
|
cl::opt<std::string> FuncNameFilter(
|
||||||
"function",
|
"function",
|
||||||
cl::desc("Function level overlap information for matching functions"));
|
cl::desc("Function level overlap information for matching functions. For "
|
||||||
|
"CSSPGO this takes a a function name with calling context"));
|
||||||
cl::opt<unsigned long long> SimilarityCutoff(
|
cl::opt<unsigned long long> SimilarityCutoff(
|
||||||
"similarity-cutoff", cl::init(0),
|
"similarity-cutoff", cl::init(0),
|
||||||
cl::desc(
|
cl::desc("For sample profiles, list function names (with calling context "
|
||||||
"For sample profiles, list function names for overlapped functions "
|
"for csspgo) for overlapped functions "
|
||||||
"with similarities below the cutoff (percentage times 10000)."));
|
"with similarities below the cutoff (percentage times 10000)."));
|
||||||
cl::opt<ProfileKinds> ProfileKind(
|
cl::opt<ProfileKinds> ProfileKind(
|
||||||
cl::desc("Profile kind:"), cl::init(instr),
|
cl::desc("Profile kind:"), cl::init(instr),
|
||||||
cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
|
cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
|
||||||
|
@ -2316,9 +2327,9 @@ showHotFunctionList(const StringMap<sampleprof::FunctionSamples> &Profiles,
|
||||||
(ProfileTotalSample > 0)
|
(ProfileTotalSample > 0)
|
||||||
? (Func.getTotalSamples() * 100.0) / ProfileTotalSample
|
? (Func.getTotalSamples() * 100.0) / ProfileTotalSample
|
||||||
: 0;
|
: 0;
|
||||||
PrintValues.emplace_back(
|
PrintValues.emplace_back(HotFuncInfo(
|
||||||
HotFuncInfo(Func.getName(), Func.getTotalSamples(), TotalSamplePercent,
|
Func.getNameWithContext(), Func.getTotalSamples(), TotalSamplePercent,
|
||||||
FuncPair.second.second, Func.getEntrySamples()));
|
FuncPair.second.second, Func.getEntrySamples()));
|
||||||
}
|
}
|
||||||
dumpHotFunctionList(ColumnTitle, ColumnOffset, PrintValues, HotFuncCount,
|
dumpHotFunctionList(ColumnTitle, ColumnOffset, PrintValues, HotFuncCount,
|
||||||
Profiles.size(), HotFuncSample, ProfileTotalSample,
|
Profiles.size(), HotFuncSample, ProfileTotalSample,
|
||||||
|
|
Loading…
Reference in New Issue