diff --git a/llvm/test/tools/llvm-profdata/sample-hot-func-list.test b/llvm/test/tools/llvm-profdata/sample-hot-func-list.test index 2ea81363d49caf..7f319e6dc0bb53 100644 --- a/llvm/test/tools/llvm-profdata/sample-hot-func-list.test +++ b/llvm/test/tools/llvm-profdata/sample-hot-func-list.test @@ -11,3 +11,12 @@ ; CHECK-NEXT: 7711 (2.17%) 610 610 _Z3fooi ; CHECK-NEXT: 6948 (1.95%) 3507 470 Func5 ; 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 diff --git a/llvm/test/tools/llvm-profdata/sample-overlap.test b/llvm/test/tools/llvm-profdata/sample-overlap.test index 02609d8f98b0d2..859b705e5f3bd3 100644 --- a/llvm/test/tools/llvm-profdata/sample-overlap.test +++ b/llvm/test/tools/llvm-profdata/sample-overlap.test @@ -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 ; 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 diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index 0066765106db62..558d3e6ffd7897 100644 --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -672,6 +672,7 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper, LLVMContext Context; sampleprof::ProfileSymbolList WriterList; Optional ProfileIsProbeBased; + Optional ProfileIsCS; for (const auto &Input : Inputs) { auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context); if (std::error_code EC = ReaderOrErr.getError()) { @@ -692,11 +693,14 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper, } StringMap &Profiles = Reader->getProfiles(); - if (ProfileIsProbeBased && + if (ProfileIsProbeBased.hasValue() && ProfileIsProbeBased != FunctionSamples::ProfileIsProbeBased) exitWithError( "cannot merge probe-based profile with non-probe-based profile"); ProfileIsProbeBased = FunctionSamples::ProfileIsProbeBased; + if (ProfileIsCS.hasValue() && ProfileIsCS != FunctionSamples::ProfileIsCS) + exitWithError("cannot merge CS profile with non-CS profile"); + ProfileIsCS = FunctionSamples::ProfileIsCS; for (StringMap::iterator I = Profiles.begin(), E = Profiles.end(); I != E; ++I) { @@ -1557,14 +1561,15 @@ void SampleOverlapAggregator::computeSampleProfileOverlap(raw_fd_ostream &OS) { StringMap BaseFuncProf; const auto &BaseProfiles = BaseReader->getProfiles(); 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(); const auto &TestProfiles = TestReader->getProfiles(); for (const auto &TestFunc : TestProfiles) { SampleOverlapStats FuncOverlap; - FuncOverlap.TestName = TestFunc.second.getName(); + FuncOverlap.TestName = TestFunc.second.getNameWithContext(); assert(TestStats.count(FuncOverlap.TestName) && "TestStats should have records for all functions in test profile " "except inlinees"); @@ -1591,7 +1596,7 @@ void SampleOverlapAggregator::computeSampleProfileOverlap(raw_fd_ostream &OS) { // Two functions match with each other. Compute function-level overlap and // aggregate them into profile-level overlap. - FuncOverlap.BaseName = Match->second->getName(); + FuncOverlap.BaseName = Match->second->getNameWithContext(); assert(BaseStats.count(FuncOverlap.BaseName) && "BaseStats should have records for all functions in base profile " "except inlinees"); @@ -1640,10 +1645,11 @@ void SampleOverlapAggregator::computeSampleProfileOverlap(raw_fd_ostream &OS) { // Traverse through functions in base profile but not in test profile. 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 " "except inlinees"); - const FuncSampleStats &FuncStats = BaseStats[F.second->getName()]; + const FuncSampleStats &FuncStats = + BaseStats[F.second->getNameWithContext()]; ++ProfOverlap.BaseUniqueCount; ProfOverlap.BaseUniqueSample += FuncStats.SampleSum; @@ -1674,7 +1680,7 @@ void SampleOverlapAggregator::initializeSampleProfileOverlap() { FuncSampleStats FuncStats; getFuncSampleStats(I.second, FuncStats, BaseHotThreshold); ProfOverlap.BaseSample += FuncStats.SampleSum; - BaseStats.try_emplace(I.second.getName(), FuncStats); + BaseStats.try_emplace(I.second.getNameWithContext(), FuncStats); } const auto &TestProf = TestReader->getProfiles(); @@ -1683,7 +1689,7 @@ void SampleOverlapAggregator::initializeSampleProfileOverlap() { FuncSampleStats FuncStats; getFuncSampleStats(I.second, FuncStats, TestHotThreshold); ProfOverlap.TestSample += FuncStats.SampleSum; - TestStats.try_emplace(I.second.getName(), FuncStats); + TestStats.try_emplace(I.second.getNameWithContext(), FuncStats); } ProfOverlap.BaseName = StringRef(BaseFilename); @@ -1842,6 +1848,8 @@ std::error_code SampleOverlapAggregator::loadProfiles() { if (BaseReader->profileIsProbeBased() != TestReader->profileIsProbeBased()) exitWithError( "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 // profile summary. @@ -1897,21 +1905,24 @@ static int overlap_main(int argc, const char *argv[]) { cl::opt Output("output", cl::value_desc("output"), cl::init("-"), cl::desc("Output file")); cl::alias OutputA("o", cl::desc("Alias for --output"), cl::aliasopt(Output)); - cl::opt IsCS("cs", cl::init(false), - cl::desc("For context sensitive counts")); + cl::opt IsCS( + "cs", cl::init(false), + cl::desc("For context sensitive PGO counts. Does not work with CSSPGO.")); cl::opt ValueCutoff( "value-cutoff", cl::init(-1), 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")); cl::opt FuncNameFilter( "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 SimilarityCutoff( "similarity-cutoff", cl::init(0), - cl::desc( - "For sample profiles, list function names for overlapped functions " - "with similarities below the cutoff (percentage times 10000).")); + cl::desc("For sample profiles, list function names (with calling context " + "for csspgo) for overlapped functions " + "with similarities below the cutoff (percentage times 10000).")); cl::opt ProfileKind( cl::desc("Profile kind:"), cl::init(instr), cl::values(clEnumVal(instr, "Instrumentation profile (default)"), @@ -2316,9 +2327,9 @@ showHotFunctionList(const StringMap &Profiles, (ProfileTotalSample > 0) ? (Func.getTotalSamples() * 100.0) / ProfileTotalSample : 0; - PrintValues.emplace_back( - HotFuncInfo(Func.getName(), Func.getTotalSamples(), TotalSamplePercent, - FuncPair.second.second, Func.getEntrySamples())); + PrintValues.emplace_back(HotFuncInfo( + Func.getNameWithContext(), Func.getTotalSamples(), TotalSamplePercent, + FuncPair.second.second, Func.getEntrySamples())); } dumpHotFunctionList(ColumnTitle, ColumnOffset, PrintValues, HotFuncCount, Profiles.size(), HotFuncSample, ProfileTotalSample,