diff --git a/llvm/test/tools/llvm-profdata/merge-filtering.test b/llvm/test/tools/llvm-profdata/merge-filtering.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-profdata/merge-filtering.test @@ -0,0 +1,95 @@ +# Tests for merge of profile files with filtering capabilities + +# no filtering +RUN: llvm-profdata merge --text %p/Inputs/basic.proftext | FileCheck %s + +CHECK: foo +CHECK-NEXT: # Func Hash: +CHECK-NEXT: 10 +CHECK-NEXT: # Num Counters: +CHECK-NEXT: 2 +CHECK-NEXT: # Counter Values: +CHECK-NEXT: 499500 +CHECK-NEXT: 179900 +CHECK: foo2 +CHECK-NEXT: # Func Hash: +CHECK-NEXT: 10 +CHECK-NEXT: # Num Counters: +CHECK-NEXT: 2 +CHECK-NEXT: # Counter Values: +CHECK-NEXT: 500500 +CHECK-NEXT: 180100 +CHECK: main +CHECK-NEXT: # Func Hash: +CHECK-NEXT: 16650 +CHECK-NEXT: # Num Counters: +CHECK-NEXT: 4 +CHECK-NEXT: # Counter Values: +CHECK-NEXT: 1 +CHECK-NEXT: 1000 +CHECK-NEXT: 1000000 +CHECK-NEXT: 499500 + +# excluding profile for one pattern matching one function +RUN: llvm-profdata merge --exclude-function "foo2" --text %p/Inputs/basic.proftext -o - | FileCheck %s --check-prefix=MERGE-EXCL-SINGLE-FUNC + +MERGE-EXCL-SINGLE-FUNC-LABEL: foo +MERGE-EXCL-SINGLE-FUNC-NEXT: # Func Hash: +MERGE-EXCL-SINGLE-FUNC-NEXT: 10 +MERGE-EXCL-SINGLE-FUNC-NEXT: # Num Counters: +MERGE-EXCL-SINGLE-FUNC-NEXT: 2 +MERGE-EXCL-SINGLE-FUNC-NEXT: # Counter Values: +MERGE-EXCL-SINGLE-FUNC-NEXT: 499500 +MERGE-EXCL-SINGLE-FUNC-NEXT: 179900 +MERGE-EXCL-SINGLE-FUNC-NOT: foo2 +MERGE-EXCL-SINGLE-FUNC-LABEL: main +MERGE-EXCL-SINGLE-FUNC-NEXT: # Func Hash: +MERGE-EXCL-SINGLE-FUNC-NEXT: 16650 +MERGE-EXCL-SINGLE-FUNC-NEXT: # Num Counters: +MERGE-EXCL-SINGLE-FUNC-NEXT: 4 +MERGE-EXCL-SINGLE-FUNC-NEXT: # Counter Values: +MERGE-EXCL-SINGLE-FUNC-NEXT: 1 +MERGE-EXCL-SINGLE-FUNC-NEXT: 1000 +MERGE-EXCL-SINGLE-FUNC-NEXT: 1000000 +MERGE-EXCL-SINGLE-FUNC-NEXT: 499500 + +# excluding profile for one pattern matching multiple functions +RUN: llvm-profdata merge --exclude-function "foo" --text %p/Inputs/basic.proftext -o - | FileCheck %s --check-prefix=MERGE-EXCL-SINGLE-PAT +MERGE-EXCL-SINGLE-PAT-NOT: foo +MERGE-EXCL-SINGLE-PAT-NOT: foo2 +MERGE-EXCL-SINGLE-PAT: main +MERGE-EXCL-SINGLE-PAT-NEXT: # Func Hash: +MERGE-EXCL-SINGLE-PAT-NEXT: 16650 +MERGE-EXCL-SINGLE-PAT-NEXT: # Num Counters: +MERGE-EXCL-SINGLE-PAT-NEXT: 4 +MERGE-EXCL-SINGLE-PAT-NEXT: # Counter Values: +MERGE-EXCL-SINGLE-PAT-NEXT: 1 +MERGE-EXCL-SINGLE-PAT-NEXT: 1000 +MERGE-EXCL-SINGLE-PAT-NEXT: 1000000 +MERGE-EXCL-SINGLE-PAT-NEXT: 499500 + +# excluding profile for multiple patterns matching multiple functions +RUN: llvm-profdata merge --exclude-function "foo2;main" --text %p/Inputs/basic.proftext -o - | FileCheck %s --check-prefix=MERGE-EXCL-MULT-PAT +MERGE-EXCL-MULT-PAT: foo +MERGE-EXCL-MULT-PAT-NEXT: # Func Hash: +MERGE-EXCL-MULT-PAT-NEXT: 10 +MERGE-EXCL-MULT-PAT-NEXT: # Num Counters: +MERGE-EXCL-MULT-PAT-NEXT: 2 +MERGE-EXCL-MULT-PAT-NEXT: # Counter Values: +MERGE-EXCL-MULT-PAT-NEXT: 499500 +MERGE-EXCL-MULT-PAT-NEXT: 179900 +MERGE-EXCL-MULT-PAT-NOT: foo2 +MERGE-EXCL-MULT-PAT-NOT: main + +# excluding profile for multiple patterns matching multiple functions +RUN: llvm-profdata merge --exclude-function "foo2;main;" --text %p/Inputs/basic.proftext -o - | FileCheck %s --check-prefix=DANGLING-DELIMITER +DANGLING-DELIMITER: foo +DANGLING-DELIMITER-NEXT: # Func Hash: +DANGLING-DELIMITER-NEXT: 10 +DANGLING-DELIMITER-NEXT: # Num Counters: +DANGLING-DELIMITER-NEXT: 2 +DANGLING-DELIMITER-NEXT: # Counter Values: +DANGLING-DELIMITER-NEXT: 499500 +DANGLING-DELIMITER-NEXT: 179900 +DANGLING-DELIMITER-NOT: foo2 +DANGLING-DELIMITER-NOT: main diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp --- a/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -251,7 +251,8 @@ /// Load an input into a writer context. static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper, const InstrProfCorrelator *Correlator, - const StringRef ProfiledBinary, WriterContext *WC) { + const StringRef ProfiledBinary, WriterContext *WC, + const StringRef ExcludeFuncList) { std::unique_lock CtxGuard{WC->Lock}; // Copy the filename, because llvm::ThreadPool copied the input "const @@ -327,6 +328,24 @@ I.Name = (*Remapper)(I.Name); const StringRef FuncName = I.Name; bool Reported = false; + + bool ToBeExcluded = false; + std::string ExcludeFuncPat; + if (!ExcludeFuncList.empty()) { + std::stringstream ExcludeFuncSS(ExcludeFuncList.str()); + while (ExcludeFuncSS.good()) { + getline(ExcludeFuncSS, ExcludeFuncPat, ';'); + if (!ExcludeFuncPat.empty() && FuncName.contains(ExcludeFuncPat)) { + ToBeExcluded = true; + break; + } + } + } + + if (ToBeExcluded) { + continue; + } + WC->Writer.addRecord(std::move(I), Input.Weight, [&](Error E) { if (Reported) { consumeError(std::move(E)); @@ -398,7 +417,8 @@ StringRef OutputFilename, ProfileFormat OutputFormat, bool OutputSparse, unsigned NumThreads, FailureMode FailMode, - const StringRef ProfiledBinary) { + const StringRef ProfiledBinary, + const std::string &ExcludeFuncList) { if (OutputFormat != PF_Binary && OutputFormat != PF_Compact_Binary && OutputFormat != PF_Ext_Binary && OutputFormat != PF_Text) exitWithError("unknown format is specified"); @@ -429,7 +449,7 @@ if (NumThreads == 1) { for (const auto &Input : Inputs) loadInput(Input, Remapper, Correlator.get(), ProfiledBinary, - Contexts[0].get()); + Contexts[0].get(), ExcludeFuncList); } else { ThreadPool Pool(hardware_concurrency(NumThreads)); @@ -437,7 +457,7 @@ unsigned Ctx = 0; for (const auto &Input : Inputs) { Pool.async(loadInput, Input, Remapper, Correlator.get(), ProfiledBinary, - Contexts[Ctx].get()); + Contexts[Ctx].get(), ExcludeFuncList); Ctx = (Ctx + 1) % NumThreads; } Pool.wait(); @@ -856,7 +876,7 @@ SmallSet WriterErrorCodes; auto WC = std::make_unique(OutputSparse, ErrorLock, WriterErrorCodes); - loadInput(Inputs[0], nullptr, nullptr, /*ProfiledBinary=*/"", WC.get()); + loadInput(Inputs[0], nullptr, nullptr, /*ProfiledBinary=*/"", WC.get(), ""); if (WC->Errors.size() > 0) exitWithError(std::move(WC->Errors[0].first), InstrFilename); @@ -1254,6 +1274,10 @@ "drop-profile-symbol-list", cl::init(false), cl::Hidden, cl::desc("Drop the profile symbol list when merging AutoFDO profiles " "(only meaningful for -sample)")); + cl::opt ExcludeFuncList( + "exclude-function", + cl::desc("Include profiles from only those functions where names don't " + "match all the regexes separated by a semi-colon")); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); @@ -1296,7 +1320,7 @@ if (ProfileKind == instr) mergeInstrProfile(WeightedInputs, DebugInfoFilename, Remapper.get(), OutputFilename, OutputFormat, OutputSparse, NumThreads, - FailureMode, ProfiledBinary); + FailureMode, ProfiledBinary, ExcludeFuncList); else mergeSampleProfile( WeightedInputs, Remapper.get(), OutputFilename, OutputFormat, @@ -1328,7 +1352,8 @@ OS << "Sum of edge counts for profile " << TestFilename << " is 0.\n"; exit(0); } - loadInput(WeightedInput, nullptr, nullptr, /*ProfiledBinary=*/"", &Context); + loadInput(WeightedInput, nullptr, nullptr, /*ProfiledBinary=*/"", &Context, + ""); overlapInput(BaseFilename, TestFilename, &Context, Overlap, FuncFilter, OS, IsCS); Overlap.dump(OS);