diff options
Diffstat (limited to 'llvm/tools/llvm-profdata/llvm-profdata.cpp')
| -rw-r--r-- | llvm/tools/llvm-profdata/llvm-profdata.cpp | 107 |
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[]) { |
