brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.5 KiB · c09b9e9 Raw
146 lines · c
1//===-- ProgressMeter.h -----------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_TOOLS_LLVM_EXEGESIS_PROGRESSMETER_H10#define LLVM_TOOLS_LLVM_EXEGESIS_PROGRESSMETER_H11 12#include "llvm/Support/Format.h"13#include "llvm/Support/raw_ostream.h"14#include <cassert>15#include <chrono>16#include <cmath>17#include <optional>18#include <type_traits>19 20namespace llvm {21namespace exegesis {22 23/// Represents `\sum_{i=1..accumulated}{step_i} / accumulated`,24/// where `step_i` is the value passed to the `i`-th call to `step()`,25/// and `accumulated` is the total number of calls to `step()`.26template <typename NumTy, typename DenTy = int> class SimpleMovingAverage {27  NumTy Accumulated = NumTy(0);28  DenTy Steps = 0;29 30public:31  SimpleMovingAverage() = default;32 33  SimpleMovingAverage(const SimpleMovingAverage &) = delete;34  SimpleMovingAverage(SimpleMovingAverage &&) = delete;35  SimpleMovingAverage &operator=(const SimpleMovingAverage &) = delete;36  SimpleMovingAverage &operator=(SimpleMovingAverage &&) = delete;37 38  inline void step(NumTy Quantity) {39    Accumulated += Quantity;40    ++Steps;41  }42 43  inline NumTy getAccumulated() const { return Accumulated; }44 45  inline DenTy getNumSteps() const { return Steps; }46 47  template <typename AvgTy = NumTy>48  inline std::optional<AvgTy> getAverage() const {49    if (Steps == 0)50      return std::nullopt;51    return AvgTy(Accumulated) / Steps;52  }53};54 55template <typename ClockTypeTy = std::chrono::steady_clock,56          typename = std::enable_if_t<ClockTypeTy::is_steady>>57class ProgressMeter {58public:59  using ClockType = ClockTypeTy;60  using TimePointType = std::chrono::time_point<ClockType>;61  using DurationType = std::chrono::duration<typename ClockType::rep,62                                             typename ClockType::period>;63  using CompetionPercentage = int;64  using Sec = std::chrono::duration<double, std::chrono::seconds::period>;65 66private:67  raw_ostream &Out;68  const int NumStepsTotal;69  SimpleMovingAverage<DurationType> ElapsedTotal;70 71public:72  friend class ProgressMeterStep;73  class ProgressMeterStep {74    ProgressMeter *P;75    const TimePointType Begin;76 77  public:78    inline ProgressMeterStep(ProgressMeter *P_)79        : P(P_), Begin(P ? ProgressMeter<ClockType>::ClockType::now()80                         : TimePointType()) {}81 82    inline ~ProgressMeterStep() {83      if (!P)84        return;85      const TimePointType End = ProgressMeter<ClockType>::ClockType::now();86      P->step(End - Begin);87    }88 89    ProgressMeterStep(const ProgressMeterStep &) = delete;90    ProgressMeterStep(ProgressMeterStep &&) = delete;91    ProgressMeterStep &operator=(const ProgressMeterStep &) = delete;92    ProgressMeterStep &operator=(ProgressMeterStep &&) = delete;93  };94 95  ProgressMeter(int NumStepsTotal_, raw_ostream &out_ = errs())96      : Out(out_), NumStepsTotal(NumStepsTotal_) {97    assert(NumStepsTotal > 0 && "No steps are planned?");98  }99 100  ProgressMeter(const ProgressMeter &) = delete;101  ProgressMeter(ProgressMeter &&) = delete;102  ProgressMeter &operator=(const ProgressMeter &) = delete;103  ProgressMeter &operator=(ProgressMeter &&) = delete;104 105private:106  void step(DurationType Elapsed) {107    assert((ElapsedTotal.getNumSteps() < NumStepsTotal) && "Step overflow!");108    assert(Elapsed.count() >= 0 && "Negative time drift detected.");109 110    auto [OldProgress, OldEta] = eta();111    ElapsedTotal.step(Elapsed);112    auto [NewProgress, NewEta] = eta();113 114    if (NewProgress < OldProgress + 1)115      return;116 117    Out << format("Processing... %*d%%", 3, NewProgress);118    if (NewEta) {119      int SecondsTotal = std::ceil(NewEta->count());120      int Seconds = SecondsTotal % 60;121      int MinutesTotal = SecondsTotal / 60;122 123      Out << format(", ETA %02d:%02d", MinutesTotal, Seconds);124    }125    Out << "\n";126    Out.flush();127  }128 129  inline std::pair<CompetionPercentage, std::optional<Sec>> eta() const {130    CompetionPercentage Progress =131        (100 * ElapsedTotal.getNumSteps()) / NumStepsTotal;132 133    std::optional<Sec> ETA;134    if (std::optional<Sec> AverageStepDuration =135            ElapsedTotal.template getAverage<Sec>())136      ETA = (NumStepsTotal - ElapsedTotal.getNumSteps()) * *AverageStepDuration;137 138    return {Progress, ETA};139  }140};141 142} // namespace exegesis143} // namespace llvm144 145#endif146