Index: tools/llvm-exegesis/lib/BenchmarkRunner.h =================================================================== --- tools/llvm-exegesis/lib/BenchmarkRunner.h +++ tools/llvm-exegesis/lib/BenchmarkRunner.h @@ -35,6 +35,9 @@ // The sequence of instructions that are to be repeated. std::vector Snippet; + + // Informations about how this configuration was built. + std::string Info; }; // Common code for all benchmark modes. @@ -56,8 +59,9 @@ virtual ~BenchmarkRunner(); - InstructionBenchmark run(unsigned Opcode, const InstructionFilter &Filter, - unsigned NumRepetitions); + llvm::Expected> + run(unsigned Opcode, const InstructionFilter &Filter, + unsigned NumRepetitions); protected: const LLVMState &State; @@ -65,11 +69,14 @@ const llvm::MCRegisterInfo &MCRegisterInfo; private: + InstructionBenchmark runOne(const BenchmarkConfiguration &Configuration, + unsigned Opcode, unsigned NumRepetitions) const; + virtual InstructionBenchmark::ModeE getMode() const = 0; - virtual llvm::Expected - createConfiguration(RegisterAliasingTrackerCache &RATC, unsigned Opcode, - llvm::raw_ostream &Debug) const = 0; + virtual llvm::Expected> + createConfigurations(RegisterAliasingTrackerCache &RATC, + unsigned Opcode) const = 0; virtual std::vector runMeasurements(const ExecutableFunction &EF, Index: tools/llvm-exegesis/lib/BenchmarkRunner.cpp =================================================================== --- tools/llvm-exegesis/lib/BenchmarkRunner.cpp +++ tools/llvm-exegesis/lib/BenchmarkRunner.cpp @@ -23,55 +23,62 @@ namespace exegesis { +static llvm::Error makeError(llvm::Twine Msg) { + return llvm::make_error(Msg, + llvm::inconvertibleErrorCode()); +} + BenchmarkRunner::InstructionFilter::~InstructionFilter() = default; + BenchmarkRunner::BenchmarkRunner(const LLVMState &State) : State(State), MCInstrInfo(State.getInstrInfo()), MCRegisterInfo(State.getRegInfo()), RATC(MCRegisterInfo, getFunctionReservedRegs(*State.createTargetMachine())) {} + BenchmarkRunner::~BenchmarkRunner() = default; -InstructionBenchmark BenchmarkRunner::run(unsigned Opcode, - const InstructionFilter &Filter, - unsigned NumRepetitions) { - InstructionBenchmark InstrBenchmark; +llvm::Expected> +BenchmarkRunner::run(unsigned Opcode, const InstructionFilter &Filter, + unsigned NumRepetitions) { + // Ignore instructions that we cannot run. + if (State.getInstrInfo().get(Opcode).isPseudo()) + return makeError("Unsupported opcode: isPseudo"); + + if (llvm::Error E = Filter.shouldRun(State, Opcode)) + return std::move(E); + + llvm::Expected> ConfigurationOrError = + createConfigurations(RATC, Opcode); + + if (llvm::Error E = ConfigurationOrError.takeError()) + return std::move(E); + + std::vector InstrBenchmarks; + for (const BenchmarkConfiguration &Conf : ConfigurationOrError.get()) + InstrBenchmarks.push_back(runOne(Conf, Opcode, NumRepetitions)); + return InstrBenchmarks; +} +InstructionBenchmark +BenchmarkRunner::runOne(const BenchmarkConfiguration &Configuration, + unsigned Opcode, unsigned NumRepetitions) const { + InstructionBenchmark InstrBenchmark; InstrBenchmark.Key.OpcodeName = State.getInstrInfo().getName(Opcode); InstrBenchmark.Mode = getMode(); InstrBenchmark.CpuName = State.getCpuName(); InstrBenchmark.LLVMTriple = State.getTriple(); InstrBenchmark.NumRepetitions = NumRepetitions; + InstrBenchmark.Info = Configuration.Info; - // Ignore instructions that we cannot run. - if (State.getInstrInfo().get(Opcode).isPseudo()) { - InstrBenchmark.Error = "Unsupported opcode: isPseudo"; - return InstrBenchmark; - } - if (llvm::Error E = Filter.shouldRun(State, Opcode)) { - InstrBenchmark.Error = llvm::toString(std::move(E)); - return InstrBenchmark; - } - llvm::raw_string_ostream InfoStream(InstrBenchmark.Info); - llvm::Expected ConfigurationOrError = - createConfiguration(RATC, Opcode, InfoStream); - if (llvm::Error E = ConfigurationOrError.takeError()) { - InstrBenchmark.Error = llvm::toString(std::move(E)); - return InstrBenchmark; - } - BenchmarkConfiguration &Configuration = ConfigurationOrError.get(); const std::vector &Snippet = Configuration.Snippet; if (Snippet.empty()) { InstrBenchmark.Error = "Empty snippet"; return InstrBenchmark; } - for (const auto &MCInst : Snippet) { + + for (const auto &MCInst : Snippet) InstrBenchmark.Key.Instructions.push_back(MCInst); - } - InfoStream << "Snippet:\n"; - for (const auto &MCInst : Snippet) { - DumpMCInst(MCRegisterInfo, MCInstrInfo, MCInst, InfoStream); - InfoStream << "\n"; - } std::vector Code; for (int I = 0; I < InstrBenchmark.NumRepetitions; ++I) Index: tools/llvm-exegesis/lib/Latency.h =================================================================== --- tools/llvm-exegesis/lib/Latency.h +++ tools/llvm-exegesis/lib/Latency.h @@ -27,9 +27,9 @@ private: InstructionBenchmark::ModeE getMode() const override; - llvm::Expected - createConfiguration(RegisterAliasingTrackerCache &RATC, unsigned OpcodeIndex, - llvm::raw_ostream &Info) const override; + llvm::Expected> + createConfigurations(RegisterAliasingTrackerCache &RATC, + unsigned OpcodeIndex) const override; std::vector runMeasurements(const ExecutableFunction &EF, Index: tools/llvm-exegesis/lib/Latency.cpp =================================================================== --- tools/llvm-exegesis/lib/Latency.cpp +++ tools/llvm-exegesis/lib/Latency.cpp @@ -56,12 +56,9 @@ return InstructionBenchmark::Latency; } -llvm::Expected -LatencyBenchmarkRunner::createConfiguration(RegisterAliasingTrackerCache &RATC, - unsigned Opcode, - llvm::raw_ostream &Info) const { - BenchmarkConfiguration Configuration; - std::vector &Snippet = Configuration.Snippet; +llvm::Expected> +LatencyBenchmarkRunner::createConfigurations(RegisterAliasingTrackerCache &RATC, + unsigned Opcode) const { const llvm::MCInstrDesc &MCInstrDesc = MCInstrInfo.get(Opcode); const Instruction ThisInstruction(MCInstrDesc, RATC); @@ -69,16 +66,17 @@ if (IsInfeasible(ThisInstruction, Error)) return makeError(llvm::Twine("Infeasible : ").concat(Error)); + BenchmarkConfiguration Conf; const AliasingConfigurations SelfAliasing(ThisInstruction, ThisInstruction); if (!SelfAliasing.empty()) { if (!SelfAliasing.hasImplicitAliasing()) { - Info << "explicit self cycles, selecting one aliasing configuration.\n"; + Conf.Info = "explicit self cycles, selecting one aliasing Conf."; setRandomAliasing(SelfAliasing); } else { - Info << "implicit Self cycles, picking random values.\n"; + Conf.Info = "implicit Self cycles, picking random values."; } - Snippet.push_back(randomizeUnsetVariablesAndBuild(ThisInstruction)); - return Configuration; + Conf.Snippet = {randomizeUnsetVariablesAndBuild(ThisInstruction)}; + return std::vector{Conf}; } // Let's try to create a dependency through another opcode. @@ -99,15 +97,17 @@ continue; setRandomAliasing(Forward); setRandomAliasing(Back); - Info << "creating cycle through " << MCInstrInfo.getName(OtherOpcode) - << ".\n"; - Snippet.push_back(randomizeUnsetVariablesAndBuild(ThisInstruction)); - Snippet.push_back(randomizeUnsetVariablesAndBuild(OtherInstruction)); - return Configuration; + Conf.Info = llvm::Twine("creating cycle through ") + .concat(MCInstrInfo.getName(OtherOpcode)) + .concat(".") + .str(); + Conf.Snippet.push_back(randomizeUnsetVariablesAndBuild(ThisInstruction)); + Conf.Snippet.push_back(randomizeUnsetVariablesAndBuild(OtherInstruction)); + return std::vector{Conf}; } return makeError( - "Infeasible : Didn't find any scheme to make the instruction serial\n"); + "Infeasible : Didn't find any scheme to make the instruction serial"); } std::vector Index: tools/llvm-exegesis/lib/Uops.h =================================================================== --- tools/llvm-exegesis/lib/Uops.h +++ tools/llvm-exegesis/lib/Uops.h @@ -27,9 +27,9 @@ private: InstructionBenchmark::ModeE getMode() const override; - llvm::Expected - createConfiguration(RegisterAliasingTrackerCache &RATC, unsigned Opcode, - llvm::raw_ostream &Info) const override; + llvm::Expected> + createConfigurations(RegisterAliasingTrackerCache &RATC, + unsigned Opcode) const override; std::vector runMeasurements(const ExecutableFunction &EF, Index: tools/llvm-exegesis/lib/Uops.cpp =================================================================== --- tools/llvm-exegesis/lib/Uops.cpp +++ tools/llvm-exegesis/lib/Uops.cpp @@ -145,40 +145,34 @@ return InstructionBenchmark::Uops; } -llvm::Expected -UopsBenchmarkRunner::createConfiguration(RegisterAliasingTrackerCache &RATC, - unsigned Opcode, - llvm::raw_ostream &Info) const { - BenchmarkConfiguration Configuration; - std::vector &Snippet = Configuration.Snippet; +llvm::Expected> +UopsBenchmarkRunner::createConfigurations(RegisterAliasingTrackerCache &RATC, + unsigned Opcode) const { const llvm::MCInstrDesc &MCInstrDesc = MCInstrInfo.get(Opcode); const Instruction Instruction(MCInstrDesc, RATC); std::string Error; - if (isInfeasible(Instruction, Error)) { - llvm::report_fatal_error(llvm::Twine("Infeasible : ").concat(Error)); - } + if (isInfeasible(Instruction, Error)) + return makeError(llvm::Twine("Infeasible : ").concat(Error)); + BenchmarkConfiguration Conf; const AliasingConfigurations SelfAliasing(Instruction, Instruction); if (SelfAliasing.empty()) { - Info << "instruction is parallel, repeating a random one.\n"; - Snippet.push_back(randomizeUnsetVariablesAndBuild(Instruction)); - return Configuration; + Conf.Info = "instruction is parallel, repeating a random one."; + Conf.Snippet = {randomizeUnsetVariablesAndBuild(Instruction)}; + return std::vector{Conf}; } if (SelfAliasing.hasImplicitAliasing()) { - Info << "instruction is serial, repeating a random one.\n"; - Snippet.push_back(randomizeUnsetVariablesAndBuild(Instruction)); - return Configuration; + Conf.Info = "instruction is serial, repeating a random one."; + Conf.Snippet = {randomizeUnsetVariablesAndBuild(Instruction)}; + return std::vector{Conf}; } const auto TiedVariables = getTiedVariables(Instruction); if (!TiedVariables.empty()) { - if (TiedVariables.size() > 1) { - Info << "Not yet implemented, don't know how to handle several tied " - "variables\n"; + if (TiedVariables.size() > 1) return makeError("Infeasible : don't know how to handle several tied " "variables"); - } - Info << "instruction has tied variables using static renaming.\n"; + Conf.Info = "instruction has tied variables using static renaming."; Variable *Var = TiedVariables.front(); assert(Var); assert(!Var->TiedOperands.empty()); @@ -187,9 +181,9 @@ for (const llvm::MCPhysReg Reg : Operand.Tracker->sourceBits().set_bits()) { clearVariableAssignments(Instruction); Var->AssignedValue = llvm::MCOperand::createReg(Reg); - Snippet.push_back(randomizeUnsetVariablesAndBuild(Instruction)); + Conf.Snippet.push_back(randomizeUnsetVariablesAndBuild(Instruction)); } - return Configuration; + return std::vector{Conf}; } // No tied variables, we pick random values for defs. llvm::BitVector Defs(MCRegisterInfo.getNumRegs()); @@ -217,10 +211,10 @@ Op.Var->AssignedValue = llvm::MCOperand::createReg(RandomReg); } } - Info - << "instruction has no tied variables picking Uses different from defs\n"; - Snippet.push_back(randomizeUnsetVariablesAndBuild(Instruction)); - return Configuration; + Conf.Info = + "instruction has no tied variables picking Uses different from defs"; + Conf.Snippet = {randomizeUnsetVariablesAndBuild(Instruction)}; + return std::vector{Conf}; } std::vector Index: tools/llvm-exegesis/llvm-exegesis.cpp =================================================================== --- tools/llvm-exegesis/llvm-exegesis.cpp +++ tools/llvm-exegesis/llvm-exegesis.cpp @@ -144,9 +144,12 @@ if (BenchmarkFile.empty()) BenchmarkFile = "-"; - ExitOnErr( - Runner->run(GetOpcodeOrDie(State.getInstrInfo()), Filter, NumRepetitions) - .writeYaml(getBenchmarkResultContext(State), BenchmarkFile)); + const BenchmarkResultContext Context = getBenchmarkResultContext(State); + std::vector Results = ExitOnErr(Runner->run( + GetOpcodeOrDie(State.getInstrInfo()), Filter, NumRepetitions)); + for (InstructionBenchmark &Result : Results) + Result.writeYaml(Context, BenchmarkFile); + exegesis::pfm::pfmTerminate(); }