EwmaDecorator, AverageDecorator interface
Vladimir Bauer
6 years ago
| 84 | 84 | } |
| 85 | 85 | |
| 86 | 86 | // EwmaDecorator interface. |
| 87 | // EWMA based decorators must to implement this one. | |
| 87 | // EWMA based decorators should implement this one. | |
| 88 | 88 | type EwmaDecorator interface { |
| 89 | IterationUpdate(int64, time.Duration) | |
| 89 | EwmaUpdate(int64, time.Duration) | |
| 90 | 90 | } |
| 91 | 91 | |
| 92 | 92 | // AverageDecorator interface. |
| 93 | 93 | // Average decorators should implement this interface to provide start |
| 94 | 94 | // time adjustment facility, for resume-able tasks. |
| 95 | 95 | type AverageDecorator interface { |
| 96 | Adjust(time.Time) | |
| 96 | AverageAdjust(time.Time) | |
| 97 | 97 | } |
| 98 | 98 | |
| 99 | 99 | // ShutdownListener interface. |
| 26 | 26 | // work duration as second argument, in order for this decorator to |
| 27 | 27 | // work correctly. This decorator is a wrapper of MovingAverageETA. |
| 28 | 28 | func EwmaETA(style TimeStyle, age float64, wcc ...WC) Decorator { |
| 29 | var average MovingAverage | |
| 29 | var average ewma.MovingAverage | |
| 30 | 30 | if age == 0 { |
| 31 | 31 | average = ewma.NewMovingAverage() |
| 32 | 32 | } else { |
| 33 | 33 | average = ewma.NewMovingAverage(age) |
| 34 | 34 | } |
| 35 | average = &ThreadSafeMovingAverage{MovingAverage: average} | |
| 35 | 36 | return MovingAverageETA(style, average, nil, wcc...) |
| 36 | 37 | } |
| 37 | 38 | |
| 45 | 46 | // |
| 46 | 47 | // `wcc` optional WC config |
| 47 | 48 | // |
| 48 | func MovingAverageETA(style TimeStyle, average MovingAverage, normalizer TimeNormalizer, wcc ...WC) Decorator { | |
| 49 | func MovingAverageETA(style TimeStyle, average ewma.MovingAverage, normalizer TimeNormalizer, wcc ...WC) Decorator { | |
| 49 | 50 | d := &movingAverageETA{ |
| 50 | 51 | WC: initWC(wcc...), |
| 51 | 52 | average: average, |
| 71 | 72 | return d.FormatMsg(d.producer(remaining)) |
| 72 | 73 | } |
| 73 | 74 | |
| 74 | func (d *movingAverageETA) NextAmount(n int64, wdd ...time.Duration) { | |
| 75 | var workDuration time.Duration | |
| 76 | for _, wd := range wdd { | |
| 77 | workDuration = wd | |
| 78 | } | |
| 79 | durPerItem := float64(workDuration) / float64(n) | |
| 75 | func (d *movingAverageETA) EwmaUpdate(n int64, dur time.Duration) { | |
| 76 | durPerItem := float64(dur) / float64(n) | |
| 80 | 77 | if math.IsInf(durPerItem, 0) || math.IsNaN(durPerItem) { |
| 81 | 78 | return |
| 82 | 79 | } |
| 1 | 1 | |
| 2 | 2 | import ( |
| 3 | 3 | "sort" |
| 4 | "sync" | |
| 4 | 5 | |
| 5 | 6 | "github.com/VividCortex/ewma" |
| 6 | 7 | ) |
| 7 | 8 | |
| 8 | // MovingAverage is the interface that computes a moving average over | |
| 9 | // a time-series stream of numbers. The average may be over a window | |
| 10 | // or exponentially decaying. | |
| 11 | type MovingAverage = ewma.MovingAverage | |
| 9 | // ThreadSafeMovingAverage is a thread safe wrapper for ewma.MovingAverage. | |
| 10 | type ThreadSafeMovingAverage struct { | |
| 11 | ewma.MovingAverage | |
| 12 | mu sync.Mutex | |
| 13 | } | |
| 14 | ||
| 15 | func (s *ThreadSafeMovingAverage) Add(value float64) { | |
| 16 | s.mu.Lock() | |
| 17 | s.MovingAverage.Add(value) | |
| 18 | s.mu.Unlock() | |
| 19 | } | |
| 20 | ||
| 21 | func (s *ThreadSafeMovingAverage) Value() float64 { | |
| 22 | s.mu.Lock() | |
| 23 | defer s.mu.Unlock() | |
| 24 | return s.MovingAverage.Value() | |
| 25 | } | |
| 26 | ||
| 27 | func (s *ThreadSafeMovingAverage) Set(value float64) { | |
| 28 | s.mu.Lock() | |
| 29 | s.MovingAverage.Set(value) | |
| 30 | s.mu.Unlock() | |
| 31 | } | |
| 12 | 32 | |
| 13 | 33 | type medianWindow [3]float64 |
| 14 | 34 | |
| 34 | 54 | } |
| 35 | 55 | |
| 36 | 56 | // NewMedian is fixed last 3 samples median MovingAverage. |
| 37 | func NewMedian() MovingAverage { | |
| 38 | return new(medianWindow) | |
| 57 | func NewMedian() ewma.MovingAverage { | |
| 58 | return &ThreadSafeMovingAverage{MovingAverage: new(medianWindow)} | |
| 39 | 59 | } |
| 31 | 31 | // work duration as second argument, in order for this decorator to |
| 32 | 32 | // work correctly. This decorator is a wrapper of MovingAverageSpeed. |
| 33 | 33 | func EwmaSpeed(unit int, format string, age float64, wcc ...WC) Decorator { |
| 34 | var average MovingAverage | |
| 34 | var average ewma.MovingAverage | |
| 35 | 35 | if age == 0 { |
| 36 | 36 | average = ewma.NewMovingAverage() |
| 37 | 37 | } else { |
| 38 | 38 | average = ewma.NewMovingAverage(age) |
| 39 | 39 | } |
| 40 | average = &ThreadSafeMovingAverage{MovingAverage: average} | |
| 40 | 41 | return MovingAverageSpeed(unit, format, average, wcc...) |
| 41 | 42 | } |
| 42 | 43 | |
| 58 | 59 | // unit=UnitKB, format="%.1f" output: "1.0MB/s" |
| 59 | 60 | // unit=UnitKB, format="% .1f" output: "1.0 MB/s" |
| 60 | 61 | // |
| 61 | func MovingAverageSpeed(unit int, format string, average MovingAverage, wcc ...WC) Decorator { | |
| 62 | func MovingAverageSpeed(unit int, format string, average ewma.MovingAverage, wcc ...WC) Decorator { | |
| 62 | 63 | if format == "" { |
| 63 | 64 | format = "%.0f" |
| 64 | 65 | } |
| 88 | 89 | return d.FormatMsg(d.msg) |
| 89 | 90 | } |
| 90 | 91 | |
| 91 | func (d *movingAverageSpeed) NextAmount(n int64, wdd ...time.Duration) { | |
| 92 | var workDuration time.Duration | |
| 93 | for _, wd := range wdd { | |
| 94 | workDuration = wd | |
| 95 | } | |
| 96 | durPerByte := float64(workDuration) / float64(n) | |
| 92 | func (d *movingAverageSpeed) EwmaUpdate(n int64, dur time.Duration) { | |
| 93 | durPerByte := float64(dur) / float64(n) | |
| 97 | 94 | if math.IsInf(durPerByte, 0) || math.IsNaN(durPerByte) { |
| 98 | 95 | return |
| 99 | 96 | } |