diff --git a/llvm/tools/llvm-exegesis/lib/ProgressMeter.h b/llvm/tools/llvm-exegesis/lib/ProgressMeter.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-exegesis/lib/ProgressMeter.h @@ -0,0 +1,147 @@ +//===-- ProgressMeter.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_EXEGESIS_PROGRESSMETER_H +#define LLVM_TOOLS_LLVM_EXEGESIS_PROGRESSMETER_H + +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include +#include + +namespace llvm { +namespace exegesis { + +template class RunningAverage { + NumTy Accumulated = NumTy(); + DenTy Steps = 0; + +public: + RunningAverage() = default; + RunningAverage(const RunningAverage &) = delete; + RunningAverage(RunningAverage &&) = delete; + RunningAverage &operator=(const RunningAverage &) = delete; + RunningAverage &operator=(RunningAverage &&) = delete; + + void step(NumTy Quantity); + + NumTy getAccumulated() const; + + DenTy getNumSteps() const; + + template AvgTy getAverage() const; +}; + +template +void RunningAverage::step(NumTy Quantity) { + Accumulated += Quantity; + ++Steps; +} + +template +NumTy RunningAverage::getAccumulated() const { + return Accumulated; +} + +template +DenTy RunningAverage::getNumSteps() const { + return Steps; +} + +template +template +AvgTy RunningAverage::getAverage() const { + return AvgTy(Accumulated) / Steps; +} + +class ProgressMeter { + friend class ProgressMeterStep; + +public: + using ClockType = std::chrono::steady_clock; + using TimePointType = std::chrono::time_point; + using DurationType = std::chrono::duration; + using CompetionPercentage = int; + using Sec = std::chrono::duration; + + class ProgressMeterStep; + + ProgressMeter(int NumStepsTotal); + ProgressMeter(const ProgressMeter &) = delete; + ProgressMeter(ProgressMeter &&) = delete; + ProgressMeter &operator=(const ProgressMeter &) = delete; + ProgressMeter &operator=(ProgressMeter &&) = delete; + +private: + void step(DurationType Elapsed); + + std::pair eta() const; + + const int numStepsTotal; + RunningAverage elapsedTotal; +}; + +class ProgressMeter::ProgressMeterStep { + ProgressMeter *P; + const TimePointType Begin; + +public: + ProgressMeterStep(ProgressMeter *P); + ~ProgressMeterStep(); + + ProgressMeterStep(const ProgressMeterStep &) = delete; + ProgressMeterStep(ProgressMeterStep &&) = delete; + ProgressMeterStep &operator=(const ProgressMeterStep &) = delete; + ProgressMeterStep &operator=(ProgressMeterStep &&) = delete; +}; + +ProgressMeter::ProgressMeterStep::ProgressMeterStep(ProgressMeter *P_) + : P(P_), Begin(P ? ProgressMeter::ClockType::now() : TimePointType()) {} + +ProgressMeter::ProgressMeterStep::~ProgressMeterStep() { + if (!P) + return; + const TimePointType End = ProgressMeter::ClockType::now(); + P->step(End - Begin); +} + +ProgressMeter::ProgressMeter(int NumStepsTotal_) + : numStepsTotal(NumStepsTotal_) {} + +void ProgressMeter::step(ProgressMeter::DurationType Elapsed) { + auto [OldProgress, OldEta] = eta(); + elapsedTotal.step(Elapsed); + auto [NewProgress, NewEta] = eta(); + + if (NewProgress < OldProgress + 1) + return; + + int Unaccounted = std::ceil(NewEta.count()); + int Seconds = Unaccounted % 60; + Unaccounted /= 60; + int Minutes = Unaccounted; + + errs() << format("Processing... %*d%%, ETA %02d:%02d\n", 3, NewProgress, + Minutes, Seconds); +} + +std::pair +ProgressMeter::eta() const { + CompetionPercentage progress = + (100 * elapsedTotal.getNumSteps()) / numStepsTotal; + + Sec averageStepDuration = elapsedTotal.getAverage(); + Sec eta = (numStepsTotal - elapsedTotal.getNumSteps()) * averageStepDuration; + + return {progress, eta}; +} + +} // namespace exegesis +} // namespace llvm + +#endif diff --git a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp --- a/llvm/tools/llvm-exegesis/llvm-exegesis.cpp +++ b/llvm/tools/llvm-exegesis/llvm-exegesis.cpp @@ -18,6 +18,7 @@ #include "lib/Error.h" #include "lib/LlvmState.h" #include "lib/PerfHelper.h" +#include "lib/ProgressMeter.h" #include "lib/SnippetFile.h" #include "lib/SnippetRepetitor.h" #include "lib/Target.h" @@ -114,6 +115,11 @@ "All of the above and take the minimum of measurements")), cl::init(exegesis::InstructionBenchmark::Duplicate)); +static cl::opt BenchmarkMeasurementsPrintProgress( + "measurements-print-progress", + cl::desc("Produce progress indicator when performing measurements"), + cl::cat(BenchmarkOptions), cl::init(false)); + static cl::opt BenchmarkSkipMeasurements( "skip-measurements", cl::desc("do everything except actually performing the measurements"), @@ -395,7 +401,11 @@ if (BenchmarkFile.empty()) BenchmarkFile = "-"; + std::optional Meter; + if (BenchmarkMeasurementsPrintProgress) + Meter.emplace(Configurations.size()); for (const BenchmarkCode &Conf : Configurations) { + ProgressMeter::ProgressMeterStep MeterStep(Meter ? &*Meter : nullptr); InstructionBenchmark Result = ExitOnErr(Runner->runConfiguration( Conf, NumRepetitions, LoopBodySize, Repetitors, DumpObjectToDisk)); ExitOnFileError(BenchmarkFile, Result.writeYaml(State, BenchmarkFile));