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 @@ -502,19 +502,29 @@ class PerfReader { public: - PerfReader(cl::list &BinaryFilenames); + PerfReader(cl::list &BinaryFilenames, + cl::list &PerfTraceFilenames); - // Hybrid sample(call stack + LBRs) profile traces are seprated by double line - // break, search for that within the first 4k charactors to avoid going - // through the whole file. + // Determine the perfscript contains hybrid samples(call stack + LBRs) by + // checking whether there is a non-empty call stack immediately followed by + // a LBR sample static bool isHybridPerfScript(StringRef FileName) { - auto BufOrError = MemoryBuffer::getFileOrSTDIN(FileName, 4000); - if (!BufOrError) - exitWithError(BufOrError.getError(), FileName); - auto Buffer = std::move(BufOrError.get()); - if (Buffer->getBuffer().find("\n\n") == StringRef::npos) - return false; - return true; + TraceStream TraceIt(FileName); + uint64_t FrameAddr = 0; + while (!TraceIt.isAtEoF()) { + int32_t Count = 0; + while (!TraceIt.isAtEoF() && + !TraceIt.getCurrentLine().ltrim().getAsInteger(16, FrameAddr)) { + Count++; + TraceIt.advance(); + } + if (!TraceIt.isAtEoF()) { + if (Count && TraceIt.getCurrentLine().startswith(" 0x")) + return true; + TraceIt.advance(); + } + } + return false; } // The parsed MMap event @@ -540,6 +550,9 @@ } private: + /// Validate the command line input + void validateCommandLine(cl::list &BinaryFilenames, + cl::list &PerfTraceFilenames); /// Parse a single line of a PERF_RECORD_MMAP2 event looking for a /// mapping between the binary name and its memory layout. /// 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 @@ -230,7 +230,45 @@ return true; } -PerfReader::PerfReader(cl::list &BinaryFilenames) { +void PerfReader::validateCommandLine( + cl::list &BinaryFilenames, + cl::list &PerfTraceFilenames) { + // Allow the invalid perfscript if we only use to show binary disassembly + if (!ProfiledBinary::isShowDisassemblyEnable()) { + for (auto &File : PerfTraceFilenames) { + if (!llvm::sys::fs::exists(File)) { + std::string Msg = "Input perf script(" + File + ") doesn't exist!"; + exitWithError(Msg); + } + } + } + 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 (CSProfileGenerator::MaxCompressionSize < -1) { + exitWithError("Value of --compress-recursion should >= -1"); + } + if (ProfiledBinary::isShowSourceLocationsEnable() && + !ProfiledBinary::isShowDisassemblyEnable()) { + exitWithError("--show-source-locations should work together with " + "--show-disassembly!"); + } +} + +PerfReader::PerfReader(cl::list &BinaryFilenames, + cl::list &PerfTraceFilenames) { + validateCommandLine(BinaryFilenames, PerfTraceFilenames); // Load the binaries. for (auto Filename : BinaryFilenames) loadBinary(Filename, /*AllowNameConflict*/ false); @@ -605,14 +643,6 @@ // TODO: Support other type of perf script PerfType = PERF_INVILID; } - - if (BinaryTable.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 `perfdata` to merge " - "profiles from multiple binaries."); - } } void PerfReader::generateRawProfile() { 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 @@ -11,7 +11,8 @@ static cl::opt OutputFilename("output", cl::value_desc("output"), cl::Required, cl::desc("Output profile file")); - +static cl::alias OutputA("o", cl::desc("Alias for --output"), + cl::aliasopt(OutputFilename)); static cl::opt OutputFormat( "format", cl::desc("Format of output profile"), cl::init(SPF_Text), cl::values( diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.h b/llvm/tools/llvm-profgen/ProfiledBinary.h --- a/llvm/tools/llvm-profgen/ProfiledBinary.h +++ b/llvm/tools/llvm-profgen/ProfiledBinary.h @@ -258,6 +258,8 @@ const PseudoProbeFuncDesc *getInlinerDescForProbe(const PseudoProbe *Probe) { return ProbeDecoder.getInlinerDescForProbe(Probe); } + static bool isShowDisassemblyEnable(); + static bool isShowSourceLocationsEnable(); }; } // end namespace sampleprof diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.cpp b/llvm/tools/llvm-profgen/ProfiledBinary.cpp --- a/llvm/tools/llvm-profgen/ProfiledBinary.cpp +++ b/llvm/tools/llvm-profgen/ProfiledBinary.cpp @@ -401,6 +401,12 @@ return CallStack; } +bool ProfiledBinary::isShowDisassemblyEnable() { return ShowDisassembly; } + +bool ProfiledBinary::isShowSourceLocationsEnable() { + return ShowSourceLocations; +} + InstructionPointer::InstructionPointer(ProfiledBinary *Binary, uint64_t Address, bool RoundToNext) : Binary(Binary), Address(Address) { 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 @@ -43,7 +43,7 @@ cl::ParseCommandLineOptions(argc, argv, "llvm SPGO profile generator\n"); // Load binaries and parse perf events and samples - PerfReader Reader(BinaryFilenames); + PerfReader Reader(BinaryFilenames, PerfTraceFilenames); Reader.parsePerfTraces(PerfTraceFilenames); std::unique_ptr Generator = ProfileGenerator::create(