diff --git a/llvm/tools/llvm-profgen/PerfReader.h b/llvm/tools/llvm-profgen/PerfReader.h --- a/llvm/tools/llvm-profgen/PerfReader.h +++ b/llvm/tools/llvm-profgen/PerfReader.h @@ -163,7 +163,7 @@ // LBR stack recorded in FIFO order SmallVector LBRStack; - HybridSample() : PerfSample(PK_HybridSample){}; + HybridSample(ProfiledBinary *B) : PerfSample(PK_HybridSample), Binary(B){}; static bool classof(const PerfSample *K) { return K->getKind() == PK_HybridSample; } @@ -531,24 +531,13 @@ const ProfiledBinary *Binary; }; -// Filename to binary map -using BinaryMap = StringMap; -// Address to binary map for fast look-up -using AddressBinaryMap = std::map; -// Binary to ContextSampleCounters Map to support multiple binary, we may have -// same binary loaded at different addresses, they should share the same sample -// counter -using BinarySampleCounterMap = - std::unordered_map; - // Load binaries and read perf trace to parse the events and samples class PerfReaderBase { public: - PerfReaderBase(cl::list &BinaryFilenames); + PerfReaderBase(StringRef BinaryPath); virtual ~PerfReaderBase() = default; static std::unique_ptr - create(cl::list &BinaryFilenames, - cl::list &PerfTraceFilenames); + create(StringRef BinaryPath, cl::list &PerfTraceFilenames); // A LBR sample is like: // 0x5c6313f/0x5c63170/P/-/-/0 0x5c630e7/0x5c63130/P/-/-/0 ... @@ -604,22 +593,20 @@ StringRef BinaryPath; }; - /// Load symbols and disassemble the code of a give binary. - /// Also register the binary in the binary table. - /// - ProfiledBinary &loadBinary(const StringRef BinaryPath, - bool AllowNameConflict = true); + /// Load symbols and disassemble the code of a given binary. + void loadBinary(StringRef BinaryPath); void updateBinaryAddress(const MMapEvent &Event); + ProfiledBinary *getBinary() const { return Binary; } PerfScriptType getPerfScriptType() const { return PerfType; } // Entry of the reader to parse multiple perf traces void parsePerfTraces(cl::list &PerfTraceFilenames); - const BinarySampleCounterMap &getBinarySampleCounters() const { - return BinarySampleCounters; + const ContextSampleCounterMap &getSampleCounters() const { + return SampleCounters; } protected: /// Validate the command line input - static void validateCommandLine(cl::list &BinaryFilenames, + static void validateCommandLine(StringRef BinaryPath, cl::list &PerfTraceFilenames); static PerfScriptType extractPerfType(cl::list &PerfTraceFilenames); @@ -636,8 +623,7 @@ SmallVectorImpl &CallStack); // Extract LBR stack from one perf trace line bool extractLBRStack(TraceStream &TraceIt, - SmallVectorImpl &LBRStack, - ProfiledBinary *Binary); + SmallVectorImpl &LBRStack); uint64_t parseAggregatedCount(TraceStream &TraceIt); // Parse one sample from multiple perf lines, override this for different // sample type @@ -648,13 +634,10 @@ // Post process the profile after trace aggregation, we will do simple range // overlap computation for AutoFDO, or unwind for CSSPGO(hybrid sample). virtual void generateRawProfile() = 0; - // Helper function for looking up binary in AddressBinaryMap - ProfiledBinary *getBinary(uint64_t Address); - BinaryMap BinaryTable; - AddressBinaryMap AddrToBinaryMap; // Used by address-based lookup. + ProfiledBinary *Binary = nullptr; - BinarySampleCounterMap BinarySampleCounters; + ContextSampleCounterMap SampleCounters; // Samples with the repeating time generated by the perf reader AggregatedCounter AggregatedSamples; PerfScriptType PerfType = PERF_UNKNOWN; @@ -671,8 +654,7 @@ */ class HybridPerfReader : public PerfReaderBase { public: - HybridPerfReader(cl::list &BinaryFilenames) - : PerfReaderBase(BinaryFilenames) { + HybridPerfReader(StringRef BinaryPath) : PerfReaderBase(BinaryPath) { PerfType = PERF_LBR_STACK; }; // Parse the hybrid sample including the call and LBR line diff --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp --- a/llvm/tools/llvm-profgen/PerfReader.cpp +++ b/llvm/tools/llvm-profgen/PerfReader.cpp @@ -245,8 +245,7 @@ } void PerfReaderBase::validateCommandLine( - cl::list &BinaryFilenames, - cl::list &PerfTraceFilenames) { + StringRef BinaryPath, cl::list &PerfTraceFilenames) { // Allow the invalid perfscript if we only use to show binary disassembly if (!ShowDisassemblyOnly) { for (auto &File : PerfTraceFilenames) { @@ -256,20 +255,12 @@ } } } - if (BinaryFilenames.size() > 1) { - // TODO: remove this if everything is ready to support multiple binaries. - exitWithError( - "Currently only support one input binary, multiple binaries' " - "profile will be merged in one profile and make profile " - "summary info inaccurate. Please use `llvm-perfdata` to merge " - "profiles from multiple binaries."); - } - for (auto &Binary : BinaryFilenames) { - if (!llvm::sys::fs::exists(Binary)) { - std::string Msg = "Input binary(" + Binary + ") doesn't exist!"; - exitWithError(Msg); - } + + if (!llvm::sys::fs::exists(BinaryPath)) { + std::string Msg = "Input binary(" + BinaryPath.str() + ") doesn't exist!"; + exitWithError(Msg); } + if (CSProfileGenerator::MaxCompressionSize < -1) { exitWithError("Value of --compress-recursion should >= -1"); } @@ -280,14 +271,14 @@ } std::unique_ptr -PerfReaderBase::create(cl::list &BinaryFilenames, +PerfReaderBase::create(StringRef BinaryPath, cl::list &PerfTraceFilenames) { - validateCommandLine(BinaryFilenames, PerfTraceFilenames); + validateCommandLine(BinaryPath, PerfTraceFilenames); PerfScriptType PerfType = extractPerfType(PerfTraceFilenames); std::unique_ptr PerfReader; if (PerfType == PERF_LBR_STACK) { - PerfReader.reset(new HybridPerfReader(BinaryFilenames)); + PerfReader.reset(new HybridPerfReader(BinaryPath)); } else if (PerfType == PERF_LBR) { // TODO: exitWithError("Unsupported perfscript!"); @@ -298,77 +289,48 @@ return PerfReader; } -PerfReaderBase::PerfReaderBase(cl::list &BinaryFilenames) { - // Load the binaries. - for (auto Filename : BinaryFilenames) - loadBinary(Filename, /*AllowNameConflict*/ false); +PerfReaderBase::PerfReaderBase(StringRef BinaryPath) { + // Load the binary. + loadBinary(BinaryPath); } -ProfiledBinary &PerfReaderBase::loadBinary(const StringRef BinaryPath, - bool AllowNameConflict) { - // The binary table is currently indexed by the binary name not the full - // binary path. This is because the user-given path may not match the one - // that was actually executed. - StringRef BinaryName = llvm::sys::path::filename(BinaryPath); - +void PerfReaderBase::loadBinary(StringRef BinaryPath) { // Call to load the binary in the ctor of ProfiledBinary. - auto Ret = BinaryTable.insert({BinaryName, ProfiledBinary(BinaryPath)}); - - if (!Ret.second && !AllowNameConflict) { - std::string ErrorMsg = "Binary name conflict: " + BinaryPath.str() + - " and " + Ret.first->second.getPath().str() + " \n"; - exitWithError(ErrorMsg); - } - + Binary = new ProfiledBinary(BinaryPath); // Initialize the base address to preferred address. - ProfiledBinary &B = Ret.first->second; - uint64_t PreferredAddr = B.getPreferredBaseAddress(); - AddrToBinaryMap[PreferredAddr] = &B; - B.setBaseAddress(PreferredAddr); - - return B; + Binary->setBaseAddress(Binary->getPreferredBaseAddress()); } void PerfReaderBase::updateBinaryAddress(const MMapEvent &Event) { - // Load the binary. - StringRef BinaryPath = Event.BinaryPath; - StringRef BinaryName = llvm::sys::path::filename(BinaryPath); - - auto I = BinaryTable.find(BinaryName); - // Drop the event which doesn't belong to user-provided binaries - if (I == BinaryTable.end()) + // Drop the event which doesn't belong to user-provided binary + StringRef BinaryName = llvm::sys::path::filename(Event.BinaryPath); + if (Binary->getName() != BinaryName) return; - ProfiledBinary &Binary = I->second; // Drop the event if its image is loaded at the same address - if (Event.Address == Binary.getBaseAddress()) { - Binary.setIsLoadedByMMap(true); + if (Event.Address == Binary->getBaseAddress()) { + Binary->setIsLoadedByMMap(true); return; } - if (Event.Offset == Binary.getTextSegmentOffset()) { + if (Event.Offset == Binary->getTextSegmentOffset()) { // A binary image could be unloaded and then reloaded at different - // place, so update the address map here. + // place, so update binary load address. // Only update for the first executable segment and assume all other // segments are loaded at consecutive memory addresses, which is the case on // X64. - AddrToBinaryMap.erase(Binary.getBaseAddress()); - AddrToBinaryMap[Event.Address] = &Binary; - - // Update binary load address. - Binary.setBaseAddress(Event.Address); - - Binary.setIsLoadedByMMap(true); + Binary->setBaseAddress(Event.Address); + Binary->setIsLoadedByMMap(true); } else { // Verify segments are loaded consecutively. - const auto &Offsets = Binary.getTextSegmentOffsets(); + const auto &Offsets = Binary->getTextSegmentOffsets(); auto It = std::lower_bound(Offsets.begin(), Offsets.end(), Event.Offset); if (It != Offsets.end() && *It == Event.Offset) { // The event is for loading a separate executable segment. auto I = std::distance(Offsets.begin(), It); - const auto &PreferredAddrs = Binary.getPreferredTextSegmentAddresses(); - if (PreferredAddrs[I] - Binary.getPreferredBaseAddress() != - Event.Address - Binary.getBaseAddress()) + const auto &PreferredAddrs = Binary->getPreferredTextSegmentAddresses(); + if (PreferredAddrs[I] - Binary->getPreferredBaseAddress() != + Event.Address - Binary->getBaseAddress()) exitWithError("Executable segments not loaded consecutively"); } else { if (It == Offsets.begin()) @@ -378,23 +340,13 @@ // via multiple mmap calls with consecutive memory addresses. --It; assert(*It < Event.Offset); - if (Event.Offset - *It != Event.Address - Binary.getBaseAddress()) + if (Event.Offset - *It != Event.Address - Binary->getBaseAddress()) exitWithError("Segment not loaded by consecutive mmaps"); } } } } -ProfiledBinary *PerfReaderBase::getBinary(uint64_t Address) { - auto Iter = AddrToBinaryMap.lower_bound(Address); - if (Iter == AddrToBinaryMap.end() || Iter->first != Address) { - if (Iter == AddrToBinaryMap.begin()) - return nullptr; - Iter--; - } - return Iter->second; -} - // Use ordered map to make the output deterministic using OrderedCounterForPrint = std::map; @@ -448,20 +400,16 @@ } void HybridPerfReader::printUnwinderOutput() { - for (auto I : BinarySampleCounters) { - const ProfiledBinary *Binary = I.first; outs() << "Binary(" << Binary->getName().str() << ")'s Range Counter:\n"; - printRangeCounter(I.second, Binary); + printRangeCounter(SampleCounters, Binary); outs() << "\nBinary(" << Binary->getName().str() << ")'s Branch Counter:\n"; - printBranchCounter(I.second, Binary); - } + printBranchCounter(SampleCounters, Binary); } void HybridPerfReader::unwindSamples() { for (const auto &Item : AggregatedSamples) { const HybridSample *Sample = dyn_cast(Item.first.getPtr()); - VirtualUnwinder Unwinder(&BinarySampleCounters[Sample->Binary], - Sample->Binary); + VirtualUnwinder Unwinder(&SampleCounters, Binary); Unwinder.unwind(Sample, Item.second); } @@ -470,8 +418,7 @@ } bool PerfReaderBase::extractLBRStack(TraceStream &TraceIt, - SmallVectorImpl &LBRStack, - ProfiledBinary *Binary) { + SmallVectorImpl &LBRStack) { // The raw format of LBR stack is like: // 0x4005c8/0x4005dc/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 ... // ... 0x4005c8/0x4005dc/P/-/-/0 @@ -572,7 +519,6 @@ // It's in bottom-up order with each frame in one line. // Extract stack frames from sample - ProfiledBinary *Binary = nullptr; while (!TraceIt.isAtEoF() && !TraceIt.getCurrentLine().startswith(" 0x")) { StringRef FrameStr = TraceIt.getCurrentLine().ltrim(); uint64_t FrameAddr = 0; @@ -583,16 +529,6 @@ return false; } TraceIt.advance(); - if (!Binary) { - Binary = getBinary(FrameAddr); - // we might have addr not match the MMAP, skip it - if (!Binary) { - if (AddrToBinaryMap.size() == 0) - WithColor::warning() << "No MMAP event in the perfscript, create it " - "with '--show-mmap-events'\n"; - break; - } - } // Currently intermixed frame from different binaries is not supported. // Ignore bottom frames not from binary of interest. if (!Binary->addressIsCode(FrameAddr)) @@ -635,7 +571,7 @@ // 0x4005c8/0x4005dc/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 ... // ... 0x4005c8/0x4005dc/P/-/-/0 # LBR Entries // - std::shared_ptr Sample = std::make_shared(); + std::shared_ptr Sample = std::make_shared(Binary); // Parsing call stack and populate into HybridSample.CallStack if (!extractCallstack(TraceIt, Sample->CallStack)) { @@ -644,19 +580,17 @@ TraceIt.advance(); return; } - // Set the binary current sample belongs to - ProfiledBinary *PB = getBinary(Sample->CallStack.front()); - Sample->Binary = PB; - if (!PB->getMissingMMapWarned() && !PB->getIsLoadedByMMap()) { + + if (!Binary->getMissingMMapWarned() && !Binary->getIsLoadedByMMap()) { WithColor::warning() << "No relevant mmap event is matched, will use " "preferred address as the base loading address!\n"; // Avoid redundant warning, only warn at the first unmatched sample. - PB->setMissingMMapWarned(true); + Binary->setMissingMMapWarned(true); } if (!TraceIt.isAtEoF() && TraceIt.getCurrentLine().startswith(" 0x")) { // Parsing LBR stack and populate into HybridSample.LBRStack - if (extractLBRStack(TraceIt, Sample->LBRStack, Sample->Binary)) { + if (extractLBRStack(TraceIt, Sample->LBRStack)) { // Canonicalize stack leaf to avoid 'random' IP from leaf frame skew LBR // ranges Sample->CallStack.front() = Sample->LBRStack[0].Target; diff --git a/llvm/tools/llvm-profgen/ProfileGenerator.h b/llvm/tools/llvm-profgen/ProfileGenerator.h --- a/llvm/tools/llvm-profgen/ProfileGenerator.h +++ b/llvm/tools/llvm-profgen/ProfileGenerator.h @@ -25,10 +25,10 @@ class ProfileGenerator { public: - ProfileGenerator(){}; + ProfileGenerator(ProfiledBinary *B) : Binary(B){}; virtual ~ProfileGenerator() = default; static std::unique_ptr - create(const BinarySampleCounterMap &BinarySampleCounters, + create(ProfiledBinary *Binary, const ContextSampleCounterMap &SampleCounters, enum PerfScriptType SampleType); virtual void generateProfile() = 0; // Use SampleProfileWriter to serialize profile map @@ -57,15 +57,18 @@ // Used by SampleProfileWriter StringMap ProfileMap; + + ProfiledBinary *Binary = nullptr; }; class CSProfileGenerator : public ProfileGenerator { protected: - const BinarySampleCounterMap &BinarySampleCounters; + const ContextSampleCounterMap &SampleCounters; public: - CSProfileGenerator(const BinarySampleCounterMap &Counters) - : BinarySampleCounters(Counters){}; + CSProfileGenerator(ProfiledBinary *Binary, + const ContextSampleCounterMap &Counters) + : ProfileGenerator(Binary), SampleCounters(Counters){}; public: void generateProfile() override; @@ -210,12 +213,10 @@ const FrameLocation &LeafLoc, uint64_t Count); void populateFunctionBodySamples(FunctionSamples &FunctionProfile, - const RangeSample &RangeCounters, - ProfiledBinary *Binary); + const RangeSample &RangeCounters); void populateFunctionBoundarySamples(StringRef ContextId, FunctionSamples &FunctionProfile, - const BranchSample &BranchCounters, - ProfiledBinary *Binary); + const BranchSample &BranchCounters); void populateInferredFunctionSamples(); public: @@ -231,25 +232,24 @@ class PseudoProbeCSProfileGenerator : public CSProfileGenerator { public: - PseudoProbeCSProfileGenerator(const BinarySampleCounterMap &Counters) - : CSProfileGenerator(Counters) {} + PseudoProbeCSProfileGenerator(ProfiledBinary *Binary, + const ContextSampleCounterMap &Counters) + : CSProfileGenerator(Binary, Counters) {} void generateProfile() override; private: // Go through each address from range to extract the top frame probe by // looking up in the Address2ProbeMap void extractProbesFromRange(const RangeSample &RangeCounter, - ProbeCounterMap &ProbeCounter, - ProfiledBinary *Binary); + ProbeCounterMap &ProbeCounter); // Fill in function body samples from probes void populateBodySamplesWithProbes(const RangeSample &RangeCounter, - SmallVectorImpl &ContextStrStack, - ProfiledBinary *Binary); + SmallVectorImpl &ContextStrStack); // Fill in boundary samples for a call probe void populateBoundarySamplesWithProbes( const BranchSample &BranchCounter, - SmallVectorImpl &ContextStrStack, ProfiledBinary *Binary); + SmallVectorImpl &ContextStrStack); // Helper function to get FunctionSamples for the leaf inlined context FunctionSamples & getFunctionProfileForLeafProbe(SmallVectorImpl &ContextStrStack, @@ -258,8 +258,7 @@ // Helper function to get FunctionSamples for the leaf probe FunctionSamples & getFunctionProfileForLeafProbe(SmallVectorImpl &ContextStrStack, - const MCDecodedPseudoProbe *LeafProbe, - ProfiledBinary *Binary); + const MCDecodedPseudoProbe *LeafProbe); }; } // end namespace sampleprof diff --git a/llvm/tools/llvm-profgen/ProfileGenerator.cpp b/llvm/tools/llvm-profgen/ProfileGenerator.cpp --- a/llvm/tools/llvm-profgen/ProfileGenerator.cpp +++ b/llvm/tools/llvm-profgen/ProfileGenerator.cpp @@ -73,22 +73,17 @@ int CSProfileGenerator::MaxContextDepth = -1; -static bool -usePseudoProbes(const BinarySampleCounterMap &BinarySampleCounters) { - return BinarySampleCounters.size() && - BinarySampleCounters.begin()->first->usePseudoProbes(); -} - std::unique_ptr -ProfileGenerator::create(const BinarySampleCounterMap &BinarySampleCounters, +ProfileGenerator::create(ProfiledBinary *Binary, + const ContextSampleCounterMap &SampleCounters, enum PerfScriptType SampleType) { std::unique_ptr ProfileGenerator; if (SampleType == PERF_LBR_STACK) { - if (usePseudoProbes(BinarySampleCounters)) { + if (Binary->usePseudoProbes()) { ProfileGenerator.reset( - new PseudoProbeCSProfileGenerator(BinarySampleCounters)); + new PseudoProbeCSProfileGenerator(Binary, SampleCounters)); } else { - ProfileGenerator.reset(new CSProfileGenerator(BinarySampleCounters)); + ProfileGenerator.reset(new CSProfileGenerator(Binary, SampleCounters)); } } else { // TODO: @@ -229,23 +224,19 @@ void CSProfileGenerator::generateProfile() { FunctionSamples::ProfileIsCS = true; - for (const auto &BI : BinarySampleCounters) { - ProfiledBinary *Binary = BI.first; - for (const auto &CI : BI.second) { - const StringBasedCtxKey *CtxKey = - dyn_cast(CI.first.getPtr()); - StringRef ContextId(CtxKey->Context); - // Get or create function profile for the range - FunctionSamples &FunctionProfile = - getFunctionProfileForContext(ContextId, CtxKey->WasLeafInlined); - - // Fill in function body samples - populateFunctionBodySamples(FunctionProfile, CI.second.RangeCounter, - Binary); - // Fill in boundary sample counts as well as call site samples for calls - populateFunctionBoundarySamples(ContextId, FunctionProfile, - CI.second.BranchCounter, Binary); - } + for (const auto &CI : SampleCounters) { + const StringBasedCtxKey *CtxKey = + dyn_cast(CI.first.getPtr()); + StringRef ContextId(CtxKey->Context); + // Get or create function profile for the range + FunctionSamples &FunctionProfile = + getFunctionProfileForContext(ContextId, CtxKey->WasLeafInlined); + + // Fill in function body samples + populateFunctionBodySamples(FunctionProfile, CI.second.RangeCounter); + // Fill in boundary sample counts as well as call site samples for calls + populateFunctionBoundarySamples(ContextId, FunctionProfile, + CI.second.BranchCounter); } // Fill in call site value sample for inlined calls and also use context to // infer missing samples. Since we don't have call count for inlined @@ -274,8 +265,7 @@ } void CSProfileGenerator::populateFunctionBodySamples( - FunctionSamples &FunctionProfile, const RangeSample &RangeCounter, - ProfiledBinary *Binary) { + FunctionSamples &FunctionProfile, const RangeSample &RangeCounter) { // Compute disjoint ranges first, so we can use MAX // for calculating count for each location. RangeSample Ranges; @@ -314,7 +304,7 @@ void CSProfileGenerator::populateFunctionBoundarySamples( StringRef ContextId, FunctionSamples &FunctionProfile, - const BranchSample &BranchCounters, ProfiledBinary *Binary) { + const BranchSample &BranchCounters) { for (auto Entry : BranchCounters) { uint64_t SourceOffset = Entry.first.first; @@ -450,8 +440,8 @@ // Helper function to extract context prefix string stack // Extract context stack for reusing, leaf context stack will // be added compressed while looking up function profile -static void -extractPrefixContextStack(SmallVectorImpl &ContextStrStack, +static void extractPrefixContextStack( + SmallVectorImpl &ContextStrStack, const SmallVectorImpl &Probes, ProfiledBinary *Binary) { for (const auto *P : Probes) { @@ -463,29 +453,23 @@ // Enable pseudo probe functionalities in SampleProf FunctionSamples::ProfileIsProbeBased = true; FunctionSamples::ProfileIsCS = true; - for (const auto &BI : BinarySampleCounters) { - ProfiledBinary *Binary = BI.first; - for (const auto &CI : BI.second) { - const ProbeBasedCtxKey *CtxKey = - dyn_cast(CI.first.getPtr()); - SmallVector ContextStrStack; - extractPrefixContextStack(ContextStrStack, CtxKey->Probes, Binary); - // Fill in function body samples from probes, also infer caller's samples - // from callee's probe - populateBodySamplesWithProbes(CI.second.RangeCounter, ContextStrStack, - Binary); - // Fill in boundary samples for a call probe - populateBoundarySamplesWithProbes(CI.second.BranchCounter, - ContextStrStack, Binary); - } + for (const auto &CI : SampleCounters) { + const ProbeBasedCtxKey *CtxKey = + dyn_cast(CI.first.getPtr()); + SmallVector ContextStrStack; + extractPrefixContextStack(ContextStrStack, CtxKey->Probes, Binary); + // Fill in function body samples from probes, also infer caller's samples + // from callee's probe + populateBodySamplesWithProbes(CI.second.RangeCounter, ContextStrStack); + // Fill in boundary samples for a call probe + populateBoundarySamplesWithProbes(CI.second.BranchCounter, ContextStrStack); } postProcessProfiles(); } void PseudoProbeCSProfileGenerator::extractProbesFromRange( - const RangeSample &RangeCounter, ProbeCounterMap &ProbeCounter, - ProfiledBinary *Binary) { + const RangeSample &RangeCounter, ProbeCounterMap &ProbeCounter) { RangeSample Ranges; findDisjointRanges(Ranges, RangeCounter); for (const auto &Range : Ranges) { @@ -524,11 +508,11 @@ void PseudoProbeCSProfileGenerator::populateBodySamplesWithProbes( const RangeSample &RangeCounter, - SmallVectorImpl &ContextStrStack, ProfiledBinary *Binary) { + SmallVectorImpl &ContextStrStack) { ProbeCounterMap ProbeCounter; // Extract the top frame probes by looking up each address among the range in // the Address2ProbeMap - extractProbesFromRange(RangeCounter, ProbeCounter, Binary); + extractProbesFromRange(RangeCounter, ProbeCounter); std::unordered_map> FrameSamples; @@ -536,7 +520,7 @@ const MCDecodedPseudoProbe *Probe = PI.first; uint64_t Count = PI.second; FunctionSamples &FunctionProfile = - getFunctionProfileForLeafProbe(ContextStrStack, Probe, Binary); + getFunctionProfileForLeafProbe(ContextStrStack, Probe); // Record the current frame and FunctionProfile whenever samples are // collected for non-danglie probes. This is for reporting all of the // zero count probes of the frame later. @@ -585,7 +569,7 @@ void PseudoProbeCSProfileGenerator::populateBoundarySamplesWithProbes( const BranchSample &BranchCounter, - SmallVectorImpl &ContextStrStack, ProfiledBinary *Binary) { + SmallVectorImpl &ContextStrStack) { for (auto BI : BranchCounter) { uint64_t SourceOffset = BI.first.first; uint64_t TargetOffset = BI.first.second; @@ -596,7 +580,7 @@ if (CallProbe == nullptr) continue; FunctionSamples &FunctionProfile = - getFunctionProfileForLeafProbe(ContextStrStack, CallProbe, Binary); + getFunctionProfileForLeafProbe(ContextStrStack, CallProbe); FunctionProfile.addBodySamples(CallProbe->getIndex(), 0, Count); FunctionProfile.addTotalSamples(Count); StringRef CalleeName = FunctionSamples::getCanonicalFnName( @@ -639,7 +623,7 @@ FunctionSamples &PseudoProbeCSProfileGenerator::getFunctionProfileForLeafProbe( SmallVectorImpl &ContextStrStack, - const MCDecodedPseudoProbe *LeafProbe, ProfiledBinary *Binary) { + const MCDecodedPseudoProbe *LeafProbe) { // Explicitly copy the context for appending the leaf context SmallVector ContextStrStackCopy(ContextStrStack.begin(), diff --git a/llvm/tools/llvm-profgen/llvm-profgen.cpp b/llvm/tools/llvm-profgen/llvm-profgen.cpp --- a/llvm/tools/llvm-profgen/llvm-profgen.cpp +++ b/llvm/tools/llvm-profgen/llvm-profgen.cpp @@ -27,11 +27,10 @@ "`script` command(the raw perf.data should be profiled with -b)"), cl::cat(ProfGenCategory)); -static cl::list - BinaryFilenames("binary", cl::value_desc("binary"), cl::OneOrMore, - llvm::cl::MiscFlags::CommaSeparated, - cl::desc("Path of profiled binary files"), - cl::cat(ProfGenCategory)); +static cl::opt BinaryPath( + "binary", cl::value_desc("binary"), cl::Required, + cl::desc("Path of profiled binary, only one binary is supported."), + cl::cat(ProfGenCategory)); extern cl::opt ShowDisassemblyOnly; @@ -50,19 +49,18 @@ cl::ParseCommandLineOptions(argc, argv, "llvm SPGO profile generator\n"); if (ShowDisassemblyOnly) { - for (auto BinaryPath : BinaryFilenames) { - (void)ProfiledBinary(BinaryPath); - } + (void)ProfiledBinary(BinaryPath); return EXIT_SUCCESS; } // Load binaries and parse perf events and samples std::unique_ptr Reader = - PerfReaderBase::create(BinaryFilenames, PerfTraceFilenames); + PerfReaderBase::create(BinaryPath, PerfTraceFilenames); Reader->parsePerfTraces(PerfTraceFilenames); - std::unique_ptr Generator = ProfileGenerator::create( - Reader->getBinarySampleCounters(), Reader->getPerfScriptType()); + std::unique_ptr Generator = + ProfileGenerator::create(Reader->getBinary(), Reader->getSampleCounters(), + Reader->getPerfScriptType()); Generator->generateProfile(); Generator->write();