imposm3/stats/stats.go

167 lines
3.9 KiB
Go

package stats
import (
"fmt"
"github.com/omniscale/imposm3/logging"
"time"
)
type Counter struct {
start time.Time
Coords *RpsCounter
Nodes *RpsCounter
Ways *RpsCounter
Relations *RpsCounter
}
func (c *Counter) Tick() {
c.Coords.Tick()
c.Nodes.Tick()
c.Ways.Tick()
c.Relations.Tick()
}
func NewCounter() *Counter {
return &Counter{
start: time.Now(),
Coords: NewRpsCounter(),
Nodes: NewRpsCounter(),
Ways: NewRpsCounter(),
Relations: NewRpsCounter(),
}
}
func NewCounterWithEstimate(counts ElementCounts) *Counter {
counter := NewCounter()
counter.Coords.total = counts.Coords.Current
counter.Nodes.total = counts.Nodes.Current
counter.Ways.total = counts.Ways.Current
counter.Relations.total = counts.Relations.Current
return counter
}
type ElementCounts struct {
Coords, Nodes, Ways, Relations ElementCount
}
// Duration returns the duration since start with seconds precission.
func (c *Counter) CurrentCount() *ElementCounts {
return &ElementCounts{
Coords: c.Coords.Count(),
Nodes: c.Nodes.Count(),
Ways: c.Ways.Count(),
Relations: c.Relations.Count(),
}
}
// Duration returns the duration since start with seconds precission.
func (c *Counter) Duration() time.Duration {
return time.Duration(int64(time.Since(c.start).Seconds()) * 1000 * 1000 * 1000)
}
type Statistics struct {
counter *Counter
done chan bool
}
const (
RESET = iota
START
STOP
QUIT
)
func (s *Statistics) AddCoords(n int) { s.counter.Coords.Add(n) }
func (s *Statistics) AddNodes(n int) { s.counter.Nodes.Add(n) }
func (s *Statistics) AddWays(n int) { s.counter.Ways.Add(n) }
func (s *Statistics) AddRelations(n int) { s.counter.Relations.Add(n) }
func (s *Statistics) Stop() *ElementCounts {
s.done <- true
return s.counter.CurrentCount()
}
func NewStatsReporter() *Statistics {
s := Statistics{}
s.counter = NewCounter()
s.done = make(chan bool)
go s.loop()
return &s
}
func NewStatsReporterWithEstimate(counts *ElementCounts) *Statistics {
s := Statistics{}
if counts != nil {
s.counter = NewCounterWithEstimate(*counts)
} else {
s.counter = NewCounter()
}
s.done = make(chan bool)
go s.loop()
return &s
}
func (s *Statistics) loop() {
tick := time.NewTicker(500 * time.Millisecond)
tock := time.NewTicker(time.Minute)
for {
select {
case <-s.done:
tick.Stop()
tock.Stop()
s.counter.PrintStats()
return
case <-tock.C:
s.counter.PrintStats()
case <-tick.C:
s.counter.PrintTick()
s.counter.Tick()
}
}
}
func fmtPercentOrVal(progress float64, value int64) string {
if progress == -1.0 {
return fmt.Sprintf("%d", value)
}
return fmt.Sprintf("%4.1f%%", progress*100)
}
func roundInt(val float64, round int) int64 {
return int64(val/float64(round)) * int64(round)
}
func (c *Counter) PrintTick() {
logging.Progress(
fmt.Sprintf("[%6s] C: %7d/s %7d/s (%s) N: %7d/s %7d/s (%s) W: %7d/s %7d/s (%s) R: %6d/s %6d/s (%s)",
c.Duration(),
roundInt(c.Coords.Rps(), 1000),
roundInt(c.Coords.LastRps(), 1000),
fmtPercentOrVal(c.Coords.Progress(), c.Coords.Value()),
roundInt(c.Nodes.Rps(), 100),
roundInt(c.Nodes.LastRps(), 100),
fmtPercentOrVal(c.Nodes.Progress(), c.Nodes.Value()),
roundInt(c.Ways.Rps(), 100),
roundInt(c.Ways.LastRps(), 100),
fmtPercentOrVal(c.Ways.Progress(), c.Ways.Value()),
roundInt(c.Relations.Rps(), 10),
roundInt(c.Relations.LastRps(), 10),
fmtPercentOrVal(c.Relations.Progress(), c.Relations.Value()),
))
}
func (c *Counter) PrintStats() {
logging.Infof("[%6s] C: %7d/s (%s) N: %7d/s (%s) W: %7d/s (%s) R: %6d/s (%s)",
c.Duration(),
roundInt(c.Coords.Rps(), 1000),
fmtPercentOrVal(c.Coords.Progress(), c.Coords.Value()),
roundInt(c.Nodes.Rps(), 100),
fmtPercentOrVal(c.Nodes.Progress(), c.Nodes.Value()),
roundInt(c.Ways.Rps(), 100),
fmtPercentOrVal(c.Ways.Progress(), c.Ways.Value()),
roundInt(c.Relations.Rps(), 10),
fmtPercentOrVal(c.Relations.Progress(), c.Relations.Value()),
)
}