mirror of https://github.com/docker/cli.git
Merge pull request #3608 from thaJeztah/formatstats_optimize
Small performance optimizations for formatting stats
This commit is contained in:
commit
53f8ed4bec
|
@ -1,7 +1,7 @@
|
||||||
package container
|
package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/docker/cli/cli/command/formatter"
|
"github.com/docker/cli/cli/command/formatter"
|
||||||
|
@ -43,7 +43,7 @@ type StatsEntry struct {
|
||||||
|
|
||||||
// Stats represents an entity to store containers statistics synchronously
|
// Stats represents an entity to store containers statistics synchronously
|
||||||
type Stats struct {
|
type Stats struct {
|
||||||
mutex sync.Mutex
|
mutex sync.RWMutex
|
||||||
StatsEntry
|
StatsEntry
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
@ -51,8 +51,8 @@ type Stats struct {
|
||||||
// GetError returns the container statistics error.
|
// GetError returns the container statistics error.
|
||||||
// This is used to determine whether the statistics are valid or not
|
// This is used to determine whether the statistics are valid or not
|
||||||
func (cs *Stats) GetError() error {
|
func (cs *Stats) GetError() error {
|
||||||
cs.mutex.Lock()
|
cs.mutex.RLock()
|
||||||
defer cs.mutex.Unlock()
|
defer cs.mutex.RUnlock()
|
||||||
return cs.err
|
return cs.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,8 +94,8 @@ func (cs *Stats) SetStatistics(s StatsEntry) {
|
||||||
|
|
||||||
// GetStatistics returns container statistics with other meta data such as the container name
|
// GetStatistics returns container statistics with other meta data such as the container name
|
||||||
func (cs *Stats) GetStatistics() StatsEntry {
|
func (cs *Stats) GetStatistics() StatsEntry {
|
||||||
cs.mutex.Lock()
|
cs.mutex.RLock()
|
||||||
defer cs.mutex.Unlock()
|
defer cs.mutex.RUnlock()
|
||||||
return cs.StatsEntry
|
return cs.StatsEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ func (c *statsContext) CPUPerc() string {
|
||||||
if c.s.IsInvalid {
|
if c.s.IsInvalid {
|
||||||
return "--"
|
return "--"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%.2f%%", c.s.CPUPercentage)
|
return formatPercentage(c.s.CPUPercentage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *statsContext) MemUsage() string {
|
func (c *statsContext) MemUsage() string {
|
||||||
|
@ -193,33 +193,37 @@ func (c *statsContext) MemUsage() string {
|
||||||
if c.os == winOSType {
|
if c.os == winOSType {
|
||||||
return units.BytesSize(c.s.Memory)
|
return units.BytesSize(c.s.Memory)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s / %s", units.BytesSize(c.s.Memory), units.BytesSize(c.s.MemoryLimit))
|
return units.BytesSize(c.s.Memory) + " / " + units.BytesSize(c.s.MemoryLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *statsContext) MemPerc() string {
|
func (c *statsContext) MemPerc() string {
|
||||||
if c.s.IsInvalid || c.os == winOSType {
|
if c.s.IsInvalid || c.os == winOSType {
|
||||||
return "--"
|
return "--"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%.2f%%", c.s.MemoryPercentage)
|
return formatPercentage(c.s.MemoryPercentage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *statsContext) NetIO() string {
|
func (c *statsContext) NetIO() string {
|
||||||
if c.s.IsInvalid {
|
if c.s.IsInvalid {
|
||||||
return "--"
|
return "--"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s / %s", units.HumanSizeWithPrecision(c.s.NetworkRx, 3), units.HumanSizeWithPrecision(c.s.NetworkTx, 3))
|
return units.HumanSizeWithPrecision(c.s.NetworkRx, 3) + " / " + units.HumanSizeWithPrecision(c.s.NetworkTx, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *statsContext) BlockIO() string {
|
func (c *statsContext) BlockIO() string {
|
||||||
if c.s.IsInvalid {
|
if c.s.IsInvalid {
|
||||||
return "--"
|
return "--"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s / %s", units.HumanSizeWithPrecision(c.s.BlockRead, 3), units.HumanSizeWithPrecision(c.s.BlockWrite, 3))
|
return units.HumanSizeWithPrecision(c.s.BlockRead, 3) + " / " + units.HumanSizeWithPrecision(c.s.BlockWrite, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *statsContext) PIDs() string {
|
func (c *statsContext) PIDs() string {
|
||||||
if c.s.IsInvalid || c.os == winOSType {
|
if c.s.IsInvalid || c.os == winOSType {
|
||||||
return "--"
|
return "--"
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%d", c.s.PidsCurrent)
|
return strconv.FormatUint(c.s.PidsCurrent, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatPercentage(val float64) string {
|
||||||
|
return strconv.FormatFloat(val, 'f', 2, 64) + "%"
|
||||||
}
|
}
|
||||||
|
|
|
@ -308,3 +308,38 @@ func TestContainerStatsContextWriteTrunc(t *testing.T) {
|
||||||
out.Reset()
|
out.Reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkStatsFormat(b *testing.B) {
|
||||||
|
b.ReportAllocs()
|
||||||
|
stats := genStats()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for _, s := range stats {
|
||||||
|
_ = s.CPUPerc()
|
||||||
|
_ = s.MemUsage()
|
||||||
|
_ = s.MemPerc()
|
||||||
|
_ = s.NetIO()
|
||||||
|
_ = s.BlockIO()
|
||||||
|
_ = s.PIDs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func genStats() []statsContext {
|
||||||
|
entry := statsContext{s: StatsEntry{
|
||||||
|
CPUPercentage: 12.3456789,
|
||||||
|
Memory: 123.456789,
|
||||||
|
MemoryLimit: 987.654321,
|
||||||
|
MemoryPercentage: 12.3456789,
|
||||||
|
BlockRead: 123.456789,
|
||||||
|
BlockWrite: 987.654321,
|
||||||
|
NetworkRx: 123.456789,
|
||||||
|
NetworkTx: 987.654321,
|
||||||
|
PidsCurrent: 123456789,
|
||||||
|
}}
|
||||||
|
stats := make([]statsContext, 100)
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
stats = append(stats, entry)
|
||||||
|
}
|
||||||
|
return stats
|
||||||
|
}
|
||||||
|
|
|
@ -184,13 +184,13 @@ func runStats(dockerCli command.Cli, opts *statsOptions) error {
|
||||||
waitFirst.Wait()
|
waitFirst.Wait()
|
||||||
|
|
||||||
var errs []string
|
var errs []string
|
||||||
cStats.mu.Lock()
|
cStats.mu.RLock()
|
||||||
for _, c := range cStats.cs {
|
for _, c := range cStats.cs {
|
||||||
if err := c.GetError(); err != nil {
|
if err := c.GetError(); err != nil {
|
||||||
errs = append(errs, err.Error())
|
errs = append(errs, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cStats.mu.Unlock()
|
cStats.mu.RUnlock()
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return errors.New(strings.Join(errs, "\n"))
|
return errors.New(strings.Join(errs, "\n"))
|
||||||
}
|
}
|
||||||
|
@ -221,11 +221,11 @@ func runStats(dockerCli command.Cli, opts *statsOptions) error {
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
cleanScreen()
|
cleanScreen()
|
||||||
ccstats := []StatsEntry{}
|
ccstats := []StatsEntry{}
|
||||||
cStats.mu.Lock()
|
cStats.mu.RLock()
|
||||||
for _, c := range cStats.cs {
|
for _, c := range cStats.cs {
|
||||||
ccstats = append(ccstats, c.GetStatistics())
|
ccstats = append(ccstats, c.GetStatistics())
|
||||||
}
|
}
|
||||||
cStats.mu.Unlock()
|
cStats.mu.RUnlock()
|
||||||
if err = statsFormatWrite(statsCtx, ccstats, daemonOSType, !opts.noTrunc); err != nil {
|
if err = statsFormatWrite(statsCtx, ccstats, daemonOSType, !opts.noTrunc); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type stats struct {
|
type stats struct {
|
||||||
mu sync.Mutex
|
mu sync.RWMutex
|
||||||
cs []*Stats
|
cs []*Stats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue