aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-profdata/llvm-profdata.cpp
diff options
context:
space:
mode:
authorWilliam Junda Huang <williamjhuang@google.com>2024-01-23 16:19:45 -0500
committerGitHub <noreply@github.com>2024-01-23 16:19:45 -0500
commit2b8649fbecdc300cde1032d739484690f75a27ba (patch)
tree21ad93ddb71324ea10974f57c8874d97a7531d46 /llvm/tools/llvm-profdata/llvm-profdata.cpp
parent3a9ff32354a95305c523ab3b13bf3684854d1327 (diff)
downloadllvm-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.cpp73
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())