tools/humanize: add 'FormatByteRate' to format transfer speed
This commit is contained in:
parent
5058d0f983
commit
d3afd10340
@ -5,6 +5,7 @@ import (
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/git-lfs/git-lfs/errors"
|
||||
@ -23,6 +24,10 @@ const (
|
||||
Gigabyte = 1000 * Megabyte
|
||||
Terabyte = 1000 * Gigabyte
|
||||
Petabyte = 1000 * Terabyte
|
||||
|
||||
// eps is the machine epsilon, or a 64-bit floating point value
|
||||
// reasonably close to zero.
|
||||
eps float64 = 7.0/3 - 4.0/3 - 1.0
|
||||
)
|
||||
|
||||
var bytesTable = map[string]uint64{
|
||||
@ -126,6 +131,38 @@ func FormatBytesUnit(s, u uint64) string {
|
||||
return fmt.Sprintf(format, rounded)
|
||||
}
|
||||
|
||||
// FormatByteRate outputs the given rate of transfer "r" as the quotient of "s"
|
||||
// (the number of bytes transferred) over "d" (the duration of time that those
|
||||
// bytes were transferred in).
|
||||
//
|
||||
// It displays the output as a quantity of a "per-unit-time" unit (i.e., B/s,
|
||||
// MiB/s) in the most representative fashion possible, as above.
|
||||
func FormatByteRate(s uint64, d time.Duration) string {
|
||||
// e is the index of the most representative unit of storage.
|
||||
var e float64
|
||||
|
||||
// f is the floating-point equivalent of "s", so as to avoid more
|
||||
// conversions than necessary.
|
||||
f := float64(s)
|
||||
|
||||
if f != 0 {
|
||||
f = f / d.Seconds()
|
||||
e = math.Floor(log(f, 1000))
|
||||
if e <= eps {
|
||||
// The result of math.Floor(log(r, 1000)) can be
|
||||
// "close-enough" to zero that it should be effectively
|
||||
// considered zero.
|
||||
e = 0
|
||||
}
|
||||
}
|
||||
|
||||
unit := uint64(math.Pow(1000, e))
|
||||
suffix := sizes[int(e)]
|
||||
|
||||
return fmt.Sprintf("%s %s/s",
|
||||
FormatBytesUnit(uint64(math.Ceil(f)), unit), suffix)
|
||||
}
|
||||
|
||||
// log takes the log base "b" of "n" (\log_b{n})
|
||||
func log(n, b float64) float64 {
|
||||
return math.Log(n) / math.Log(b)
|
||||
|
@ -3,6 +3,7 @@ package humanize_test
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/git-lfs/git-lfs/tools/humanize"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -59,6 +60,16 @@ func (c *FormatBytesUnitTestCase) Assert(t *testing.T) {
|
||||
assert.Equal(t, c.Expected, humanize.FormatBytesUnit(c.Given, c.Unit))
|
||||
}
|
||||
|
||||
type FormatByteRateTestCase struct {
|
||||
Given uint64
|
||||
Over time.Duration
|
||||
Expected string
|
||||
}
|
||||
|
||||
func (c *FormatByteRateTestCase) Assert(t *testing.T) {
|
||||
assert.Equal(t, c.Expected, humanize.FormatByteRate(c.Given, c.Over))
|
||||
}
|
||||
|
||||
func TestParseBytes(t *testing.T) {
|
||||
for desc, c := range map[string]*ParseBytesTestCase{
|
||||
"parse byte (zero, empty)": {"", uint64(0), nil},
|
||||
@ -234,3 +245,36 @@ func TestFormatBytesUnit(t *testing.T) {
|
||||
t.Run(desc, c.Assert)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormateByteRate(t *testing.T) {
|
||||
for desc, c := range map[string]*FormatByteRateTestCase{
|
||||
"format bytes": {uint64(1 * math.Pow(10, 0)), time.Second, "1 B/s"},
|
||||
"format kilobytes": {uint64(1 * math.Pow(10, 3)), time.Second, "1.0 KB/s"},
|
||||
"format megabytes": {uint64(1 * math.Pow(10, 6)), time.Second, "1.0 MB/s"},
|
||||
"format gigabytes": {uint64(1 * math.Pow(10, 9)), time.Second, "1.0 GB/s"},
|
||||
"format petabytes": {uint64(1 * math.Pow(10, 12)), time.Second, "1.0 TB/s"},
|
||||
"format terabytes": {uint64(1 * math.Pow(10, 15)), time.Second, "1.0 PB/s"},
|
||||
|
||||
"format kilobytes under": {uint64(1.49 * math.Pow(10, 3)), time.Second, "1.5 KB/s"},
|
||||
"format megabytes under": {uint64(1.49 * math.Pow(10, 6)), time.Second, "1.5 MB/s"},
|
||||
"format gigabytes under": {uint64(1.49 * math.Pow(10, 9)), time.Second, "1.5 GB/s"},
|
||||
"format petabytes under": {uint64(1.49 * math.Pow(10, 12)), time.Second, "1.5 TB/s"},
|
||||
"format terabytes under": {uint64(1.49 * math.Pow(10, 15)), time.Second, "1.5 PB/s"},
|
||||
|
||||
"format kilobytes over": {uint64(1.51 * math.Pow(10, 3)), time.Second, "1.5 KB/s"},
|
||||
"format megabytes over": {uint64(1.51 * math.Pow(10, 6)), time.Second, "1.5 MB/s"},
|
||||
"format gigabytes over": {uint64(1.51 * math.Pow(10, 9)), time.Second, "1.5 GB/s"},
|
||||
"format petabytes over": {uint64(1.51 * math.Pow(10, 12)), time.Second, "1.5 TB/s"},
|
||||
"format terabytes over": {uint64(1.51 * math.Pow(10, 15)), time.Second, "1.5 PB/s"},
|
||||
|
||||
"format kilobytes exact": {uint64(1.3 * math.Pow(10, 3)), time.Second, "1.3 KB/s"},
|
||||
"format megabytes exact": {uint64(1.3 * math.Pow(10, 6)), time.Second, "1.3 MB/s"},
|
||||
"format gigabytes exact": {uint64(1.3 * math.Pow(10, 9)), time.Second, "1.3 GB/s"},
|
||||
"format petabytes exact": {uint64(1.3 * math.Pow(10, 12)), time.Second, "1.3 TB/s"},
|
||||
"format terabytes exact": {uint64(1.3 * math.Pow(10, 15)), time.Second, "1.3 PB/s"},
|
||||
|
||||
"format bytes (non-second)": {uint64(10 * math.Pow(10, 0)), 2 * time.Second, "5 B/s"},
|
||||
} {
|
||||
t.Run(desc, c.Assert)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user