diff options
author | William Junda Huang <williamjhuang@google.com> | 2024-01-23 16:19:45 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-23 16:19:45 -0500 |
commit | 2b8649fbecdc300cde1032d739484690f75a27ba (patch) | |
tree | 21ad93ddb71324ea10974f57c8874d97a7531d46 /llvm/tools/llvm-profdata/llvm-profdata.cpp | |
parent | 3a9ff32354a95305c523ab3b13bf3684854d1327 (diff) | |
download | llvm-2b8649fbecdc300cde1032d739484690f75a27ba.zip llvm-2b8649fbecdc300cde1032d739484690f75a27ba.tar.gz llvm-2b8649fbecdc300cde1032d739484690f75a27ba.tar.bz2 |
Added feature in llvm-profdata merge to filter functions from the profile (#78378)
`--function=<regex>` Include functions matching regex in the output
`--no-function=<regex>` Exclude functions matching regex from the output
If both are specified, `--no-function` has a higher precedence if a
function name matches both filters
Diffstat (limited to 'llvm/tools/llvm-profdata/llvm-profdata.cpp')
-rw-r--r-- | llvm/tools/llvm-profdata/llvm-profdata.cpp | 73 |
1 files changed, 70 insertions, 3 deletions
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp index e6dc81b..239aa1c 100644 --- 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" @@ -131,9 +132,11 @@ cl::opt<std::string> cl::sub(MergeSubcommand)); cl::opt<std::string> FuncNameFilter( "function", - cl::desc("Details for matching functions. For overlapping CSSPGO, this " - "takes a function name with calling context."), - cl::sub(ShowSubcommand), cl::sub(OverlapSubcommand)); + cl::desc("Only functions matching the filter are shown in the output. For " + "overlapping CSSPGO, this takes a function name with calling " + "context."), + cl::sub(ShowSubcommand), cl::sub(OverlapSubcommand), + cl::sub(MergeSubcommand)); // TODO: Consider creating a template class (e.g., MergeOption, ShowOption) to // factor out the common cl::sub in cl::opt constructor for subcommand-specific @@ -243,6 +246,10 @@ cl::opt<uint64_t> TemporalProfMaxTraceLength( cl::sub(MergeSubcommand), cl::desc("The maximum length of a single temporal profile trace " "(default: 10000)")); +cl::opt<std::string> FuncNameNegativeFilter( + "no-function", cl::init(""), + cl::sub(MergeSubcommand), + cl::desc("Exclude functions matching the filter from the output.")); cl::opt<FailureMode> FailMode("failure-mode", cl::init(failIfAnyAreInvalid), @@ -759,6 +766,62 @@ static void mergeWriterContexts(WriterContext *Dst, WriterContext *Src) { }); } +static StringRef +getFuncName(const StringMap<InstrProfWriter::ProfilingData>::value_type &Val) { + return Val.first(); +} + +static std::string +getFuncName(const SampleProfileMap::value_type &Val) { + return Val.second.getContext().toString(); +} + +template <typename T> +static void filterFunctions(T &ProfileMap) { + bool hasFilter = !FuncNameFilter.empty(); + bool hasNegativeFilter = !FuncNameNegativeFilter.empty(); + if (!hasFilter && !hasNegativeFilter) + return; + + // If filter starts with '?' it is MSVC mangled name, not a regex. + llvm::Regex ProbablyMSVCMangledName("[?@$_0-9A-Za-z]+"); + if (hasFilter && FuncNameFilter[0] == '?' && + ProbablyMSVCMangledName.match(FuncNameFilter)) + FuncNameFilter = llvm::Regex::escape(FuncNameFilter); + if (hasNegativeFilter && FuncNameNegativeFilter[0] == '?' && + ProbablyMSVCMangledName.match(FuncNameNegativeFilter)) + FuncNameNegativeFilter = llvm::Regex::escape(FuncNameNegativeFilter); + + size_t Count = ProfileMap.size(); + llvm::Regex Pattern(FuncNameFilter); + llvm::Regex NegativePattern(FuncNameNegativeFilter); + std::string Error; + if (hasFilter && !Pattern.isValid(Error)) + exitWithError(Error); + if (hasNegativeFilter && !NegativePattern.isValid(Error)) + exitWithError(Error); + + // Handle MD5 profile, so it is still able to match using the original name. + std::string MD5Name = std::to_string(llvm::MD5Hash(FuncNameFilter)); + std::string NegativeMD5Name = + std::to_string(llvm::MD5Hash(FuncNameNegativeFilter)); + + for (auto I = ProfileMap.begin(); I != ProfileMap.end();) { + auto Tmp = I++; + const auto &FuncName = getFuncName(*Tmp); + // Negative filter has higher precedence than positive filter. + if ((hasNegativeFilter && + (NegativePattern.match(FuncName) || + (FunctionSamples::UseMD5 && NegativeMD5Name == FuncName))) || + (hasFilter && !(Pattern.match(FuncName) || + (FunctionSamples::UseMD5 && MD5Name == FuncName)))) + ProfileMap.erase(Tmp); + } + + llvm::dbgs() << Count - ProfileMap.size() << " of " << Count << " functions " + << "in the original profile are filtered.\n"; +} + static void writeInstrProfile(StringRef OutputFilename, ProfileFormat OutputFormat, InstrProfWriter &Writer) { @@ -878,6 +941,8 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs, (NumErrors > 0 && FailMode == failIfAnyAreInvalid)) exitWithError("no profile can be merged"); + filterFunctions(Contexts[0]->Writer.getProfileData()); + writeInstrProfile(OutputFilename, OutputFormat, Contexts[0]->Writer); } @@ -1459,6 +1524,8 @@ static void mergeSampleProfile(const WeightedFileVector &Inputs, ProfileIsCS = FunctionSamples::ProfileIsCS = false; } + filterFunctions(ProfileMap); + auto WriterOrErr = SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]); if (std::error_code EC = WriterOrErr.getError()) |