summaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-profdata/llvm-profdata.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
commit344a3780b2e33f6ca763666c380202b18aab72a3 (patch)
treef0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/tools/llvm-profdata/llvm-profdata.cpp
parentb60736ec1405bb0a8dd40989f67ef4c93da068ab (diff)
Diffstat (limited to 'llvm/tools/llvm-profdata/llvm-profdata.cpp')
-rw-r--r--llvm/tools/llvm-profdata/llvm-profdata.cpp212
1 files changed, 147 insertions, 65 deletions
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index 8dc43924c067..66d70120ac9b 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -20,6 +20,7 @@
#include "llvm/ProfileData/SampleProfReader.h"
#include "llvm/ProfileData/SampleProfWriter.h"
#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Discriminator.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
@@ -54,6 +55,14 @@ static void warn(Twine Message, std::string Whence = "",
WithColor::note() << Hint << "\n";
}
+static void warn(Error E, StringRef Whence = "") {
+ if (E.isA<InstrProfError>()) {
+ handleAllErrors(std::move(E), [&](const InstrProfError &IPE) {
+ warn(IPE.message(), std::string(Whence), std::string(""));
+ });
+ }
+}
+
static void exitWithError(Twine Message, std::string Whence = "",
std::string Hint = "") {
WithColor::error();
@@ -243,7 +252,8 @@ static void loadInput(const WeightedFile &Input, SymbolRemapper *Remapper,
auto Reader = std::move(ReaderOrErr.get());
bool IsIRProfile = Reader->isIRLevelProfile();
bool HasCSIRProfile = Reader->hasCSIRLevelProfile();
- if (WC->Writer.setIsIRLevelProfile(IsIRProfile, HasCSIRProfile)) {
+ if (Error E = WC->Writer.setIsIRLevelProfile(IsIRProfile, HasCSIRProfile)) {
+ consumeError(std::move(E));
WC->Errors.emplace_back(
make_error<StringError>(
"Merge IR generated profile with Clang generated profile.",
@@ -297,16 +307,19 @@ static void writeInstrProfile(StringRef OutputFilename,
InstrProfWriter &Writer) {
std::error_code EC;
raw_fd_ostream Output(OutputFilename.data(), EC,
- OutputFormat == PF_Text ? sys::fs::OF_Text
+ OutputFormat == PF_Text ? sys::fs::OF_TextWithCRLF
: sys::fs::OF_None);
if (EC)
exitWithErrorCode(EC, OutputFilename);
if (OutputFormat == PF_Text) {
if (Error E = Writer.writeText(Output))
- exitWithError(std::move(E));
+ warn(std::move(E));
} else {
- Writer.write(Output);
+ if (Output.is_displayed())
+ exitWithError("cannot write a non-text format profile to the terminal");
+ if (Error E = Writer.write(Output))
+ warn(std::move(E));
}
}
@@ -315,12 +328,9 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
StringRef OutputFilename,
ProfileFormat OutputFormat, bool OutputSparse,
unsigned NumThreads, FailureMode FailMode) {
- if (OutputFilename.compare("-") == 0)
- exitWithError("Cannot write indexed profdata format to stdout.");
-
if (OutputFormat != PF_Binary && OutputFormat != PF_Compact_Binary &&
OutputFormat != PF_Ext_Binary && OutputFormat != PF_Text)
- exitWithError("Unknown format is specified.");
+ exitWithError("unknown format is specified");
std::mutex ErrorLock;
SmallSet<instrprof_error, 4> WriterErrorCodes;
@@ -383,7 +393,7 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs,
}
if (NumErrors == Inputs.size() ||
(NumErrors > 0 && FailMode == failIfAnyAreInvalid))
- exitWithError("No profiles could be merged.");
+ exitWithError("no profile can be merged");
writeInstrProfile(OutputFilename, OutputFormat, Contexts[0]->Writer);
}
@@ -441,6 +451,25 @@ static void updateInstrProfileEntry(InstrProfileEntry &IFE,
const uint64_t ColdPercentileIdx = 15;
const uint64_t HotPercentileIdx = 11;
+using sampleprof::FSDiscriminatorPass;
+
+// Internal options to set FSDiscriminatorPass. Used in merge and show
+// commands.
+static cl::opt<FSDiscriminatorPass> FSDiscriminatorPassOption(
+ "fs-discriminator-pass", cl::init(PassLast), cl::Hidden,
+ cl::desc("Zero out the discriminator bits for the FS discrimiantor "
+ "pass beyond this value. The enum values are defined in "
+ "Support/Discriminator.h"),
+ cl::values(clEnumVal(Base, "Use base discriminators only"),
+ clEnumVal(Pass1, "Use base and pass 1 discriminators"),
+ clEnumVal(Pass2, "Use base and pass 1-2 discriminators"),
+ clEnumVal(Pass3, "Use base and pass 1-3 discriminators"),
+ clEnumVal(PassLast, "Use all discriminator bits (default)")));
+
+static unsigned getDiscriminatorMask() {
+ return getN1Bits(getFSPassBitEnd(FSDiscriminatorPassOption.getValue()));
+}
+
/// Adjust the instr profile in \p WC based on the sample profile in
/// \p Reader.
static void
@@ -522,18 +551,18 @@ static void supplementInstrProfile(
unsigned SupplMinSizeThreshold, float ZeroCounterThreshold,
unsigned InstrProfColdThreshold) {
if (OutputFilename.compare("-") == 0)
- exitWithError("Cannot write indexed profdata format to stdout.");
+ exitWithError("cannot write indexed profdata format to stdout");
if (Inputs.size() != 1)
- exitWithError("Expect one input to be an instr profile.");
+ exitWithError("expect one input to be an instr profile");
if (Inputs[0].Weight != 1)
- exitWithError("Expect instr profile doesn't have weight.");
+ exitWithError("expect instr profile doesn't have weight");
StringRef InstrFilename = Inputs[0].Filename;
// Read sample profile.
LLVMContext Context;
- auto ReaderOrErr =
- sampleprof::SampleProfileReader::create(SampleFilename.str(), Context);
+ auto ReaderOrErr = sampleprof::SampleProfileReader::create(
+ SampleFilename.str(), Context, FSDiscriminatorPassOption);
if (std::error_code EC = ReaderOrErr.getError())
exitWithErrorCode(EC, SampleFilename);
auto Reader = std::move(ReaderOrErr.get());
@@ -564,12 +593,13 @@ remapSamples(const sampleprof::FunctionSamples &Samples,
Result.addTotalSamples(Samples.getTotalSamples());
Result.addHeadSamples(Samples.getHeadSamples());
for (const auto &BodySample : Samples.getBodySamples()) {
- Result.addBodySamples(BodySample.first.LineOffset,
- BodySample.first.Discriminator,
+ uint32_t MaskedDiscriminator =
+ BodySample.first.Discriminator & getDiscriminatorMask();
+ Result.addBodySamples(BodySample.first.LineOffset, MaskedDiscriminator,
BodySample.second.getSamples());
for (const auto &Target : BodySample.second.getCallTargets()) {
Result.addCalledTargetSamples(BodySample.first.LineOffset,
- BodySample.first.Discriminator,
+ MaskedDiscriminator,
Remapper(Target.first()), Target.second);
}
}
@@ -656,15 +686,19 @@ static void
mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
StringRef OutputFilename, ProfileFormat OutputFormat,
StringRef ProfileSymbolListFile, bool CompressAllSections,
- bool UseMD5, bool GenPartialProfile, FailureMode FailMode) {
+ bool UseMD5, bool GenPartialProfile,
+ bool SampleMergeColdContext, bool SampleTrimColdContext,
+ bool SampleColdContextFrameDepth, FailureMode FailMode) {
using namespace sampleprof;
StringMap<FunctionSamples> ProfileMap;
SmallVector<std::unique_ptr<sampleprof::SampleProfileReader>, 5> Readers;
LLVMContext Context;
sampleprof::ProfileSymbolList WriterList;
Optional<bool> ProfileIsProbeBased;
+ Optional<bool> ProfileIsCS;
for (const auto &Input : Inputs) {
- auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context);
+ auto ReaderOrErr = SampleProfileReader::create(Input.Filename, Context,
+ FSDiscriminatorPassOption);
if (std::error_code EC = ReaderOrErr.getError()) {
warnOrExitGivenError(FailMode, EC, Input.Filename);
continue;
@@ -683,11 +717,14 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
}
StringMap<FunctionSamples> &Profiles = Reader->getProfiles();
- if (ProfileIsProbeBased &&
+ if (ProfileIsProbeBased.hasValue() &&
ProfileIsProbeBased != FunctionSamples::ProfileIsProbeBased)
exitWithError(
"cannot merge probe-based profile with non-probe-based profile");
ProfileIsProbeBased = FunctionSamples::ProfileIsProbeBased;
+ if (ProfileIsCS.hasValue() && ProfileIsCS != FunctionSamples::ProfileIsCS)
+ exitWithError("cannot merge CS profile with non-CS profile");
+ ProfileIsCS = FunctionSamples::ProfileIsCS;
for (StringMap<FunctionSamples>::iterator I = Profiles.begin(),
E = Profiles.end();
I != E; ++I) {
@@ -696,7 +733,7 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
Remapper ? remapSamples(I->second, *Remapper, Result)
: FunctionSamples();
FunctionSamples &Samples = Remapper ? Remapped : I->second;
- StringRef FName = Samples.getName();
+ StringRef FName = Samples.getNameWithContext();
MergeResult(Result, ProfileMap[FName].merge(Samples, Input.Weight));
if (Result != sampleprof_error::success) {
std::error_code EC = make_error_code(Result);
@@ -709,6 +746,22 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
if (ReaderList)
WriterList.merge(*ReaderList);
}
+
+ if (ProfileIsCS && (SampleMergeColdContext || SampleTrimColdContext)) {
+ // Use threshold calculated from profile summary unless specified.
+ SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
+ auto Summary = Builder.computeSummaryForProfiles(ProfileMap);
+ uint64_t SampleProfColdThreshold =
+ ProfileSummaryBuilder::getColdCountThreshold(
+ (Summary->getDetailedSummary()));
+
+ // Trim and merge cold context profile using cold threshold above;
+ SampleContextTrimmer(ProfileMap)
+ .trimAndMergeColdContextProfiles(
+ SampleProfColdThreshold, SampleTrimColdContext,
+ SampleMergeColdContext, SampleColdContextFrameDepth);
+ }
+
auto WriterOrErr =
SampleProfileWriter::create(OutputFilename, FormatMap[OutputFormat]);
if (std::error_code EC = WriterOrErr.getError())
@@ -720,7 +773,8 @@ mergeSampleProfile(const WeightedFileVector &Inputs, SymbolRemapper *Remapper,
auto Buffer = getInputFileBuf(ProfileSymbolListFile);
handleExtBinaryWriter(*Writer, OutputFormat, Buffer.get(), WriterList,
CompressAllSections, UseMD5, GenPartialProfile);
- Writer->write(ProfileMap);
+ if (std::error_code EC = Writer->write(ProfileMap))
+ exitWithErrorCode(std::move(EC));
}
static WeightedFile parseWeightedFile(const StringRef &WeightedFilename) {
@@ -729,7 +783,7 @@ static WeightedFile parseWeightedFile(const StringRef &WeightedFilename) {
uint64_t Weight;
if (WeightStr.getAsInteger(10, Weight) || Weight < 1)
- exitWithError("Input weight must be a positive integer.");
+ exitWithError("input weight must be a positive integer");
return {std::string(FileName), Weight};
}
@@ -808,8 +862,7 @@ static int merge_main(int argc, const char *argv[]) {
cl::alias RemappingFileA("r", cl::desc("Alias for --remapping-file"),
cl::aliasopt(RemappingFile));
cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
- cl::init("-"), cl::Required,
- cl::desc("Output file"));
+ cl::init("-"), cl::desc("Output file"));
cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
cl::aliasopt(OutputFilename));
cl::opt<ProfileKinds> ProfileKind(
@@ -851,6 +904,18 @@ static int merge_main(int argc, const char *argv[]) {
"use-md5", cl::init(false), cl::Hidden,
cl::desc("Choose to use MD5 to represent string in name table (only "
"meaningful for -extbinary)"));
+ cl::opt<bool> SampleMergeColdContext(
+ "sample-merge-cold-context", cl::init(false), cl::Hidden,
+ cl::desc(
+ "Merge context sample profiles whose count is below cold threshold"));
+ cl::opt<bool> SampleTrimColdContext(
+ "sample-trim-cold-context", cl::init(false), cl::Hidden,
+ 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,
+ cl::desc("Keep the last K frames while merging cold profile. 1 means the "
+ "context-less base profile"));
cl::opt<bool> GenPartialProfile(
"gen-partial-profile", cl::init(false), cl::Hidden,
cl::desc("Generate a partial profile (only meaningful for -extbinary)"));
@@ -866,16 +931,16 @@ static int merge_main(int argc, const char *argv[]) {
"sample profile, if the ratio of the number of zero counters "
"divided by the 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. "));
+ "being harmful for performance and will be dropped."));
cl::opt<unsigned> SupplMinSizeThreshold(
"suppl-min-size-threshold", cl::init(10), cl::Hidden,
cl::desc("If the size of a function is smaller than the threshold, "
"assume it can be inlined by PGO early inliner and it won't "
- "be adjusted based on sample profile. "));
+ "be adjusted based on sample profile."));
cl::opt<unsigned> InstrProfColdThreshold(
"instr-prof-cold-threshold", cl::init(0), cl::Hidden,
cl::desc("User specified cold threshold for instr profile which will "
- "override the cold threshold got from profile summary. "));
+ "override the cold threshold got from profile summary."));
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
@@ -891,7 +956,7 @@ static int merge_main(int argc, const char *argv[]) {
parseInputFilenamesFile(Buffer.get(), WeightedInputs);
if (WeightedInputs.empty())
- exitWithError("No input files specified. See " +
+ exitWithError("no input files specified. See " +
sys::path::filename(argv[0]) + " -help");
if (DumpInputFileList) {
@@ -921,7 +986,9 @@ static int merge_main(int argc, const char *argv[]) {
else
mergeSampleProfile(WeightedInputs, Remapper.get(), OutputFilename,
OutputFormat, ProfileSymbolListFile, CompressAllSections,
- UseMD5, GenPartialProfile, FailureMode);
+ UseMD5, GenPartialProfile, SampleMergeColdContext,
+ SampleTrimColdContext, SampleColdContextFrameDepth,
+ FailureMode);
return 0;
}
@@ -938,7 +1005,7 @@ static void overlapInstrProfile(const std::string &BaseFilename,
OverlapStats Overlap;
Error E = Overlap.accumulateCounts(BaseFilename, TestFilename, IsCS);
if (E)
- exitWithError(std::move(E), "Error in getting profile count sums");
+ exitWithError(std::move(E), "error in getting profile count sums");
if (Overlap.Base.CountSum < 1.0f) {
OS << "Sum of edge counts for profile " << BaseFilename << " is 0.\n";
exit(0);
@@ -1548,14 +1615,15 @@ void SampleOverlapAggregator::computeSampleProfileOverlap(raw_fd_ostream &OS) {
StringMap<const FunctionSamples *> BaseFuncProf;
const auto &BaseProfiles = BaseReader->getProfiles();
for (const auto &BaseFunc : BaseProfiles) {
- BaseFuncProf.try_emplace(BaseFunc.second.getName(), &(BaseFunc.second));
+ BaseFuncProf.try_emplace(BaseFunc.second.getNameWithContext(),
+ &(BaseFunc.second));
}
ProfOverlap.UnionCount = BaseFuncProf.size();
const auto &TestProfiles = TestReader->getProfiles();
for (const auto &TestFunc : TestProfiles) {
SampleOverlapStats FuncOverlap;
- FuncOverlap.TestName = TestFunc.second.getName();
+ FuncOverlap.TestName = TestFunc.second.getNameWithContext();
assert(TestStats.count(FuncOverlap.TestName) &&
"TestStats should have records for all functions in test profile "
"except inlinees");
@@ -1582,7 +1650,7 @@ void SampleOverlapAggregator::computeSampleProfileOverlap(raw_fd_ostream &OS) {
// Two functions match with each other. Compute function-level overlap and
// aggregate them into profile-level overlap.
- FuncOverlap.BaseName = Match->second->getName();
+ FuncOverlap.BaseName = Match->second->getNameWithContext();
assert(BaseStats.count(FuncOverlap.BaseName) &&
"BaseStats should have records for all functions in base profile "
"except inlinees");
@@ -1631,10 +1699,11 @@ void SampleOverlapAggregator::computeSampleProfileOverlap(raw_fd_ostream &OS) {
// Traverse through functions in base profile but not in test profile.
for (const auto &F : BaseFuncProf) {
- assert(BaseStats.count(F.second->getName()) &&
+ assert(BaseStats.count(F.second->getNameWithContext()) &&
"BaseStats should have records for all functions in base profile "
"except inlinees");
- const FuncSampleStats &FuncStats = BaseStats[F.second->getName()];
+ const FuncSampleStats &FuncStats =
+ BaseStats[F.second->getNameWithContext()];
++ProfOverlap.BaseUniqueCount;
ProfOverlap.BaseUniqueSample += FuncStats.SampleSum;
@@ -1665,7 +1734,7 @@ void SampleOverlapAggregator::initializeSampleProfileOverlap() {
FuncSampleStats FuncStats;
getFuncSampleStats(I.second, FuncStats, BaseHotThreshold);
ProfOverlap.BaseSample += FuncStats.SampleSum;
- BaseStats.try_emplace(I.second.getName(), FuncStats);
+ BaseStats.try_emplace(I.second.getNameWithContext(), FuncStats);
}
const auto &TestProf = TestReader->getProfiles();
@@ -1674,7 +1743,7 @@ void SampleOverlapAggregator::initializeSampleProfileOverlap() {
FuncSampleStats FuncStats;
getFuncSampleStats(I.second, FuncStats, TestHotThreshold);
ProfOverlap.TestSample += FuncStats.SampleSum;
- TestStats.try_emplace(I.second.getName(), FuncStats);
+ TestStats.try_emplace(I.second.getNameWithContext(), FuncStats);
}
ProfOverlap.BaseName = StringRef(BaseFilename);
@@ -1815,11 +1884,13 @@ std::error_code SampleOverlapAggregator::loadProfiles() {
using namespace sampleprof;
LLVMContext Context;
- auto BaseReaderOrErr = SampleProfileReader::create(BaseFilename, Context);
+ auto BaseReaderOrErr = SampleProfileReader::create(BaseFilename, Context,
+ FSDiscriminatorPassOption);
if (std::error_code EC = BaseReaderOrErr.getError())
exitWithErrorCode(EC, BaseFilename);
- auto TestReaderOrErr = SampleProfileReader::create(TestFilename, Context);
+ auto TestReaderOrErr = SampleProfileReader::create(TestFilename, Context,
+ FSDiscriminatorPassOption);
if (std::error_code EC = TestReaderOrErr.getError())
exitWithErrorCode(EC, TestFilename);
@@ -1833,6 +1904,8 @@ std::error_code SampleOverlapAggregator::loadProfiles() {
if (BaseReader->profileIsProbeBased() != TestReader->profileIsProbeBased())
exitWithError(
"cannot compare probe-based profile with non-probe-based profile");
+ if (BaseReader->profileIsCS() != TestReader->profileIsCS())
+ exitWithError("cannot compare CS profile with non-CS profile");
// Load BaseHotThreshold and TestHotThreshold as 99-percentile threshold in
// profile summary.
@@ -1888,21 +1961,24 @@ static int overlap_main(int argc, const char *argv[]) {
cl::opt<std::string> Output("output", cl::value_desc("output"), cl::init("-"),
cl::desc("Output file"));
cl::alias OutputA("o", cl::desc("Alias for --output"), cl::aliasopt(Output));
- cl::opt<bool> IsCS("cs", cl::init(false),
- cl::desc("For context sensitive counts"));
+ cl::opt<bool> IsCS(
+ "cs", cl::init(false),
+ cl::desc("For context sensitive PGO counts. Does not work with CSSPGO."));
cl::opt<unsigned long long> ValueCutoff(
"value-cutoff", cl::init(-1),
cl::desc(
- "Function level overlap information for every function in test "
+ "Function level overlap information for every function (with calling "
+ "context for csspgo) in test "
"profile with max count value greater then the parameter value"));
cl::opt<std::string> FuncNameFilter(
"function",
- cl::desc("Function level overlap information for matching functions"));
+ cl::desc("Function level overlap information for matching functions. For "
+ "CSSPGO this takes a a function name with calling context"));
cl::opt<unsigned long long> SimilarityCutoff(
"similarity-cutoff", cl::init(0),
- cl::desc(
- "For sample profiles, list function names for overlapped functions "
- "with similarities below the cutoff (percentage times 10000)."));
+ cl::desc("For sample profiles, list function names (with calling context "
+ "for csspgo) for overlapped functions "
+ "with similarities below the cutoff (percentage times 10000)."));
cl::opt<ProfileKinds> ProfileKind(
cl::desc("Profile kind:"), cl::init(instr),
cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
@@ -1910,7 +1986,7 @@ static int overlap_main(int argc, const char *argv[]) {
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data overlap tool\n");
std::error_code EC;
- raw_fd_ostream OS(Output.data(), EC, sys::fs::OF_Text);
+ raw_fd_ostream OS(Output.data(), EC, sys::fs::OF_TextWithCRLF);
if (EC)
exitWithErrorCode(EC, Output);
@@ -1926,7 +2002,8 @@ static int overlap_main(int argc, const char *argv[]) {
return 0;
}
-typedef struct ValueSitesStats {
+namespace {
+struct ValueSitesStats {
ValueSitesStats()
: TotalNumValueSites(0), TotalNumValueSitesWithValueProfile(0),
TotalNumValues(0) {}
@@ -1934,7 +2011,8 @@ typedef struct ValueSitesStats {
uint64_t TotalNumValueSitesWithValueProfile;
uint64_t TotalNumValues;
std::vector<unsigned> ValueSitesHistogram;
-} ValueSitesStats;
+};
+} // namespace
static void traverseAllValueSites(const InstrProfRecord &Func, uint32_t VK,
ValueSitesStats &Stats, raw_fd_ostream &OS,
@@ -1991,7 +2069,7 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
bool ShowAllFunctions, bool ShowCS,
uint64_t ValueCutoff, bool OnlyListBelow,
const std::string &ShowFunction, bool TextFormat,
- raw_fd_ostream &OS) {
+ bool ShowBinaryIds, raw_fd_ostream &OS) {
auto ReaderOrErr = InstrProfReader::create(Filename);
std::vector<uint32_t> Cutoffs = std::move(DetailedSummaryCutoffs);
if (ShowDetailedSummary && Cutoffs.empty()) {
@@ -2173,6 +2251,11 @@ static int showInstrProfile(const std::string &Filename, bool ShowCounts,
OS << "Total count: " << PS->getTotalCount() << "\n";
PS->printDetailedSummary(OS);
}
+
+ if (ShowBinaryIds)
+ if (Error E = Reader->printBinaryIds(OS))
+ exitWithError(std::move(E), Filename);
+
return 0;
}
@@ -2307,9 +2390,9 @@ showHotFunctionList(const StringMap<sampleprof::FunctionSamples> &Profiles,
(ProfileTotalSample > 0)
? (Func.getTotalSamples() * 100.0) / ProfileTotalSample
: 0;
- PrintValues.emplace_back(
- HotFuncInfo(Func.getName(), Func.getTotalSamples(), TotalSamplePercent,
- FuncPair.second.second, Func.getEntrySamples()));
+ PrintValues.emplace_back(HotFuncInfo(
+ Func.getNameWithContext(), Func.getTotalSamples(), TotalSamplePercent,
+ FuncPair.second.second, Func.getEntrySamples()));
}
dumpHotFunctionList(ColumnTitle, ColumnOffset, PrintValues, HotFuncCount,
Profiles.size(), HotFuncSample, ProfileTotalSample,
@@ -2326,12 +2409,12 @@ static int showSampleProfile(const std::string &Filename, bool ShowCounts,
raw_fd_ostream &OS) {
using namespace sampleprof;
LLVMContext Context;
- auto ReaderOrErr = SampleProfileReader::create(Filename, Context);
+ auto ReaderOrErr =
+ SampleProfileReader::create(Filename, Context, FSDiscriminatorPassOption);
if (std::error_code EC = ReaderOrErr.getError())
exitWithErrorCode(EC, Filename);
auto Reader = std::move(ReaderOrErr.get());
-
if (ShowSectionInfoOnly) {
showSectionInfo(Reader.get(), OS);
return 0;
@@ -2423,12 +2506,11 @@ static int show_main(int argc, const char *argv[]) {
cl::desc("Show the information of each section in the sample profile. "
"The flag is only usable when the sample profile is in "
"extbinary format"));
+ cl::opt<bool> ShowBinaryIds("binary-ids", cl::init(false),
+ cl::desc("Show binary ids in the profile. "));
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
- if (OutputFilename.empty())
- OutputFilename = "-";
-
if (Filename == OutputFilename) {
errs() << sys::path::filename(argv[0])
<< ": Input file name cannot be the same as the output file name!\n";
@@ -2436,7 +2518,7 @@ static int show_main(int argc, const char *argv[]) {
}
std::error_code EC;
- raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_Text);
+ raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::OF_TextWithCRLF);
if (EC)
exitWithErrorCode(EC, OutputFilename);
@@ -2444,11 +2526,11 @@ static int show_main(int argc, const char *argv[]) {
WithColor::warning() << "-function argument ignored: showing all functions\n";
if (ProfileKind == instr)
- return showInstrProfile(Filename, ShowCounts, TopNFunctions,
- ShowIndirectCallTargets, ShowMemOPSizes,
- ShowDetailedSummary, DetailedSummaryCutoffs,
- ShowAllFunctions, ShowCS, ValueCutoff,
- OnlyListBelow, ShowFunction, TextFormat, OS);
+ return showInstrProfile(
+ Filename, ShowCounts, TopNFunctions, ShowIndirectCallTargets,
+ ShowMemOPSizes, ShowDetailedSummary, DetailedSummaryCutoffs,
+ ShowAllFunctions, ShowCS, ValueCutoff, OnlyListBelow, ShowFunction,
+ TextFormat, ShowBinaryIds, OS);
else
return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
ShowDetailedSummary, ShowFunction,