Skip to content

Commit ef7460a

Browse files
committed
auto-scale precision, limiting to 3 digits
1 parent d0c992a commit ef7460a

File tree

5 files changed

+57
-127
lines changed

5 files changed

+57
-127
lines changed

cli/clistat/cgroup.go

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const (
5151
// If there is no limit set, the total is assumed to be the
5252
// number of host cores multiplied by the CFS period.
5353
// If the system is not containerized, this always returns nil.
54-
func (s *Statter) ContainerCPU(m Prefix) (*Result, error) {
54+
func (s *Statter) ContainerCPU() (*Result, error) {
5555
// Firstly, check if we are containerized.
5656
if ok, err := IsContainerized(s.fs); err != nil || !ok {
5757
return nil, nil //nolint: nilnil
@@ -84,10 +84,9 @@ func (s *Statter) ContainerCPU(m Prefix) (*Result, error) {
8484
}
8585

8686
r := &Result{
87-
Unit: "cores",
88-
Prefix: m,
89-
Used: used2 - used1,
90-
Total: ptr.To(total),
87+
Unit: "cores",
88+
Used: used2 - used1,
89+
Total: ptr.To(total),
9190
}
9291
return r, nil
9392
}
@@ -185,20 +184,20 @@ func (s *Statter) cGroupV1CPUUsed() (float64, error) {
185184

186185
// ContainerMemory returns the memory usage of the container cgroup.
187186
// If the system is not containerized, this always returns nil.
188-
func (s *Statter) ContainerMemory(m Prefix) (*Result, error) {
187+
func (s *Statter) ContainerMemory() (*Result, error) {
189188
if ok, err := IsContainerized(s.fs); err != nil || !ok {
190189
return nil, nil //nolint:nilnil
191190
}
192191

193192
if s.isCGroupV2() {
194-
return s.cGroupV2Memory(m)
193+
return s.cGroupV2Memory()
195194
}
196195

197196
// Fall back to CGroupv1
198-
return s.cGroupV1Memory(m)
197+
return s.cGroupV1Memory()
199198
}
200199

201-
func (s *Statter) cGroupV2Memory(m Prefix) (*Result, error) {
200+
func (s *Statter) cGroupV2Memory() (*Result, error) {
202201
maxUsageBytes, err := readInt64(s.fs, cgroupV2MemoryMaxBytes)
203202
if err != nil {
204203
return nil, xerrors.Errorf("read memory total: %w", err)
@@ -215,14 +214,13 @@ func (s *Statter) cGroupV2Memory(m Prefix) (*Result, error) {
215214
}
216215

217216
return &Result{
218-
Total: ptr.To(float64(maxUsageBytes)),
219-
Used: float64(currUsageBytes - inactiveFileBytes),
220-
Unit: "B",
221-
Prefix: m,
217+
Total: ptr.To(float64(maxUsageBytes)),
218+
Used: float64(currUsageBytes - inactiveFileBytes),
219+
Unit: "B",
222220
}, nil
223221
}
224222

225-
func (s *Statter) cGroupV1Memory(m Prefix) (*Result, error) {
223+
func (s *Statter) cGroupV1Memory() (*Result, error) {
226224
maxUsageBytes, err := readInt64(s.fs, cgroupV1MemoryMaxUsageBytes)
227225
if err != nil {
228226
return nil, xerrors.Errorf("read memory total: %w", err)
@@ -241,10 +239,9 @@ func (s *Statter) cGroupV1Memory(m Prefix) (*Result, error) {
241239

242240
// Total memory used is usage - total_inactive_file
243241
return &Result{
244-
Total: ptr.To(float64(maxUsageBytes)),
245-
Used: float64(usageBytes - totalInactiveFileBytes),
246-
Unit: "B",
247-
Prefix: m,
242+
Total: ptr.To(float64(maxUsageBytes)),
243+
Used: float64(usageBytes - totalInactiveFileBytes),
244+
Unit: "B",
248245
}, nil
249246
}
250247

cli/clistat/disk.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010

1111
// Disk returns the disk usage of the given path.
1212
// If path is empty, it returns the usage of the root directory.
13-
func (*Statter) Disk(path string, m Prefix) (*Result, error) {
13+
func (*Statter) Disk(path string) (*Result, error) {
1414
if path == "" {
1515
path = "/"
1616
}
@@ -22,6 +22,5 @@ func (*Statter) Disk(path string, m Prefix) (*Result, error) {
2222
r.Total = ptr.To(float64(stat.Blocks * uint64(stat.Bsize)))
2323
r.Used = float64(stat.Blocks-stat.Bfree) * float64(stat.Bsize)
2424
r.Unit = "B"
25-
r.Prefix = m
2625
return &r, nil
2726
}

cli/clistat/disk_windows.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77

88
// Disk returns the disk usage of the given path.
99
// If path is empty, it defaults to C:\
10-
func (*Statter) Disk(path string, m Prefix) (*Result, error) {
10+
func (*Statter) Disk(path string) (*Result, error) {
1111
if path == "" {
1212
path = `C:\`
1313
}
@@ -31,6 +31,5 @@ func (*Statter) Disk(path string, m Prefix) (*Result, error) {
3131
r.Total = ptr.To(float64(totalBytes))
3232
r.Used = float64(totalBytes - freeBytes)
3333
r.Unit = "B"
34-
r.Prefix = m
3534
return &r, nil
3635
}

cli/clistat/stat.go

Lines changed: 25 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"strings"
77
"time"
88

9+
"github.com/dustin/go-humanize"
910
"github.com/elastic/go-sysinfo"
1011
"github.com/spf13/afero"
1112
"golang.org/x/xerrors"
@@ -14,77 +15,6 @@ import (
1415
sysinfotypes "github.com/elastic/go-sysinfo/types"
1516
)
1617

17-
// Prefix is an SI prefix for a unit.
18-
type Prefix string
19-
20-
// Float64 returns the prefix as a float64.
21-
func (m *Prefix) Float64() (float64, error) {
22-
switch *m {
23-
case PrefixDeciShort, PrefixDeci:
24-
return 0.1, nil
25-
case PrefixCentiShort, PrefixCenti:
26-
return 0.01, nil
27-
case PrefixMilliShort, PrefixMilli:
28-
return 0.001, nil
29-
case PrefixMicroShort, PrefixMicro:
30-
return 0.000_001, nil
31-
case PrefixNanoShort, PrefixNano:
32-
return 0.000_000_001, nil
33-
case PrefixKiloShort, PrefixKilo:
34-
return 1_000.0, nil
35-
case PrefixMegaShort, PrefixMega:
36-
return 1_000_000.0, nil
37-
case PrefixGigaShort, PrefixGiga:
38-
return 1_000_000_000.0, nil
39-
case PrefixTeraShort, PrefixTera:
40-
return 1_000_000_000_000.0, nil
41-
case PrefixKibiShort, PrefixKibi:
42-
return 1024.0, nil
43-
case PrefixMebiShort, PrefixMebi:
44-
return 1_048_576.0, nil
45-
case PrefixGibiShort, PrefixGibi:
46-
return 1_073_741_824.0, nil
47-
case PrefixTebiShort, PrefixTebi:
48-
return 1_099_511_627_776.0, nil
49-
default:
50-
return 0, xerrors.Errorf("unknown prefix: %s", *m)
51-
}
52-
}
53-
54-
const (
55-
PrefixDeci Prefix = "deci"
56-
PrefixCenti Prefix = "centi"
57-
PrefixMilli Prefix = "milli"
58-
PrefixMicro Prefix = "micro"
59-
PrefixNano Prefix = "nano"
60-
61-
PrefixDeciShort Prefix = "d"
62-
PrefixCentiShort Prefix = "c"
63-
PrefixMilliShort Prefix = "m"
64-
PrefixMicroShort Prefix = "u"
65-
PrefixNanoShort Prefix = "n"
66-
67-
PrefixKilo Prefix = "kilo"
68-
PrefixMega Prefix = "mega"
69-
PrefixGiga Prefix = "giga"
70-
PrefixTera Prefix = "tera"
71-
72-
PrefixKiloShort Prefix = "K"
73-
PrefixMegaShort Prefix = "M"
74-
PrefixGigaShort Prefix = "G"
75-
PrefixTeraShort Prefix = "T"
76-
77-
PrefixKibi = "kibi"
78-
PrefixMebi = "mebi"
79-
PrefixGibi = "gibi"
80-
PrefixTebi = "tebi"
81-
82-
PrefixKibiShort Prefix = "Ki"
83-
PrefixMebiShort Prefix = "Mi"
84-
PrefixGibiShort Prefix = "Gi"
85-
PrefixTebiShort Prefix = "Ti"
86-
)
87-
8818
// Result is a generic result type for a statistic.
8919
// Total is the total amount of the resource available.
9020
// It is nil if the resource is not a finite quantity.
@@ -94,37 +24,44 @@ type Result struct {
9424
Total *float64 `json:"total"`
9525
Unit string `json:"unit"`
9626
Used float64 `json:"used"`
97-
// Prefix controls the string representation of the result.
98-
Prefix Prefix `json:"-"`
9927
}
10028

10129
// String returns a human-readable representation of the result.
10230
func (r *Result) String() string {
10331
if r == nil {
10432
return "-"
10533
}
34+
10635
var sb strings.Builder
107-
scale, err := r.Prefix.Float64()
108-
prefix := string(r.Prefix)
109-
if err != nil {
110-
prefix = ""
111-
scale = 1.0
36+
usedScaled, scale := humanize.ComputeSI(r.Used)
37+
usedPrec := 1
38+
if usedScaled >= 100.0 {
39+
usedPrec = 0
11240
}
113-
_, _ = sb.WriteString(strconv.FormatFloat(r.Used/scale, 'f', 1, 64))
41+
_, _ = sb.WriteString(strconv.FormatFloat(usedScaled, 'f', usedPrec, 64))
11442
if r.Total != (*float64)(nil) {
43+
// TODO(cian): handle case where scale of total is different to used
44+
totalScaled, _ := humanize.ComputeSI(*r.Total)
45+
totalPrec := 1
46+
if totalScaled >= 100.0 {
47+
totalPrec = 0
48+
}
11549
_, _ = sb.WriteString("/")
116-
_, _ = sb.WriteString(strconv.FormatFloat(*r.Total/scale, 'f', 1, 64))
50+
_, _ = sb.WriteString(strconv.FormatFloat(totalScaled, 'f', totalPrec, 64))
11751
}
52+
11853
if r.Unit != "" {
11954
_, _ = sb.WriteString(" ")
120-
_, _ = sb.WriteString(prefix)
55+
_, _ = sb.WriteString(scale)
12156
_, _ = sb.WriteString(r.Unit)
12257
}
123-
if r.Total != (*float64)(nil) && *r.Total != 0.0 {
58+
59+
if r.Total != nil && *r.Total != 0.0 {
12460
_, _ = sb.WriteString(" (")
125-
_, _ = sb.WriteString(strconv.FormatFloat(100.0*r.Used/(*r.Total), 'f', 0, 64))
61+
_, _ = sb.WriteString(strconv.FormatFloat(r.Used/(*r.Total)*100, 'f', 0, 64))
12662
_, _ = sb.WriteString("%)")
12763
}
64+
12865
return sb.String()
12966
}
13067

@@ -181,11 +118,10 @@ func New(opts ...Option) (*Statter, error) {
181118
// This is calculated by taking the difference between the total and idle HostCPU time
182119
// and scaling it by the number of cores.
183120
// Units are in "cores".
184-
func (s *Statter) HostCPU(m Prefix) (*Result, error) {
121+
func (s *Statter) HostCPU() (*Result, error) {
185122
r := &Result{
186-
Unit: "cores",
187-
Total: ptr.To(float64(s.nproc)),
188-
Prefix: m,
123+
Unit: "cores",
124+
Total: ptr.To(float64(s.nproc)),
189125
}
190126
c1, err := s.hi.CPUTime()
191127
if err != nil {
@@ -208,10 +144,9 @@ func (s *Statter) HostCPU(m Prefix) (*Result, error) {
208144
}
209145

210146
// HostMemory returns the memory usage of the host, in gigabytes.
211-
func (s *Statter) HostMemory(m Prefix) (*Result, error) {
147+
func (s *Statter) HostMemory() (*Result, error) {
212148
r := &Result{
213-
Unit: "B",
214-
Prefix: m,
149+
Unit: "B",
215150
}
216151
hm, err := s.hi.Memory()
217152
if err != nil {

cli/clistat/stat_internal_test.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,24 @@ func TestResultString(t *testing.T) {
2626
Result: Result{Used: 0.0, Total: ptr.To(0.0), Unit: "HP"},
2727
},
2828
{
29-
Expected: "123.0 seconds",
29+
Expected: "123 seconds",
3030
Result: Result{Used: 123.01, Total: nil, Unit: "seconds"},
3131
},
3232
{
3333
Expected: "12.3",
3434
Result: Result{Used: 12.34, Total: nil, Unit: ""},
3535
},
3636
{
37-
Expected: "1.5 KiB",
38-
Result: Result{Used: 1536, Total: nil, Unit: "B", Prefix: PrefixKibiShort},
37+
Expected: "1.5 kB",
38+
Result: Result{Used: 1536, Total: nil, Unit: "B"},
3939
},
4040
{
4141
Expected: "1.2 things",
42-
Result: Result{Used: 1.234, Total: nil, Unit: "things", Prefix: "invalid"},
42+
Result: Result{Used: 1.234, Total: nil, Unit: "things"},
4343
},
4444
{
45-
Expected: "0.0/100.0 TiB (0%)",
46-
Result: Result{Used: 1, Total: ptr.To(1024 * 1024 * 1024 * 1024 * 100.0), Unit: "B", Prefix: "Ti"},
45+
Expected: "0.0/100 TiB (0%)",
46+
Result: Result{Used: 1, Total: ptr.To(1000 * 1000 * 1000 * 1000 * 100.0), Unit: "B"},
4747
},
4848
} {
4949
assert.Equal(t, tt.Expected, tt.Result.String())
@@ -64,7 +64,7 @@ func TestStatter(t *testing.T) {
6464
require.NoError(t, err)
6565
t.Run("HostCPU", func(t *testing.T) {
6666
t.Parallel()
67-
cpu, err := s.HostCPU("")
67+
cpu, err := s.HostCPU()
6868
require.NoError(t, err)
6969
assert.NotZero(t, cpu.Used)
7070
assert.NotZero(t, cpu.Total)
@@ -73,7 +73,7 @@ func TestStatter(t *testing.T) {
7373

7474
t.Run("HostMemory", func(t *testing.T) {
7575
t.Parallel()
76-
mem, err := s.HostMemory("")
76+
mem, err := s.HostMemory()
7777
require.NoError(t, err)
7878
assert.NotZero(t, mem.Used)
7979
assert.NotZero(t, mem.Total)
@@ -82,7 +82,7 @@ func TestStatter(t *testing.T) {
8282

8383
t.Run("HostDisk", func(t *testing.T) {
8484
t.Parallel()
85-
disk, err := s.Disk("", "") // default to home dir
85+
disk, err := s.Disk("") // default to home dir
8686
require.NoError(t, err)
8787
assert.NotZero(t, disk.Used)
8888
assert.NotZero(t, disk.Total)
@@ -124,7 +124,7 @@ func TestStatter(t *testing.T) {
124124
}
125125
s, err := New(WithFS(fs), withWait(fakeWait))
126126
require.NoError(t, err)
127-
cpu, err := s.ContainerCPU("")
127+
cpu, err := s.ContainerCPU()
128128
require.NoError(t, err)
129129
require.NotNil(t, cpu)
130130
assert.Equal(t, 1.0, cpu.Used)
@@ -142,7 +142,7 @@ func TestStatter(t *testing.T) {
142142
}
143143
s, err := New(WithFS(fs), withNproc(2), withWait(fakeWait))
144144
require.NoError(t, err)
145-
cpu, err := s.ContainerCPU("")
145+
cpu, err := s.ContainerCPU()
146146
require.NoError(t, err)
147147
require.NotNil(t, cpu)
148148
assert.Equal(t, 1.0, cpu.Used)
@@ -156,7 +156,7 @@ func TestStatter(t *testing.T) {
156156
fs := initFS(t, fsContainerCgroupV1)
157157
s, err := New(WithFS(fs), withNoWait)
158158
require.NoError(t, err)
159-
mem, err := s.ContainerMemory("")
159+
mem, err := s.ContainerMemory()
160160
require.NoError(t, err)
161161
require.NotNil(t, mem)
162162
assert.Equal(t, 268435456.0, mem.Used)
@@ -177,7 +177,7 @@ func TestStatter(t *testing.T) {
177177
}
178178
s, err := New(WithFS(fs), withWait(fakeWait))
179179
require.NoError(t, err)
180-
cpu, err := s.ContainerCPU("")
180+
cpu, err := s.ContainerCPU()
181181
require.NoError(t, err)
182182
require.NotNil(t, cpu)
183183
assert.Equal(t, 1.0, cpu.Used)
@@ -194,7 +194,7 @@ func TestStatter(t *testing.T) {
194194
}
195195
s, err := New(WithFS(fs), withNproc(2), withWait(fakeWait))
196196
require.NoError(t, err)
197-
cpu, err := s.ContainerCPU("")
197+
cpu, err := s.ContainerCPU()
198198
require.NoError(t, err)
199199
require.NotNil(t, cpu)
200200
assert.Equal(t, 1.0, cpu.Used)
@@ -208,7 +208,7 @@ func TestStatter(t *testing.T) {
208208
fs := initFS(t, fsContainerCgroupV2)
209209
s, err := New(WithFS(fs), withNoWait)
210210
require.NoError(t, err)
211-
mem, err := s.ContainerMemory("")
211+
mem, err := s.ContainerMemory()
212212
require.NoError(t, err)
213213
require.NotNil(t, mem)
214214
assert.Equal(t, 268435456.0, mem.Used)

0 commit comments

Comments
 (0)