diff --git a/bps.go b/bps.go index 250ada9..ff40761 100644 --- a/bps.go +++ b/bps.go @@ -131,6 +131,48 @@ func (b *BPS) HumanRate() string { return human(uint64(b.Rate())) + "/s" } +// Sparkline returns a human-friendly sprakline of history +func (b *BPS) Sparkline(count int) string { + if count > len(b.buckets) { + return "bucket count inappropriate" + } + sparks := []string{"▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"} + line := "" + bucketsPer := len(b.buckets) / count + b.Lock() + defer b.Unlock() + + var max int64 + var cur int64 + + // find max + for i := 0; i < len(b.buckets); i++ { + cur = b.buckets[i] + if cur > max { + max = cur + } + } + + if max == 0 { + for i := 0; i < count; i++ { + line += sparks[0] + } + return line + } + + cur = 0 + for i := 0; i < len(b.buckets); i++ { + val := b.buckets[(b.timeI+i)%len(b.buckets)] + cur += val + if i%bucketsPer == 0 { + approx := int((float64(cur) / float64(max)) * float64(len(sparks)-1)) + line += sparks[approx] + cur = 0 + } + } + return line +} + // Close cleans up and shuts down a BPS. func (b *BPS) Close() { close(b.quit) diff --git a/bps_test.go b/bps_test.go index 6365f46..df9057e 100644 --- a/bps_test.go +++ b/bps_test.go @@ -93,3 +93,33 @@ func TestHumanBytes(t *testing.T) { t.Fatalf("did not get right human rate; got %v, want %v", got, want) } } + +func TestSparkline(t *testing.T) { + bw := BPS{ + buckets: make([]int64, 10), + } + t.Logf("%+v", bw.Sparkline(100)) + bw.buckets[3] = 100 + t.Logf("%+v", bw.Sparkline(10)) + bw.buckets[7] = 300 + for i := 1; i < 10; i++ { + t.Logf("%+v", bw.Sparkline(i)) + } + + for i := 0; i < 10; i++ { + bw.buckets[i] = int64(i * 10) + t.Logf("%+v", bw.Sparkline(10)) + } + t.Logf("%+v", bw.Sparkline(10)) + for i := 0; i < 10; i++ { + bw.buckets[i] = 0 + } + + for i := 0; i < 10; i++ { + bw.buckets[i] = int64((10 - i) * 10) + t.Logf("%+v", bw.Sparkline(10)) + } + t.Logf("%+v", bw.Sparkline(10)) + bw.buckets[5] = 200 + t.Logf("%+v", bw.Sparkline(10)) +}