TimeNormalizer
Vladimir Bauer
7 years ago
| 8 | 8 | "github.com/vbauerster/mpb/internal" |
| 9 | 9 | ) |
| 10 | 10 | |
| 11 | type TimeNormalizer func(time.Duration) time.Duration | |
| 12 | ||
| 11 | 13 | // EwmaETA exponential-weighted-moving-average based ETA decorator. |
| 12 | 14 | // |
| 13 | 15 | // `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS] |
| 16 | 18 | // |
| 17 | 19 | // `wcc` optional WC config |
| 18 | 20 | func EwmaETA(style int, age float64, wcc ...WC) Decorator { |
| 19 | return MovingAverageETA(style, ewma.NewMovingAverage(age), wcc...) | |
| 21 | return MovingAverageETA(style, ewma.NewMovingAverage(age), NopTimeNormalizer(), wcc...) | |
| 20 | 22 | } |
| 21 | 23 | |
| 22 | 24 | // MovingAverageETA decorator relies on MovingAverage implementation to calculate its average. |
| 26 | 28 | // `average` MovingAverage implementation |
| 27 | 29 | // |
| 28 | 30 | // `wcc` optional WC config |
| 29 | func MovingAverageETA(style int, average MovingAverage, wcc ...WC) Decorator { | |
| 31 | func MovingAverageETA(style int, average MovingAverage, normalizer TimeNormalizer, wcc ...WC) Decorator { | |
| 30 | 32 | var wc WC |
| 31 | 33 | for _, widthConf := range wcc { |
| 32 | 34 | wc = widthConf |
| 33 | 35 | } |
| 34 | 36 | wc.Init() |
| 35 | 37 | d := &movingAverageETA{ |
| 36 | WC: wc, | |
| 37 | style: style, | |
| 38 | average: average, | |
| 38 | WC: wc, | |
| 39 | style: style, | |
| 40 | average: average, | |
| 41 | normalizer: normalizer, | |
| 39 | 42 | } |
| 40 | 43 | return d |
| 41 | 44 | } |
| 45 | 48 | style int |
| 46 | 49 | average ewma.MovingAverage |
| 47 | 50 | completeMsg *string |
| 51 | normalizer TimeNormalizer | |
| 48 | 52 | } |
| 49 | 53 | |
| 50 | 54 | func (d *movingAverageETA) Decor(st *Statistics) string { |
| 56 | 60 | if math.IsInf(v, 0) || math.IsNaN(v) { |
| 57 | 61 | v = 0 |
| 58 | 62 | } |
| 59 | remaining := time.Duration((st.Total - st.Current) * int64(v)) | |
| 63 | remaining := d.normalizer(time.Duration((st.Total - st.Current) * int64(v))) | |
| 60 | 64 | hours := int64((remaining / time.Hour) % 60) |
| 61 | 65 | minutes := int64((remaining / time.Minute) % 60) |
| 62 | 66 | seconds := int64((remaining / time.Second) % 60) |
| 148 | 152 | func (d *averageETA) OnCompleteMessage(msg string) { |
| 149 | 153 | d.completeMsg = &msg |
| 150 | 154 | } |
| 155 | ||
| 156 | func MaxTolerateTimeNormalizer(maxTolerate time.Duration) TimeNormalizer { | |
| 157 | var normalized time.Duration | |
| 158 | var lastCall time.Time | |
| 159 | return func(remaining time.Duration) time.Duration { | |
| 160 | if diff := normalized - remaining; diff <= 0 || diff >= maxTolerate || remaining <= maxTolerate { | |
| 161 | normalized = remaining | |
| 162 | lastCall = time.Now() | |
| 163 | return remaining | |
| 164 | } | |
| 165 | normalized -= time.Since(lastCall) | |
| 166 | lastCall = time.Now() | |
| 167 | return normalized | |
| 168 | } | |
| 169 | } | |
| 170 | ||
| 171 | func FixedIntervalTimeNormalizer(updInterval int) TimeNormalizer { | |
| 172 | var normalized time.Duration | |
| 173 | var lastCall time.Time | |
| 174 | var count int | |
| 175 | return func(remaining time.Duration) time.Duration { | |
| 176 | if count == 0 || remaining <= time.Duration(15*time.Second) { | |
| 177 | count = updInterval | |
| 178 | normalized = remaining | |
| 179 | lastCall = time.Now() | |
| 180 | return remaining | |
| 181 | } | |
| 182 | count-- | |
| 183 | normalized -= time.Since(lastCall) | |
| 184 | lastCall = time.Now() | |
| 185 | if normalized > 0 { | |
| 186 | return normalized | |
| 187 | } | |
| 188 | return remaining | |
| 189 | } | |
| 190 | } | |
| 191 | ||
| 192 | func NopTimeNormalizer() TimeNormalizer { | |
| 193 | return func(remaining time.Duration) time.Duration { | |
| 194 | return remaining | |
| 195 | } | |
| 196 | } | |