...
1 package utils
2
3 import (
4 "fmt"
5 "sync"
6 "time"
7 )
8
9
23 type ProgressReporter struct {
24 lastPrinted time.Time
25 eta time.Time
26 etaCalced time.Time
27 rate1 *rateCalculator
28 rate2 *rateCalculator
29 cur_rc int
30 since_rc time.Time
31 start time.Time
32 total uint64
33 done uint64
34 RawPrint bool
35 addlock sync.Mutex
36 Prefix string
37 }
38
39 func (p *ProgressReporter) SetTotal(total uint64) {
40 p.total = total
41 }
42 func (p *ProgressReporter) Set(a uint64) {
43 p.Add(a - p.done)
44 }
45 func (p *ProgressReporter) Inc() {
46 p.Add(1)
47 }
48 func (p *ProgressReporter) Add(a uint64) {
49 p.fixRates()
50 p.addlock.Lock()
51 defer p.addlock.Unlock()
52 p.rate1.Add(a)
53 p.rate2.Add(a)
54 p.done = p.done + a
55 }
56 func (p *ProgressReporter) Eta() time.Time {
57 if time.Since(p.etaCalced) < (time.Duration(5) * time.Second) {
58 return p.eta
59 }
60 left := float64(p.total - p.done)
61 r := p.Rate()
62 secs_to_go := time.Duration(left/r) * time.Second
63 p.eta = time.Now().Add(secs_to_go)
64 p.etaCalced = time.Now()
65 return p.eta
66 }
67
68
69 func (p *ProgressReporter) PrintSingleLine() bool {
70 s := p.String()
71 if s == "" {
72 return false
73 }
74 fmt.Printf("%c%s", byte(13), s)
75 return true
76 }
77 func (p *ProgressReporter) Print() bool {
78 s := p.String()
79 if s == "" {
80 return false
81 }
82 fmt.Println(s)
83 return true
84 }
85
86 func (p *ProgressReporter) fixRates() {
87 if p.rate1 == nil {
88 p.rate1 = &rateCalculator{name: "calc1", start: time.Now()}
89 }
90 if p.rate2 == nil {
91 p.rate2 = &rateCalculator{name: "calc2", start: time.Now()}
92 }
93 if p.cur_rc == 0 {
94 p.cur_rc = 1
95 }
96 if time.Since(p.since_rc) > time.Duration(5)*time.Second {
97 if p.cur_rc == 1 {
98 p.cur_rc = 2
99 p.rate1.Reset()
100 } else {
101 p.cur_rc = 1
102 p.rate2.Reset()
103 }
104 p.since_rc = time.Now()
105 }
106 }
107 func (p *ProgressReporter) Rate() float64 {
108 p.fixRates()
109
110 var rc *rateCalculator
111
112 rc = p.rate1
113 if p.cur_rc == 2 {
114 rc = p.rate2
115 }
116
117 res := rc.Rate()
118 return res
119 }
120 func (p *ProgressReporter) String() string {
121 if (time.Since(p.lastPrinted)) < (time.Duration(1) * time.Second) {
122 return ""
123 }
124 p.lastPrinted = time.Now()
125 eta_s := p.Eta().Format("2006-01-02 15:04:05")
126 perc := float32(float32(p.done) / float32(p.total) * float32(100))
127 sp := ""
128 if p.Prefix != "" {
129 sp = fmt.Sprintf("[%s]: ", p.Prefix)
130 }
131 prefix := fmt.Sprintf("%sProcessing %d", sp, p.done)
132 if p.total != 0 {
133 prefix = fmt.Sprintf("%sProcessing %d of %d (%2.1f%%), ETA: %v", sp, p.done, p.total, perc, eta_s)
134 }
135 if p.RawPrint {
136 return prefix + fmt.Sprintf(", %.1f/sec", p.Rate())
137 } else {
138 return prefix + fmt.Sprintf(", %s/sec", PrettyNumber(uint64(p.Rate())))
139 }
140
141 }
142
143 type RateCalculator interface {
144 Add(a uint64)
145 Rate() float64
146 Reset()
147 String() string
148 }
149
150 func NewRateCalculator(name string) RateCalculator {
151 res := &rateCalculator{name: name, start: time.Now()}
152 return res
153
154 }
155
156 type rateCalculator struct {
157 start time.Time
158 counter uint64
159 additions int
160 resetted bool
161 name string
162 }
163
164 func (r *rateCalculator) Add(a uint64) {
165 r.additions++
166 r.counter = r.counter + a
167
168 }
169 func (r *rateCalculator) Rate() float64 {
170 elapsed := time.Since(r.start).Seconds()
171 z := float64(r.counter)
172 f := z / (elapsed)
173 return f
174 }
175 func (r *rateCalculator) Reset() {
176 r.start = time.Now()
177 r.additions = 0
178 r.counter = 0
179 r.resetted = false
180
181 }
182
183 func (r *rateCalculator) String() string {
184 return fmt.Sprintf("%s (started %0.1f seconds ago, points=%d", r.name, time.Since(r.start).Seconds(), r.additions)
185 }
186
View as plain text