1
0
mirror of https://github.com/minio/mc.git synced 2025-08-09 13:22:43 +03:00

improve UI for netperf inspired from object perf test (#4117)

Refer for the behavior https://asciinema.org/a/501270
This commit is contained in:
Harshavardhana
2022-06-13 04:17:28 -07:00
committed by GitHub
parent fc64e84829
commit 36d5749991
5 changed files with 128 additions and 59 deletions

View File

@@ -19,6 +19,7 @@ package cmd
import ( import (
"fmt" "fmt"
"sort"
"strings" "strings"
"github.com/charmbracelet/bubbles/spinner" "github.com/charmbracelet/bubbles/spinner"
@@ -40,8 +41,9 @@ type speedTestUI struct {
} }
type speedTestResult struct { type speedTestResult struct {
final bool final bool
result madmin.SpeedTestResult result *madmin.SpeedTestResult
nresult *madmin.NetperfResult
} }
func initSpeedTestUI() *speedTestUI { func initSpeedTestUI() *speedTestUI {
@@ -100,45 +102,86 @@ func (m *speedTestUI) View() string {
table.SetBorder(false) table.SetBorder(false)
table.SetTablePadding("\t") // pad with tabs table.SetTablePadding("\t") // pad with tabs
table.SetNoWhiteSpace(true) table.SetNoWhiteSpace(true)
res := m.result.result res := m.result.result
nres := m.result.nresult
table.SetHeader([]string{"", "Throughput", "IOPS"}) if res != nil {
data := make([][]string, 2) table.SetHeader([]string{"", "Throughput", "IOPS"})
data := make([][]string, 2)
if res.Version == "" { if res.Version == "" {
data[0] = []string{ data[0] = []string{
"PUT", "PUT",
whiteStyle.Render("-- KiB/sec"), whiteStyle.Render("-- KiB/sec"),
whiteStyle.Render("-- objs/sec"), whiteStyle.Render("-- objs/sec"),
}
data[1] = []string{
"GET",
whiteStyle.Render("-- KiB/sec"),
whiteStyle.Render("-- objs/sec"),
}
} else {
data[0] = []string{
"PUT",
whiteStyle.Render(humanize.IBytes(res.PUTStats.ThroughputPerSec) + "/s"),
whiteStyle.Render(humanize.Comma(int64(res.PUTStats.ObjectsPerSec)) + " objs/s"),
}
data[1] = []string{
"GET",
whiteStyle.Render(humanize.IBytes(res.GETStats.ThroughputPerSec) + "/s"),
whiteStyle.Render(humanize.Comma(int64(res.GETStats.ObjectsPerSec)) + " objs/s"),
}
} }
data[1] = []string{ table.AppendBulk(data)
"GET", table.Render()
whiteStyle.Render("-- KiB/sec"),
whiteStyle.Render("-- objs/sec"), if m.quitting {
s.WriteString(fmt.Sprintf("\nSpeedtest: %s", m.result.String()))
if vstr := m.result.StringVerbose(); vstr != "" {
s.WriteString(vstr)
} else {
s.WriteString("\n")
}
} }
} else { } else if nres != nil {
data[0] = []string{ table.SetHeader([]string{"Node", "RX", "TX", ""})
"PUT", data := make([][]string, 0, len(nres.NodeResults))
whiteStyle.Render(humanize.IBytes(res.PUTStats.ThroughputPerSec) + "/s"),
whiteStyle.Render(humanize.Comma(int64(res.PUTStats.ObjectsPerSec)) + " objs/s"), for _, nodeResult := range nres.NodeResults {
if nodeResult.Error != "" {
data = append(data, []string{
nodeResult.Endpoint,
"✗",
"✗",
"Err: " + nodeResult.Error,
})
} else {
data = append(data, []string{
nodeResult.Endpoint,
humanize.IBytes(uint64(nodeResult.RX)),
humanize.IBytes(uint64(nodeResult.TX)),
"✔",
})
}
} }
data[1] = []string{
"GET", sort.Slice(data, func(i, j int) bool {
whiteStyle.Render(humanize.IBytes(res.GETStats.ThroughputPerSec) + "/s"), return data[i][0] < data[j][0]
whiteStyle.Render(humanize.Comma(int64(res.GETStats.ObjectsPerSec)) + " objs/s"), })
table.AppendBulk(data)
table.Render()
if m.quitting {
s.WriteString("\nNetperf: ✔\n")
} }
} }
table.AppendBulk(data)
table.Render()
if !m.quitting { if !m.quitting {
s.WriteString(fmt.Sprintf("\nSpeedtest: %s", m.spinner.View())) if nres != nil {
} else { s.WriteString(fmt.Sprintf("\nNetperf: %s", m.spinner.View()))
s.WriteString(fmt.Sprintf("\nSpeedtest: %s", m.result.String())) } else if res != nil {
if vstr := m.result.StringVerbose(); vstr != "" { s.WriteString(fmt.Sprintf("\nSpeedtest: %s", m.spinner.View()))
s.WriteString(vstr)
} else {
s.WriteString("\n")
} }
} }
return s.String() return s.String()

View File

@@ -19,12 +19,10 @@ package cmd
import ( import (
"context" "context"
"fmt" "os"
"strings"
"time" "time"
"github.com/briandowns/spinner" tea "github.com/charmbracelet/bubbletea"
humanize "github.com/dustin/go-humanize"
"github.com/minio/cli" "github.com/minio/cli"
json "github.com/minio/colorjson" json "github.com/minio/colorjson"
"github.com/minio/madmin-go" "github.com/minio/madmin-go"
@@ -34,15 +32,8 @@ import (
type netperfResult madmin.NetperfResult type netperfResult madmin.NetperfResult
func (m netperfResult) String() (msg string) { func (m netperfResult) String() (msg string) {
for _, r := range m.NodeResults { // string version is handled by banner.
msg += fmt.Sprintf("%s TX: %s/s RX: %s/s", r.Endpoint, humanize.IBytes(uint64(r.TX)), humanize.IBytes(uint64(r.RX))) return ""
if r.Error != "" {
msg += " Error: " + r.Error
}
msg += "\n"
}
msg = strings.TrimSuffix(msg, "\n")
return msg
} }
func (m netperfResult) JSON() string { func (m netperfResult) JSON() string {
@@ -71,15 +62,54 @@ func mainAdminSpeedtestNetperf(ctx *cli.Context, aliasedURL string) error {
return nil return nil
} }
s := spinner.New(spinner.CharSets[14], 100*time.Millisecond) resultCh := make(chan madmin.NetperfResult)
go func() {
result, err := client.Netperf(ctxt, duration)
fatalIf(probe.NewError(err), "Unable to capture network perf results")
if !globalJSON { resultCh <- result
s.Start() close(resultCh)
}()
if globalJSON {
for {
select {
case result := <-resultCh:
printMsg(netperfResult(result))
return nil
}
}
} }
result, err := client.Netperf(ctxt, duration) done := make(chan struct{})
s.Stop()
fatalIf(probe.NewError(err), "Failed to execute netperf") p := tea.NewProgram(initSpeedTestUI())
printMsg(netperfResult(result)) go func() {
if e := p.Start(); e != nil {
os.Exit(1)
}
close(done)
}()
go func() {
for {
select {
case result := <-resultCh:
p.Send(speedTestResult{
nresult: &result,
final: true,
})
return
default:
p.Send(speedTestResult{
nresult: &madmin.NetperfResult{},
})
time.Sleep(100 * time.Millisecond)
}
}
}()
<-done
return nil return nil
} }

View File

@@ -105,7 +105,6 @@ EXAMPLES:
5. Run network throughput test: 5. Run network throughput test:
{{.Prompt}} {{.HelpName}} net myminio {{.Prompt}} {{.HelpName}} net myminio
`, `,
} }
@@ -231,7 +230,7 @@ func mainSupportPerf(ctx *cli.Context) error {
continue continue
} }
printMsg(speedTestResult{ printMsg(speedTestResult{
result: result, result: &result,
}) })
} }
return nil return nil
@@ -250,15 +249,12 @@ func mainSupportPerf(ctx *cli.Context) error {
go func() { go func() {
var result madmin.SpeedTestResult var result madmin.SpeedTestResult
for result = range resultCh { for result = range resultCh {
if result.Version == "" {
continue
}
p.Send(speedTestResult{ p.Send(speedTestResult{
result: result, result: &result,
}) })
} }
p.Send(speedTestResult{ p.Send(speedTestResult{
result: result, result: &result,
final: true, final: true,
}) })
}() }()