aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-profdata/llvm-profdata.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-profdata/llvm-profdata.cpp')
-rw-r--r--llvm/tools/llvm-profdata/llvm-profdata.cpp107
1 files changed, 83 insertions, 24 deletions
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 6000460d3c23..9c6586483ef0 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -19,6 +19,7 @@
#include "llvm/ProfileData/InstrProfCorrelator.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/ProfileData/InstrProfWriter.h"
+#include "llvm/ProfileData/MemProf.h"
#include "llvm/ProfileData/ProfileCommon.h"
#include "llvm/ProfileData/RawMemProfReader.h"
#include "llvm/ProfileData/SampleProfReader.h"
@@ -37,6 +38,7 @@
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <queue>
using namespace llvm;
@@ -89,6 +91,7 @@ static void exitWithError(Error E, StringRef Whence = "") {
}
exitWithError(IPE.message(), std::string(Whence), std::string(Hint));
});
+ return;
}
exitWithError(toString(std::move(E)), std::string(Whence));
@@ -237,7 +240,7 @@ static void overlapInput(const std::string &BaseFilename,
/// Load an input into a writer context.
static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
const InstrProfCorrelator *Correlator,
- WriterContext *WC) {
+ const StringRef ProfiledBinary, WriterContext *WC) {
std::unique_lock<std::mutex> CtxGuard{WC->Lock};
// Copy the filename, because llvm::ThreadPool copied the input "const
@@ -245,6 +248,48 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
// invalid outside of this packaged task.
std::string Filename = Input.Filename;
+ using ::llvm::memprof::RawMemProfReader;
+ if (RawMemProfReader::hasFormat(Input.Filename)) {
+ auto ReaderOrErr = RawMemProfReader::create(Input.Filename, ProfiledBinary);
+ if (!ReaderOrErr) {
+ exitWithError(ReaderOrErr.takeError(), Input.Filename);
+ }
+ std::unique_ptr<RawMemProfReader> Reader = std::move(ReaderOrErr.get());
+ // Check if the profile types can be merged, e.g. clang frontend profiles
+ // should not be merged with memprof profiles.
+ if (Error E = WC->Writer.mergeProfileKind(Reader->getProfileKind())) {
+ consumeError(std::move(E));
+ WC->Errors.emplace_back(
+ make_error<StringError>(
+ "Cannot merge MemProf profile with Clang generated profile.",
+ std::error_code()),
+ Filename);
+ return;
+ }
+
+ auto MemProfError = [&](Error E) {
+ instrprof_error IPE = InstrProfError::take(std::move(E));
+ WC->Errors.emplace_back(make_error<InstrProfError>(IPE), Filename);
+ };
+
+ // Add the frame mappings into the writer context.
+ const auto &IdToFrame = Reader->getFrameMapping();
+ for (const auto &I : IdToFrame) {
+ bool Succeeded = WC->Writer.addMemProfFrame(
+ /*Id=*/I.first, /*Frame=*/I.getSecond(), MemProfError);
+ // If we weren't able to add the frame mappings then it doesn't make sense
+ // to try to add the records from this profile.
+ if (!Succeeded)
+ return;
+ }
+ const auto &FunctionProfileData = Reader->getProfileData();
+ // Add the memprof records into the writer context.
+ for (const auto &I : FunctionProfileData) {
+ WC->Writer.addMemProfRecord(/*Id=*/I.first, /*Record=*/I.second);
+ }
+ return;
+ }
+
auto ReaderOrErr = InstrProfReader::create(Input.Filename, Correlator);
if (Error E = ReaderOrErr.takeError()) {
// Skip the empty profiles by returning sliently.
@@ -330,7 +375,8 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
SymbolRemapper *Remapper,
StringRef OutputFilename,
ProfileFormat OutputFormat, bool OutputSparse,
- unsigned NumThreads, FailureMode FailMode) {
+ unsigned NumThreads, FailureMode FailMode,
+ const StringRef ProfiledBinary) {
if (OutputFormat != PF_Binary && OutputFormat != PF_Compact_Binary &&
OutputFormat != PF_Ext_Binary && OutputFormat != PF_Text)
exitWithError("unknown format is specified");
@@ -363,14 +409,15 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
if (NumThreads == 1) {
for (const auto &Input : Inputs)
- loadInput(Input, Remapper, Correlator.get(), Contexts[0].get());
+ loadInput(Input, Remapper, Correlator.get(), ProfiledBinary,
+ Contexts[0].get());
} else {
ThreadPool Pool(hardware_concurrency(NumThreads));
// Load the inputs in parallel (N/NumThreads serial steps).
unsigned Ctx = 0;
for (const auto &Input : Inputs) {
- Pool.async(loadInput, Input, Remapper, Correlator.get(),
+ Pool.async(loadInput, Input, Remapper, Correlator.get(), ProfiledBinary,
Contexts[Ctx].get());
Ctx = (Ctx + 1) % NumThreads;
}
@@ -587,7 +634,7 @@ static void supplementInstrProfile(
SmallSet<instrprof_error, 4> WriterErrorCodes;
auto WC = std::make_unique<WriterContext>(OutputSparse, ErrorLock,
WriterErrorCodes);
- loadInput(Inputs[0], nullptr, nullptr, WC.get());
+ loadInput(Inputs[0], nullptr, nullptr, /*ProfiledBinary=*/"", WC.get());
if (WC->Errors.size() > 0)
exitWithError(std::move(WC->Errors[0].first), InstrFilename);
@@ -708,7 +755,7 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
LLVMContext Context;
sampleprof::ProfileSymbolList WriterList;
Optional<bool> ProfileIsProbeBased;
- Optional<bool> ProfileIsCSFlat;
+ Optional<bool> ProfileIsCS;
for (const auto &Input : Inputs) {
auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context,
FSDiscriminatorPassOption);
@@ -730,15 +777,14 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
}
SampleProfileMap &Profiles = Reader->getProfiles();
- if (ProfileIsProbeBased.hasValue() &&
+ if (ProfileIsProbeBased &&
ProfileIsProbeBased != FunctionSamples::ProfileIsProbeBased)
exitWithError(
"cannot merge probe-based profile with non-probe-based profile");
ProfileIsProbeBased = FunctionSamples::ProfileIsProbeBased;
- if (ProfileIsCSFlat.hasValue() &&
- ProfileIsCSFlat != FunctionSamples::ProfileIsCSFlat)
+ if (ProfileIsCS && ProfileIsCS != FunctionSamples::ProfileIsCS)
exitWithError("cannot merge CS profile with non-CS profile");
- ProfileIsCSFlat = FunctionSamples::ProfileIsCSFlat;
+ ProfileIsCS = FunctionSamples::ProfileIsCS;
for (SampleProfileMap::iterator I = Profiles.begin(), E = Profiles.end();
I != E; ++I) {
sampleprof_error Result = sampleprof_error::success;
@@ -761,7 +807,7 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
WriterList.merge(*ReaderList);
}
- if (ProfileIsCSFlat && (SampleMergeColdContext || SampleTrimColdContext)) {
+ if (ProfileIsCS && (SampleMergeColdContext || SampleTrimColdContext)) {
// Use threshold calculated from profile summary unless specified.
SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
auto Summary = Builder.computeSummaryForProfiles(ProfileMap);
@@ -776,10 +822,10 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
SampleMergeColdContext, SampleColdContextFrameDepth, false);
}
- if (ProfileIsCSFlat && GenCSNestedProfile) {
+ if (ProfileIsCS && GenCSNestedProfile) {
CSProfileConverter CSConverter(ProfileMap);
CSConverter.convertProfiles();
- ProfileIsCSFlat = FunctionSamples::ProfileIsCSFlat = false;
+ ProfileIsCS = FunctionSamples::ProfileIsCS = false;
}
auto WriterOrErr =
@@ -933,7 +979,7 @@ static int merge_main(int argc, const char *argv[]) {
cl::desc(
"Trim context sample profiles whose count is below cold threshold"));
cl::opt<uint32_t> SampleColdContextFrameDepth(
- "sample-frame-depth-for-cold-context", cl::init(1), cl::ZeroOrMore,
+ "sample-frame-depth-for-cold-context", cl::init(1),
cl::desc("Keep the last K frames while merging cold profile. 1 means the "
"context-less base profile"));
cl::opt<bool> GenPartialProfile(
@@ -949,7 +995,7 @@ static int merge_main(int argc, const char *argv[]) {
"zero-counter-threshold", cl::init(0.7), cl::Hidden,
cl::desc("For the function which is cold in instr profile but hot in "
"sample profile, if the ratio of the number of zero counters "
- "divided by the the total number of counters is above the "
+ "divided by the total number of counters is above the "
"threshold, the profile of the function will be regarded as "
"being harmful for performance and will be dropped."));
cl::opt<unsigned> SupplMinSizeThreshold(
@@ -967,6 +1013,9 @@ static int merge_main(int argc, const char *argv[]) {
cl::opt<std::string> DebugInfoFilename(
"debug-info", cl::init(""),
cl::desc("Use the provided debug info to correlate the raw profile."));
+ cl::opt<std::string> ProfiledBinary(
+ "profiled-binary", cl::init(""),
+ cl::desc("Path to binary from which the profile was collected."));
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
@@ -1009,7 +1058,7 @@ static int merge_main(int argc, const char *argv[]) {
if (ProfileKind == instr)
mergeInstrProfile(WeightedInputs, DebugInfoFilename, Remapper.get(),
OutputFilename, OutputFormat, OutputSparse, NumThreads,
- FailureMode);
+ FailureMode, ProfiledBinary);
else
mergeSampleProfile(WeightedInputs, Remapper.get(), OutputFilename,
OutputFormat, ProfileSymbolListFile, CompressAllSections,
@@ -1040,7 +1089,7 @@ static void overlapInstrProfile(const std::string &BaseFilename,
OS << "Sum of edge counts for profile " << TestFilename << " is 0.\n";
exit(0);
}
- loadInput(WeightedInput, nullptr, nullptr, &Context);
+ loadInput(WeightedInput, nullptr, nullptr, /*ProfiledBinary=*/"", &Context);
overlapInput(BaseFilename, TestFilename, &Context, Overlap, FuncFilter, OS,
IsCS);
Overlap.dump(OS);
@@ -1936,7 +1985,7 @@ std::error_code SampleOverlapAggregator::loadProfiles() {
if (BaseReader->profileIsProbeBased() != TestReader->profileIsProbeBased())
exitWithError(
"cannot compare probe-based profile with non-probe-based profile");
- if (BaseReader->profileIsCSFlat() != TestReader->profileIsCSFlat())
+ if (BaseReader->profileIsCS() != TestReader->profileIsCS())
exitWithError("cannot compare CS profile with non-CS profile");
// Load BaseHotThreshold and TestHotThreshold as 99-percentile threshold in
@@ -2097,7 +2146,7 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
auto ReaderOrErr = InstrProfReader::create(Filename);
std::vector<uint32_t> Cutoffs = std::move(DetailedSummaryCutoffs);
if (ShowDetailedSummary && Cutoffs.empty()) {
- Cutoffs = {800000, 900000, 950000, 990000, 999000, 999900, 999990};
+ Cutoffs = ProfileSummaryBuilder::DefaultCutoffs;
}
InstrProfSummaryBuilder Builder(std::move(Cutoffs));
if (Error E = ReaderOrErr.takeError())
@@ -2480,14 +2529,21 @@ static int showSampleProfile(const std::string &Filename, bool ShowCounts,
return 0;
}
-static int showMemProfProfile(const std::string &Filename, raw_fd_ostream &OS) {
- auto ReaderOr = llvm::memprof::RawMemProfReader::create(Filename);
+static int showMemProfProfile(const std::string &Filename,
+ const std::string &ProfiledBinary,
+ raw_fd_ostream &OS) {
+ auto ReaderOr = llvm::memprof::RawMemProfReader::create(
+ Filename, ProfiledBinary, /*KeepNames=*/true);
if (Error E = ReaderOr.takeError())
- exitWithError(std::move(E), Filename);
+ // Since the error can be related to the profile or the binary we do not
+ // pass whence. Instead additional context is provided where necessary in
+ // the error message.
+ exitWithError(std::move(E), /*Whence*/ "");
std::unique_ptr<llvm::memprof::RawMemProfReader> Reader(
ReaderOr.get().release());
- Reader->printSummaries(OS);
+
+ Reader->printYAML(OS);
return 0;
}
@@ -2587,6 +2643,9 @@ static int show_main(int argc, const char *argv[]) {
cl::opt<bool> ShowCovered(
"covered", cl::init(false),
cl::desc("Show only the functions that have been executed."));
+ cl::opt<std::string> ProfiledBinary(
+ "profiled-binary", cl::init(""),
+ cl::desc("Path to binary from which the profile was collected."));
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
@@ -2624,7 +2683,7 @@ static int show_main(int argc, const char *argv[]) {
ShowAllFunctions, ShowDetailedSummary,
ShowFunction, ShowProfileSymbolList,
ShowSectionInfoOnly, ShowHotFuncList, OS);
- return showMemProfProfile(Filename, OS);
+ return showMemProfProfile(Filename, ProfiledBinary, OS);
}
int main(int argc, const char *argv[]) {