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,109 @@ +# 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 one regex pattern matching multiple functions +RUN: llvm-profdata merge --exclude-function "foo.*" --text %p/Inputs/basic.proftext -o - | FileCheck %s --check-prefix=MERGE-EXCL-REGEX-SINGLE-PAT +MERGE-EXCL-REGEX-SINGLE-PAT-NOT: foo +MERGE-EXCL-REGEX-SINGLE-PAT-NOT: foo2 +MERGE-EXCL-REGEX-SINGLE-PAT: main +MERGE-EXCL-REGEX-SINGLE-PAT-NEXT: # Func Hash: +MERGE-EXCL-REGEX-SINGLE-PAT-NEXT: 16650 +MERGE-EXCL-REGEX-SINGLE-PAT-NEXT: # Num Counters: +MERGE-EXCL-REGEX-SINGLE-PAT-NEXT: 4 +MERGE-EXCL-REGEX-SINGLE-PAT-NEXT: # Counter Values: +MERGE-EXCL-REGEX-SINGLE-PAT-NEXT: 1 +MERGE-EXCL-REGEX-SINGLE-PAT-NEXT: 1000 +MERGE-EXCL-REGEX-SINGLE-PAT-NEXT: 1000000 +MERGE-EXCL-REGEX-SINGLE-PAT-NEXT: 499500 + +# excluding profile for multiple patterns matching multiple functions +RUN: llvm-profdata merge --exclude-function "foo$|main" --text %p/Inputs/basic.proftext -o - | FileCheck %s --check-prefix=MERGE-EXCL-MULT-PAT +MERGE-EXCL-MULT-PAT-NOT: foo +MERGE-EXCL-MULT-PAT: foo2 +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: 500500 +MERGE-EXCL-MULT-PAT-NEXT: 180100 +MERGE-EXCL-MULT-PAT-NOT: main + +# excluding profile for multiple regex patterns matching multiple functions +RUN: llvm-profdata merge --exclude-function "foo2.*|ma.*" --text %p/Inputs/basic.proftext -o - | FileCheck %s --check-prefix=MERGE-EXCL-REGEX-MULT-PAT +MERGE-EXCL-REGEX-MULT-PAT: foo +MERGE-EXCL-REGEX-MULT-PAT-NEXT: # Func Hash: +MERGE-EXCL-REGEX-MULT-PAT-NEXT: 10 +MERGE-EXCL-REGEX-MULT-PAT-NEXT: # Num Counters: +MERGE-EXCL-REGEX-MULT-PAT-NEXT: 2 +MERGE-EXCL-REGEX-MULT-PAT-NEXT: # Counter Values: +MERGE-EXCL-REGEX-MULT-PAT-NEXT: 499500 +MERGE-EXCL-REGEX-MULT-PAT-NEXT: 179900 +MERGE-EXCL-REGEX-MULT-PAT-NOT: foo2 +MERGE-EXCL-REGEX-MULT-PAT-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 @@ -34,6 +34,7 @@ #include "llvm/Support/MD5.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/Threading.h" #include "llvm/Support/VirtualFileSystem.h" @@ -251,7 +252,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 ExcludeFuncs) { std::unique_lock CtxGuard{WC->Lock}; // Copy the filename, because llvm::ThreadPool copied the input "const @@ -327,6 +329,23 @@ I.Name = (*Remapper)(I.Name); const StringRef FuncName = I.Name; bool Reported = false; + + if (!ExcludeFuncs.empty()) { + Regex Re(ExcludeFuncs); + std::string Err; + if (!Re.isValid(Err)) { + WC->Errors.emplace_back( + make_error(Twine("Regex ") + ExcludeFuncs + + " is not valid: " + Err, + std::error_code()), + Filename); + return; + } + + if (Re.match(FuncName)) + 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 StringRef ExcludeFuncs) { 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(), ExcludeFuncs); } 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(), ExcludeFuncs); Ctx = (Ctx + 1) % NumThreads; } Pool.wait(); @@ -856,7 +876,8 @@ 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(), + /*ExcludeFuncs=*/""); if (WC->Errors.size() > 0) exitWithError(std::move(WC->Errors[0].first), InstrFilename); @@ -1254,6 +1275,9 @@ "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 ExcludeFuncs( + "exclude-function", + cl::desc("Exclude functions whose names match the regex")); cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n"); @@ -1287,16 +1311,25 @@ exitWithError( "-supplement-instr-with-sample can only work with -instr. "); + if (!ExcludeFuncs.empty()) + exitWithError("-exclude-function is not supported with " + "-supplement-instr-with-sample. "); + supplementInstrProfile(WeightedInputs, SupplInstrWithSample, OutputFilename, OutputFormat, OutputSparse, SupplMinSizeThreshold, ZeroCounterThreshold, InstrProfColdThreshold); return 0; } + if (!ExcludeFuncs.empty()) + if (ProfileKind != instr) + exitWithError( + "-exclude-function is only supported for -instr profiles. "); + if (ProfileKind == instr) mergeInstrProfile(WeightedInputs, DebugInfoFilename, Remapper.get(), OutputFilename, OutputFormat, OutputSparse, NumThreads, - FailureMode, ProfiledBinary); + FailureMode, ProfiledBinary, ExcludeFuncs); else mergeSampleProfile( WeightedInputs, Remapper.get(), OutputFilename, OutputFormat, @@ -1328,7 +1361,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, + /*ExcludeFuncs=*/""); overlapInput(BaseFilename, TestFilename, &Context, Overlap, FuncFilter, OS, IsCS); Overlap.dump(OS);