Codebase list golang-github-vbauerster-mpb / e8de980
Refactoring: ewma speed decorator Vladimir Bauer 8 years ago
12 changed file(s) with 498 addition(s) and 412 deletion(s). Raw diff Collapse all Expand all
5757 removeOnComplete bool
5858 barClearOnComplete bool
5959 completeFlushed bool
60 startTime time.Time
61 timeElapsed time.Duration
6260 aDecorators []decor.Decorator
6361 pDecorators []decor.Decorator
6462 amountReceivers []decor.AmountReceiver
139137 }
140138
141139 // ProxyReader wrapper for io operations, like io.Copy
142 func (b *Bar) ProxyReader(r io.Reader, startBlock ...chan<- time.Time) *Reader {
140 //
141 // `r` io.Reader to be wrapped
142 //
143 // `sbChannels` optional start block channels
144 func (b *Bar) ProxyReader(r io.Reader, sbChannels ...chan<- time.Time) *Reader {
143145 proxyReader := &Reader{
144 Reader: r,
145 bar: b,
146 }
147 if len(startBlock) > 0 {
148 proxyReader.startBlockCh = startBlock[0]
146 Reader: r,
147 bar: b,
148 sbChannels: sbChannels,
149149 }
150150 return proxyReader
151151 }
250250 for _, ar := range s.amountReceivers {
251251 ar.NextAmount(n)
252252 }
253 s.timeElapsed = time.Since(s.startTime)
254253 }:
255254 case <-b.done:
256255 }
265264
266265 func (b *Bar) serve(wg *sync.WaitGroup, s *bState, cancel <-chan struct{}) {
267266 defer wg.Done()
268 s.startTime = time.Now()
269267 for {
270268 select {
271269 case op := <-b.operateState:
414412
415413 func newStatistics(s *bState) *decor.Statistics {
416414 return &decor.Statistics{
417 ID: s.id,
418 Completed: s.completeFlushed,
419 Total: s.total,
420 Current: s.current,
421 StartTime: s.startTime,
422 TimeElapsed: s.timeElapsed,
415 ID: s.id,
416 Completed: s.completeFlushed,
417 Total: s.total,
418 Current: s.current,
423419 }
424420 }
425421
134134
135135 io.WriteString(st, res)
136136 }
137
138 // CountersNoUnit returns raw counters decorator
139 //
140 // `pairFormat` printf compatible verbs for current and total, like "%f" or "%d"
141 //
142 // `wcc` optional WC config
143 func CountersNoUnit(pairFormat string, wcc ...WC) Decorator {
144 return counters(0, pairFormat, wcc...)
145 }
146
147 // CountersKibiByte returns human friendly byte counters decorator, where counters unit is multiple by 1024.
148 //
149 // `pairFormat` printf compatible verbs for current and total, like "%f" or "%d"
150 //
151 // `wcc` optional WC config
152 //
153 // pairFormat example:
154 //
155 // "%.1f / %.1f" = "1.0MiB / 12.0MiB" or "% .1f / % .1f" = "1.0 MiB / 12.0 MiB"
156 func CountersKibiByte(pairFormat string, wcc ...WC) Decorator {
157 return counters(unitKiB, pairFormat, wcc...)
158 }
159
160 // CountersKiloByte returns human friendly byte counters decorator, where counters unit is multiple by 1000.
161 //
162 // `pairFormat` printf compatible verbs for current and total, like "%f" or "%d"
163 //
164 // `wcc` optional WC config
165 //
166 // pairFormat example:
167 //
168 // "%.1f / %.1f" = "1.0MB / 12.0MB" or "% .1f / % .1f" = "1.0 MB / 12.0 MB"
169 func CountersKiloByte(pairFormat string, wcc ...WC) Decorator {
170 return counters(unitKB, pairFormat, wcc...)
171 }
172
173 func counters(unit int, pairFormat string, wcc ...WC) Decorator {
174 var wc WC
175 for _, widthConf := range wcc {
176 wc = widthConf
177 }
178 wc.BuildFormat()
179 return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
180 var str string
181 switch unit {
182 case unitKiB:
183 str = fmt.Sprintf(pairFormat, CounterKiB(s.Current), CounterKiB(s.Total))
184 case unitKB:
185 str = fmt.Sprintf(pairFormat, CounterKB(s.Current), CounterKB(s.Total))
186 default:
187 str = fmt.Sprintf(pairFormat, s.Current, s.Total)
188 }
189 return wc.FormatMsg(str, widthAccumulator, widthDistributor)
190 })
191 }
0 package decor
1
2 import (
3 "fmt"
4 "unicode/utf8"
5 )
6
7 const (
8 // DidentRight bit specifies identation direction.
9 // |foo |b | With DidentRight
10 // | foo| b| Without DidentRight
11 DidentRight = 1 << iota
12
13 // DextraSpace bit adds extra space, makes sense with DSyncWidth only.
14 // When DidentRight bit set, the space will be added to the right,
15 // otherwise to the left.
16 DextraSpace
17
18 // DSyncWidth bit enables same column width synchronization.
19 // Effective with multiple bars only.
20 DSyncWidth
21
22 // DSyncWidthR is shortcut for DSyncWidth|DidentRight
23 DSyncWidthR = DSyncWidth | DidentRight
24
25 // DSyncSpace is shortcut for DSyncWidth|DextraSpace
26 DSyncSpace = DSyncWidth | DextraSpace
27
28 // DSyncSpaceR is shortcut for DSyncWidth|DextraSpace|DidentRight
29 DSyncSpaceR = DSyncWidth | DextraSpace | DidentRight
30 )
31
32 const (
33 ET_STYLE_GO = iota
34 ET_STYLE_HHMMSS
35 ET_STYLE_HHMM
36 ET_STYLE_MMSS
37 )
38
39 // Statistics is a struct, which gets passed to a Decorator.
40 type Statistics struct {
41 ID int
42 Completed bool
43 Total int64
44 Current int64
45 }
46
47 // Decorator is an interface with one method:
48 //
49 // Decor(st *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string
50 //
51 // All decorators in this package implement this interface.
52 type Decorator interface {
53 Decor(*Statistics, chan<- int, <-chan int) string
54 }
55
56 // OnCompleteMessenger is an interface with one method:
57 //
58 // OnCompleteMessage(message string, wc ...WC)
59 //
60 // Decorators implementing this interface suppose to return provided string on complete event.
61 type OnCompleteMessenger interface {
62 OnCompleteMessage(string, ...WC)
63 }
64
65 type AmountReceiver interface {
66 NextAmount(int)
67 }
68
69 type ShutdownListener interface {
70 Shutdown()
71 }
72
73 // DecoratorFunc is an adapter for Decorator interface
74 type DecoratorFunc func(*Statistics, chan<- int, <-chan int) string
75
76 func (f DecoratorFunc) Decor(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
77 return f(s, widthAccumulator, widthDistributor)
78 }
79
80 // Global convenience shortcuts
81 var (
82 WCSyncWidth = WC{C: DSyncWidth}
83 WCSyncWidthR = WC{C: DSyncWidthR}
84 WCSyncSpace = WC{C: DSyncSpace}
85 WCSyncSpaceR = WC{C: DSyncSpaceR}
86 )
87
88 // WC is a struct with two public fields W and C, both of int type.
89 // W represents width and C represents bit set of width related config.
90 type WC struct {
91 W int
92 C int
93 format string
94 }
95
96 // FormatMsg formats final message according to WC.W and WC.C.
97 // Should be called by any Decorator implementation.
98 func (wc WC) FormatMsg(msg string, widthAccumulator chan<- int, widthDistributor <-chan int) string {
99 if (wc.C & DSyncWidth) != 0 {
100 widthAccumulator <- utf8.RuneCountInString(msg)
101 max := <-widthDistributor
102 if max == 0 {
103 max = wc.W
104 }
105 if (wc.C & DextraSpace) != 0 {
106 max++
107 }
108 return fmt.Sprintf(fmt.Sprintf(wc.format, max), msg)
109 }
110 return fmt.Sprintf(fmt.Sprintf(wc.format, wc.W), msg)
111 }
112
113 // BuildFormat builds initial format according to WC.C
114 func (wc *WC) BuildFormat() {
115 wc.format = "%%"
116 if (wc.C & DidentRight) != 0 {
117 wc.format += "-"
118 }
119 wc.format += "%ds"
120 }
121
122 // OnComplete returns decorator, which wraps provided decorator, with sole
123 // purpose to display provided message on complete event.
124 //
125 // `decorator` Decorator to wrap
126 //
127 // `message` message to display on complete event
128 //
129 // `wcc` optional WC config
130 func OnComplete(decorator Decorator, message string, wcc ...WC) Decorator {
131 if cm, ok := decorator.(OnCompleteMessenger); ok {
132 cm.OnCompleteMessage(message, wcc...)
133 return decorator
134 }
135 msgDecorator := Name(message, wcc...)
136 return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
137 if s.Completed {
138 return msgDecorator.Decor(s, widthAccumulator, widthDistributor)
139 }
140 return decorator.Decor(s, widthAccumulator, widthDistributor)
141 })
142 }
+0
-346
decor/decorators.go less more
0 package decor
1
2 import (
3 "fmt"
4 "math"
5 "time"
6 "unicode/utf8"
7 )
8
9 const (
10 // DidentRight bit specifies identation direction.
11 // |foo |b | With DidentRight
12 // | foo| b| Without DidentRight
13 DidentRight = 1 << iota
14
15 // DextraSpace bit adds extra space, makes sense with DSyncWidth only.
16 // When DidentRight bit set, the space will be added to the right,
17 // otherwise to the left.
18 DextraSpace
19
20 // DSyncWidth bit enables same column width synchronization.
21 // Effective with multiple bars only.
22 DSyncWidth
23
24 // DSyncWidthR is shortcut for DSyncWidth|DidentRight
25 DSyncWidthR = DSyncWidth | DidentRight
26
27 // DSyncSpace is shortcut for DSyncWidth|DextraSpace
28 DSyncSpace = DSyncWidth | DextraSpace
29
30 // DSyncSpaceR is shortcut for DSyncWidth|DextraSpace|DidentRight
31 DSyncSpaceR = DSyncWidth | DextraSpace | DidentRight
32 )
33
34 const (
35 ET_STYLE_GO = iota
36 ET_STYLE_HHMMSS
37 ET_STYLE_HHMM
38 ET_STYLE_MMSS
39 )
40
41 // Statistics is a struct, which gets passed to a Decorator.
42 type Statistics struct {
43 ID int
44 Completed bool
45 Total int64
46 Current int64
47 StartTime time.Time
48 TimeElapsed time.Duration
49 }
50
51 // Decorator is an interface with one method:
52 //
53 // Decor(st *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string
54 //
55 // All decorators in this package implement this interface.
56 type Decorator interface {
57 Decor(*Statistics, chan<- int, <-chan int) string
58 }
59
60 // OnCompleteMessenger is an interface with one method:
61 //
62 // OnCompleteMessage(message string, wc ...WC)
63 //
64 // Decorators implementing this interface suppose to return provided string on complete event.
65 type OnCompleteMessenger interface {
66 OnCompleteMessage(string, ...WC)
67 }
68
69 type AmountReceiver interface {
70 NextAmount(int)
71 }
72
73 type ShutdownListener interface {
74 Shutdown()
75 }
76
77 // DecoratorFunc is an adapter for Decorator interface
78 type DecoratorFunc func(*Statistics, chan<- int, <-chan int) string
79
80 func (f DecoratorFunc) Decor(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
81 return f(s, widthAccumulator, widthDistributor)
82 }
83
84 // WC is a struct with two public fields W and C, both of int type.
85 // W represents width and C represents bit set of width related config.
86 type WC struct {
87 W int
88 C int
89 format string
90 }
91
92 // FormatMsg formats final message according to WC.W and WC.C.
93 // Should be called by any Decorator implementation.
94 func (wc WC) FormatMsg(msg string, widthAccumulator chan<- int, widthDistributor <-chan int) string {
95 if (wc.C & DSyncWidth) != 0 {
96 widthAccumulator <- utf8.RuneCountInString(msg)
97 max := <-widthDistributor
98 if max == 0 {
99 max = wc.W
100 }
101 if (wc.C & DextraSpace) != 0 {
102 max++
103 }
104 return fmt.Sprintf(fmt.Sprintf(wc.format, max), msg)
105 }
106 return fmt.Sprintf(fmt.Sprintf(wc.format, wc.W), msg)
107 }
108
109 // BuildFormat builds initial format according to WC.C
110 func (wc *WC) BuildFormat() {
111 wc.format = "%%"
112 if (wc.C & DidentRight) != 0 {
113 wc.format += "-"
114 }
115 wc.format += "%ds"
116 }
117
118 // Global convenience shortcuts
119 var (
120 WCSyncWidth = WC{C: DSyncWidth}
121 WCSyncWidthR = WC{C: DSyncWidthR}
122 WCSyncSpace = WC{C: DSyncSpace}
123 WCSyncSpaceR = WC{C: DSyncSpaceR}
124 )
125
126 // OnComplete returns decorator, which wraps provided decorator, with sole
127 // purpose to display provided message on complete event.
128 //
129 // `decorator` Decorator to wrap
130 //
131 // `message` message to display on complete event
132 //
133 // `wc` optional WC config
134 func OnComplete(decorator Decorator, message string, wc ...WC) Decorator {
135 if cm, ok := decorator.(OnCompleteMessenger); ok {
136 cm.OnCompleteMessage(message, wc...)
137 return decorator
138 }
139 msgDecorator := Name(message, wc...)
140 return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
141 if s.Completed {
142 return msgDecorator.Decor(s, widthAccumulator, widthDistributor)
143 }
144 return decorator.Decor(s, widthAccumulator, widthDistributor)
145 })
146 }
147
148 // StaticName returns name decorator.
149 //
150 // `name` string to display
151 //
152 // `wc` optional WC config
153 func StaticName(name string, wc ...WC) Decorator {
154 return Name(name, wc...)
155 }
156
157 // Name returns name decorator.
158 //
159 // `name` string to display
160 //
161 // `wc` optional WC config
162 func Name(name string, wc ...WC) Decorator {
163 var wc0 WC
164 if len(wc) > 0 {
165 wc0 = wc[0]
166 }
167 wc0.BuildFormat()
168 return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
169 return wc0.FormatMsg(name, widthAccumulator, widthDistributor)
170 })
171 }
172
173 // CountersNoUnit returns raw counters decorator
174 //
175 // `pairFormat` printf compatible verbs for current and total, like "%f" or "%d"
176 //
177 // `wc` optional WC config
178 func CountersNoUnit(pairFormat string, wc ...WC) Decorator {
179 return counters(pairFormat, 0, wc...)
180 }
181
182 // CountersKibiByte returns human friendly byte counters decorator, where counters unit is multiple by 1024.
183 //
184 // `pairFormat` printf compatible verbs for current and total, like "%f" or "%d"
185 //
186 // `wc` optional WC config
187 //
188 // pairFormat example:
189 //
190 // "%.1f / %.1f" = "1.0MiB / 12.0MiB" or "% .1f / % .1f" = "1.0 MiB / 12.0 MiB"
191 func CountersKibiByte(pairFormat string, wc ...WC) Decorator {
192 return counters(pairFormat, unitKiB, wc...)
193 }
194
195 // CountersKiloByte returns human friendly byte counters decorator, where counters unit is multiple by 1000.
196 //
197 // `pairFormat` printf compatible verbs for current and total, like "%f" or "%d"
198 //
199 // `wc` optional WC config
200 //
201 // pairFormat example:
202 //
203 // "%.1f / %.1f" = "1.0MB / 12.0MB" or "% .1f / % .1f" = "1.0 MB / 12.0 MB"
204 func CountersKiloByte(pairFormat string, wc ...WC) Decorator {
205 return counters(pairFormat, unitKB, wc...)
206 }
207
208 func counters(pairFormat string, unit int, wc ...WC) Decorator {
209 var wc0 WC
210 if len(wc) > 0 {
211 wc0 = wc[0]
212 }
213 wc0.BuildFormat()
214 return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
215 var str string
216 switch unit {
217 case unitKiB:
218 str = fmt.Sprintf(pairFormat, CounterKiB(s.Current), CounterKiB(s.Total))
219 case unitKB:
220 str = fmt.Sprintf(pairFormat, CounterKB(s.Current), CounterKB(s.Total))
221 default:
222 str = fmt.Sprintf(pairFormat, s.Current, s.Total)
223 }
224 return wc0.FormatMsg(str, widthAccumulator, widthDistributor)
225 })
226 }
227
228 // Elapsed returns elapsed time decorator.
229 //
230 // `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
231 //
232 // `wc` optional WC config
233 func Elapsed(style int, wc ...WC) Decorator {
234 var wc0 WC
235 if len(wc) > 0 {
236 wc0 = wc[0]
237 }
238 wc0.BuildFormat()
239 return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
240 var str string
241 hours := int64((s.TimeElapsed / time.Hour) % 60)
242 minutes := int64((s.TimeElapsed / time.Minute) % 60)
243 seconds := int64((s.TimeElapsed / time.Second) % 60)
244
245 switch style {
246 case ET_STYLE_GO:
247 str = fmt.Sprint(time.Duration(s.TimeElapsed.Seconds()) * time.Second)
248 case ET_STYLE_HHMMSS:
249 str = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
250 case ET_STYLE_HHMM:
251 str = fmt.Sprintf("%02d:%02d", hours, minutes)
252 case ET_STYLE_MMSS:
253 str = fmt.Sprintf("%02d:%02d", minutes, seconds)
254 }
255 return wc0.FormatMsg(str, widthAccumulator, widthDistributor)
256 })
257 }
258
259 // Percentage returns percentage decorator.
260 //
261 // `wc` optional WC config
262 func Percentage(wc ...WC) Decorator {
263 var wc0 WC
264 if len(wc) > 0 {
265 wc0 = wc[0]
266 }
267 wc0.BuildFormat()
268 return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
269 str := fmt.Sprintf("%d %%", CalcPercentage(s.Total, s.Current, 100))
270 return wc0.FormatMsg(str, widthAccumulator, widthDistributor)
271 })
272 }
273
274 // CalcPercentage is a helper function, to calculate percentage.
275 func CalcPercentage(total, current, width int64) int64 {
276 if total <= 0 {
277 return 0
278 }
279 p := float64(width*current) / float64(total)
280 return int64(round(p))
281 }
282
283 // SpeedNoUnit returns raw I/O operation speed decorator.
284 //
285 // `unitFormat` printf compatible verb for value, like "%f" or "%d"
286 //
287 // `wc` optional WC config
288 //
289 // unitFormat example:
290 //
291 // "%.1f" = "1.0" or "% .1f" = "1.0"
292 func SpeedNoUnit(unitFormat string, wc ...WC) Decorator {
293 return speed(unitFormat, 0, wc...)
294 }
295
296 // SpeedKibiByte returns human friendly I/O operation speed decorator,
297 //
298 // `unitFormat` printf compatible verb for value, like "%f" or "%d"
299 //
300 // `wc` optional WC config
301 //
302 // unitFormat example:
303 //
304 // "%.1f" = "1.0MiB/s" or "% .1f" = "1.0 MiB/s"
305 func SpeedKibiByte(unitFormat string, wc ...WC) Decorator {
306 return speed(unitFormat, unitKiB, wc...)
307 }
308
309 // SpeedKiloByte returns human friendly I/O operation speed decorator,
310 //
311 // `unitFormat` printf compatible verb for value, like "%f" or "%d"
312 //
313 // `wc` optional WC config
314 //
315 // unitFormat example:
316 //
317 // "%.1f" = "1.0MB/s" or "% .1f" = "1.0 MB/s"
318 func SpeedKiloByte(unitFormat string, wc ...WC) Decorator {
319 return speed(unitFormat, unitKB, wc...)
320 }
321
322 func speed(unitFormat string, unit int, wc ...WC) Decorator {
323 var wc0 WC
324 if len(wc) > 0 {
325 wc0 = wc[0]
326 }
327 wc0.BuildFormat()
328 return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
329 var str string
330 speed := float64(s.Current) / s.TimeElapsed.Seconds()
331 if math.IsNaN(speed) || math.IsInf(speed, 0) {
332 speed = .0
333 }
334
335 switch unit {
336 case unitKiB:
337 str = fmt.Sprintf(unitFormat, SpeedKiB(speed))
338 case unitKB:
339 str = fmt.Sprintf(unitFormat, SpeedKB(speed))
340 default:
341 str = fmt.Sprintf(unitFormat, speed)
342 }
343 return wc0.FormatMsg(str, widthAccumulator, widthDistributor)
344 })
345 }
0 package decor
1
2 import (
3 "fmt"
4 "time"
5 )
6
7 // Elapsed returns elapsed time decorator.
8 //
9 // `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
10 //
11 // `wcc` optional WC config
12 func Elapsed(style int, wcc ...WC) Decorator {
13 var wc WC
14 for _, widthConf := range wcc {
15 wc = widthConf
16 }
17 wc.BuildFormat()
18 startTime := time.Now()
19 return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
20 var str string
21 timeElapsed := time.Since(startTime)
22 hours := int64((timeElapsed / time.Hour) % 60)
23 minutes := int64((timeElapsed / time.Minute) % 60)
24 seconds := int64((timeElapsed / time.Second) % 60)
25
26 switch style {
27 case ET_STYLE_GO:
28 str = fmt.Sprint(time.Duration(timeElapsed.Seconds()) * time.Second)
29 case ET_STYLE_HHMMSS:
30 str = fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
31 case ET_STYLE_HHMM:
32 str = fmt.Sprintf("%02d:%02d", hours, minutes)
33 case ET_STYLE_MMSS:
34 str = fmt.Sprintf("%02d:%02d", minutes, seconds)
35 }
36 return wc.FormatMsg(str, widthAccumulator, widthDistributor)
37 })
38 }
1010 //
1111 // `style` one of [ET_STYLE_GO|ET_STYLE_HHMMSS|ET_STYLE_HHMM|ET_STYLE_MMSS]
1212 //
13 // `age` is related to the decay factor alpha by the formula given for the DECAY constant.
14 // It signifies the average age of the samples as time goes to infinity. Basically age is
15 // the previous N samples to average over. If zero value provided, it defaults to 30.
13 // `age` is the previous N samples to average over.
14 // If zero value provided, it defaults to 30.
1615 //
17 // `startBlock` is a time.Time receive channel. User suppose to send time.Now()
18 // to this channel on each iteration of block start, right before actual job.
19 // The channel will be closed automatically on bar shutdown event, so there is
20 // no need to close from user side.
16 // `sbCh` is a start block receive channel. User suppose to send time.Now()
17 // to this channel on each iteration of a start block, right before actual job.
18 // The channel will be auto closed on bar shutdown event, so there is no need
19 // to close from user side.
2120 //
22 // `wc` optional WC config
23 func ETA(style int, age float64, startBlock chan time.Time, wc ...WC) Decorator {
24 var wc0 WC
25 if len(wc) > 0 {
26 wc0 = wc[0]
21 // `wcc` optional WC config
22 func ETA(style int, age float64, sbCh chan time.Time, wcc ...WC) Decorator {
23 var wc WC
24 for _, widthConf := range wcc {
25 wc = widthConf
2726 }
28 wc0.BuildFormat()
27 wc.BuildFormat()
2928 if age == .0 {
3029 age = ewma.AVG_METRIC_AGE
3130 }
32 eta := &ewmaETA{
33 mAverage: ewma.NewMovingAverage(age),
34 startBlockReceiver: startBlock,
35 startBlockStreamer: make(chan time.Time),
36 style: style,
37 wc: wc0,
31 d := &ewmaETA{
32 style: style,
33 wc: wc,
34 mAverage: ewma.NewMovingAverage(age),
35 sbReceiver: sbCh,
36 sbStreamer: make(chan time.Time),
3837 }
39 go eta.serve()
40 return eta
38 go d.serve()
39 return d
4140 }
4241
4342 type ewmaETA struct {
44 mAverage ewma.MovingAverage
45 startBlockReceiver chan time.Time
46 startBlockStreamer chan time.Time
47 style int
48 wc WC
49 onComplete *struct {
43 style int
44 wc WC
45 mAverage ewma.MovingAverage
46 sbReceiver chan time.Time
47 sbStreamer chan time.Time
48 onComplete *struct {
5049 msg string
5150 wc WC
5251 }
7877 }
7978
8079 func (s *ewmaETA) NextAmount(n int) {
81 sb := <-s.startBlockStreamer
80 sb := <-s.sbStreamer
8281 lastBlockTime := time.Since(sb)
8382 lastItemEstimate := float64(lastBlockTime) / float64(n)
8483 s.mAverage.Add(lastItemEstimate)
8584 }
8685
87 func (s *ewmaETA) OnCompleteMessage(msg string, wc ...WC) {
88 var wc0 WC
89 if len(wc) > 0 {
90 wc0 = wc[0]
86 func (s *ewmaETA) OnCompleteMessage(msg string, wcc ...WC) {
87 var wc WC
88 for _, widthConf := range wcc {
89 wc = widthConf
9190 }
92 wc0.BuildFormat()
91 wc.BuildFormat()
9392 s.onComplete = &struct {
9493 msg string
9594 wc WC
96 }{msg, wc0}
95 }{msg, wc}
9796 }
9897
9998 func (s *ewmaETA) Shutdown() {
100 close(s.startBlockReceiver)
99 close(s.sbReceiver)
101100 }
102101
103102 func (s *ewmaETA) serve() {
104 for now := range s.startBlockReceiver {
105 s.startBlockStreamer <- now
103 for now := range s.sbReceiver {
104 s.sbStreamer <- now
106105 }
107106 }
0 package decor
1
2 // StaticName returns name decorator.
3 //
4 // `name` string to display
5 //
6 // `wcc` optional WC config
7 func StaticName(name string, wcc ...WC) Decorator {
8 return Name(name, wcc...)
9 }
10
11 // Name returns name decorator.
12 //
13 // `name` string to display
14 //
15 // `wcc` optional WC config
16 func Name(name string, wcc ...WC) Decorator {
17 var wc WC
18 for _, widthConf := range wcc {
19 wc = widthConf
20 }
21 wc.BuildFormat()
22 return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
23 return wc.FormatMsg(name, widthAccumulator, widthDistributor)
24 })
25 }
0 package decor
1
2 import "fmt"
3
4 // Percentage returns percentage decorator.
5 //
6 // `wcc` optional WC config
7 func Percentage(wcc ...WC) Decorator {
8 var wc WC
9 for _, widthConf := range wcc {
10 wc = widthConf
11 }
12 wc.BuildFormat()
13 return DecoratorFunc(func(s *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
14 str := fmt.Sprintf("%d %%", CalcPercentage(s.Total, s.Current, 100))
15 return wc.FormatMsg(str, widthAccumulator, widthDistributor)
16 })
17 }
18
19 // CalcPercentage is a helper function, to calculate percentage.
20 func CalcPercentage(total, current, width int64) int64 {
21 if total <= 0 {
22 return 0
23 }
24 p := float64(width*current) / float64(total)
25 return int64(round(p))
26 }
44 "io"
55 "strconv"
66 "strings"
7 "time"
8
9 "github.com/VividCortex/ewma"
710 )
811
912 type SpeedKiB float64
113116
114117 io.WriteString(st, res)
115118 }
119
120 // SpeedNoUnit returns raw I/O operation speed decorator.
121 //
122 // `unitFormat` printf compatible verb for value, like "%f" or "%d"
123 //
124 // `age` is the previous N samples to average over.
125 // If zero value provided, it defaults to 30.
126 //
127 // `sbCh` is a start block receive channel. User suppose to send time.Now()
128 // to this channel on each iteration of a start block, right before actual job.
129 // The channel will be auto closed on bar shutdown event, so there is no need
130 // to close from user side.
131 //
132 // `wcc` optional WC config
133 //
134 // unitFormat example:
135 //
136 // "%.1f" = "1.0" or "% .1f" = "1.0"
137 func SpeedNoUnit(unitFormat string, age float64, sbCh chan time.Time, wcc ...WC) Decorator {
138 return speed(0, unitFormat, age, sbCh, wcc...)
139 }
140
141 // SpeedKibiByte returns human friendly I/O operation speed decorator,
142 //
143 // `unitFormat` printf compatible verb for value, like "%f" or "%d"
144 //
145 // `age` is the previous N samples to average over.
146 // If zero value provided, it defaults to 30.
147 //
148 // `sbCh` is a start block receive channel. User suppose to send time.Now()
149 // to this channel on each iteration of a start block, right before actual job.
150 // The channel will be auto closed on bar shutdown event, so there is no need
151 // to close from user side.
152 //
153 // `wcc` optional WC config
154 //
155 // unitFormat example:
156 //
157 // "%.1f" = "1.0MiB/s" or "% .1f" = "1.0 MiB/s"
158 func SpeedKibiByte(unitFormat string, age float64, sbCh chan time.Time, wcc ...WC) Decorator {
159 return speed(unitKiB, unitFormat, age, sbCh, wcc...)
160 }
161
162 // SpeedKiloByte returns human friendly I/O operation speed decorator,
163 //
164 // `unitFormat` printf compatible verb for value, like "%f" or "%d"
165 //
166 // `age` is the previous N samples to average over.
167 // If zero value provided, it defaults to 30.
168 //
169 // `sbCh` is a start block receive channel. User suppose to send time.Now()
170 // to this channel on each iteration of a start block, right before actual job.
171 // The channel will be auto closed on bar shutdown event, so there is no need
172 // to close from user side.
173 //
174 // `wcc` optional WC config
175 //
176 // unitFormat example:
177 //
178 // "%.1f" = "1.0MB/s" or "% .1f" = "1.0 MB/s"
179 func SpeedKiloByte(unitFormat string, age float64, sbCh chan time.Time, wcc ...WC) Decorator {
180 return speed(unitKB, unitFormat, age, sbCh, wcc...)
181 }
182
183 func speed(unit int, unitFormat string, age float64, sbCh chan time.Time, wcc ...WC) Decorator {
184 var wc WC
185 for _, widthConf := range wcc {
186 wc = widthConf
187 }
188 wc.BuildFormat()
189 if age == .0 {
190 age = ewma.AVG_METRIC_AGE
191 }
192 d := &ewmaSpeed{
193 unit: unit,
194 unitFormat: unitFormat,
195 wc: wc,
196 mAverage: ewma.NewMovingAverage(age),
197 sbReceiver: sbCh,
198 sbStreamer: make(chan time.Time),
199 }
200 go d.serve()
201 return d
202 }
203
204 type ewmaSpeed struct {
205 unit int
206 unitFormat string
207 wc WC
208 mAverage ewma.MovingAverage
209 sbReceiver chan time.Time
210 sbStreamer chan time.Time
211 onComplete *struct {
212 msg string
213 wc WC
214 }
215 }
216
217 func (s *ewmaSpeed) Decor(st *Statistics, widthAccumulator chan<- int, widthDistributor <-chan int) string {
218 if st.Completed && s.onComplete != nil {
219 return s.onComplete.wc.FormatMsg(s.onComplete.msg, widthAccumulator, widthDistributor)
220 }
221 var str string
222 speed := round(s.mAverage.Value())
223 switch s.unit {
224 case unitKiB:
225 str = fmt.Sprintf(s.unitFormat, SpeedKiB(speed))
226 case unitKB:
227 str = fmt.Sprintf(s.unitFormat, SpeedKB(speed))
228 default:
229 str = fmt.Sprintf(s.unitFormat, speed)
230 }
231 return s.wc.FormatMsg(str, widthAccumulator, widthDistributor)
232 }
233
234 func (s *ewmaSpeed) NextAmount(n int) {
235 sb := <-s.sbStreamer
236 speed := float64(n) / time.Since(sb).Seconds()
237 s.mAverage.Add(speed)
238 }
239
240 func (s *ewmaSpeed) OnCompleteMessage(msg string, wcc ...WC) {
241 var wc WC
242 for _, widthConf := range wcc {
243 wc = widthConf
244 }
245 wc.BuildFormat()
246 s.onComplete = &struct {
247 msg string
248 wc WC
249 }{msg, wc}
250 }
251
252 func (s *ewmaSpeed) Shutdown() {
253 close(s.sbReceiver)
254 }
255
256 func (s *ewmaSpeed) serve() {
257 for now := range s.sbReceiver {
258 s.sbStreamer <- now
259 }
260 }
5757 return
5858 }
5959
60 startBlock := make(chan time.Time)
61
60 sbEta := make(chan time.Time)
61 sbSpeed := make(chan time.Time)
6262 // create bar with appropriate decorators
6363 bar := p.AddBar(size, mpb.BarPriority(n),
6464 mpb.PrependDecorators(
6666 decor.CountersKibiByte("%6.1f / %6.1f", decor.WCSyncWidth),
6767 ),
6868 mpb.AppendDecorators(
69 decor.ETA(decor.ET_STYLE_HHMMSS, 60, startBlock, decor.WCSyncWidth),
70 decor.SpeedKibiByte("%6.1f", decor.WCSyncSpace),
69 decor.ETA(decor.ET_STYLE_HHMMSS, 60, sbEta, decor.WCSyncWidth),
70 decor.SpeedKibiByte("% .2f", 60, sbSpeed, decor.WCSyncSpace),
7171 ),
7272 )
7373
7474 // create proxy reader
75 reader := bar.ProxyReader(resp.Body, startBlock)
75 reader := bar.ProxyReader(resp.Body, sbEta, sbSpeed)
7676 // and copy from reader
7777 _, err = io.Copy(dest, reader)
7878
3838
3939 p := mpb.New(mpb.WithWidth(64))
4040
41 startBlock := make(chan time.Time)
41 sbEta := make(chan time.Time)
42 sbSpeed := make(chan time.Time)
4243 bar := p.AddBar(size,
4344 mpb.PrependDecorators(
4445 decor.CountersKibiByte("% 6.1f / % 6.1f", decor.WC{W: 18}),
4546 ),
4647 mpb.AppendDecorators(
47 decor.ETA(decor.ET_STYLE_HHMMSS, 120, startBlock),
48 decor.SpeedKibiByte("% 6.1f", decor.WC{W: 14}),
48 decor.ETA(decor.ET_STYLE_HHMMSS, 120, sbEta),
49 decor.SpeedKibiByte("% .2f", 120, sbSpeed, decor.WC{W: 14}),
4950 ),
5051 )
5152
5253 // create proxy reader
53 reader := bar.ProxyReader(resp.Body, startBlock)
54 reader := bar.ProxyReader(resp.Body, sbEta, sbSpeed)
5455
5556 // and copy from reader, ignoring errors
5657 io.Copy(dest, reader)
77 // Reader is io.Reader wrapper, for proxy read bytes
88 type Reader struct {
99 io.Reader
10 bar *Bar
11 startBlockCh chan<- time.Time
10 bar *Bar
11 sbChannels []chan<- time.Time
1212 }
1313
1414 func (r *Reader) Read(p []byte) (int, error) {
15 if r.startBlockCh != nil {
16 r.startBlockCh <- time.Now()
15 now := time.Now()
16 for _, ch := range r.sbChannels {
17 ch <- now
1718 }
1819 n, err := r.Reader.Read(p)
1920 r.bar.IncrBy(n)