123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- //===-- 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 <cassert>
- #include <chrono>
- #include <cmath>
- #include <optional>
- #include <type_traits>
- namespace llvm {
- namespace exegesis {
- /// Represents `\sum_{i=1..accumulated}{step_i} / accumulated`,
- /// where `step_i` is the value passed to the `i`-th call to `step()`,
- /// and `accumulated` is the total number of calls to `step()`.
- template <typename NumTy, typename DenTy = int> class SimpleMovingAverage {
- NumTy Accumulated = NumTy(0);
- DenTy Steps = 0;
- public:
- SimpleMovingAverage() = default;
- SimpleMovingAverage(const SimpleMovingAverage &) = delete;
- SimpleMovingAverage(SimpleMovingAverage &&) = delete;
- SimpleMovingAverage &operator=(const SimpleMovingAverage &) = delete;
- SimpleMovingAverage &operator=(SimpleMovingAverage &&) = delete;
- inline void step(NumTy Quantity) {
- Accumulated += Quantity;
- ++Steps;
- }
- inline NumTy getAccumulated() const { return Accumulated; }
- inline DenTy getNumSteps() const { return Steps; }
- template <typename AvgTy = NumTy>
- inline std::optional<AvgTy> getAverage() const {
- if (Steps == 0)
- return std::nullopt;
- return AvgTy(Accumulated) / Steps;
- }
- };
- template <typename ClockTypeTy = std::chrono::steady_clock,
- typename = std::enable_if_t<ClockTypeTy::is_steady>>
- class ProgressMeter {
- public:
- using ClockType = ClockTypeTy;
- using TimePointType = std::chrono::time_point<ClockType>;
- using DurationType = std::chrono::duration<typename ClockType::rep,
- typename ClockType::period>;
- using CompetionPercentage = int;
- using Sec = std::chrono::duration<double, std::chrono::seconds::period>;
- private:
- raw_ostream &Out;
- const int NumStepsTotal;
- SimpleMovingAverage<DurationType> ElapsedTotal;
- public:
- friend class ProgressMeterStep;
- class ProgressMeterStep {
- ProgressMeter *P;
- const TimePointType Begin;
- public:
- inline ProgressMeterStep(ProgressMeter *P_)
- : P(P_), Begin(P ? ProgressMeter<ClockType>::ClockType::now()
- : TimePointType()) {}
- inline ~ProgressMeterStep() {
- if (!P)
- return;
- const TimePointType End = ProgressMeter<ClockType>::ClockType::now();
- P->step(End - Begin);
- }
- ProgressMeterStep(const ProgressMeterStep &) = delete;
- ProgressMeterStep(ProgressMeterStep &&) = delete;
- ProgressMeterStep &operator=(const ProgressMeterStep &) = delete;
- ProgressMeterStep &operator=(ProgressMeterStep &&) = delete;
- };
- ProgressMeter(int NumStepsTotal_, raw_ostream &out_ = llvm::errs())
- : Out(out_), NumStepsTotal(NumStepsTotal_) {
- assert(NumStepsTotal > 0 && "No steps are planned?");
- }
- ProgressMeter(const ProgressMeter &) = delete;
- ProgressMeter(ProgressMeter &&) = delete;
- ProgressMeter &operator=(const ProgressMeter &) = delete;
- ProgressMeter &operator=(ProgressMeter &&) = delete;
- private:
- void step(DurationType Elapsed) {
- assert((ElapsedTotal.getNumSteps() < NumStepsTotal) && "Step overflow!");
- assert(Elapsed.count() >= 0 && "Negative time drift detected.");
- auto [OldProgress, OldEta] = eta();
- ElapsedTotal.step(Elapsed);
- auto [NewProgress, NewEta] = eta();
- if (NewProgress < OldProgress + 1)
- return;
- Out << format("Processing... %*d%%", 3, NewProgress);
- if (NewEta) {
- int SecondsTotal = std::ceil(NewEta->count());
- int Seconds = SecondsTotal % 60;
- int MinutesTotal = SecondsTotal / 60;
- Out << format(", ETA %02d:%02d", MinutesTotal, Seconds);
- }
- Out << "\n";
- Out.flush();
- }
- inline std::pair<CompetionPercentage, std::optional<Sec>> eta() const {
- CompetionPercentage Progress =
- (100 * ElapsedTotal.getNumSteps()) / NumStepsTotal;
- std::optional<Sec> ETA;
- if (std::optional<Sec> AverageStepDuration =
- ElapsedTotal.template getAverage<Sec>())
- ETA = (NumStepsTotal - ElapsedTotal.getNumSteps()) * *AverageStepDuration;
- return {Progress, ETA};
- }
- };
- } // namespace exegesis
- } // namespace llvm
- #endif
|