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:
@@ -19,6 +19,7 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/bubbles/spinner"
|
||||
@@ -41,7 +42,8 @@ type speedTestUI struct {
|
||||
|
||||
type speedTestResult struct {
|
||||
final bool
|
||||
result madmin.SpeedTestResult
|
||||
result *madmin.SpeedTestResult
|
||||
nresult *madmin.NetperfResult
|
||||
}
|
||||
|
||||
func initSpeedTestUI() *speedTestUI {
|
||||
@@ -100,8 +102,11 @@ func (m *speedTestUI) View() string {
|
||||
table.SetBorder(false)
|
||||
table.SetTablePadding("\t") // pad with tabs
|
||||
table.SetNoWhiteSpace(true)
|
||||
res := m.result.result
|
||||
|
||||
res := m.result.result
|
||||
nres := m.result.nresult
|
||||
|
||||
if res != nil {
|
||||
table.SetHeader([]string{"", "Throughput", "IOPS"})
|
||||
data := make([][]string, 2)
|
||||
|
||||
@@ -131,9 +136,7 @@ func (m *speedTestUI) View() string {
|
||||
table.AppendBulk(data)
|
||||
table.Render()
|
||||
|
||||
if !m.quitting {
|
||||
s.WriteString(fmt.Sprintf("\nSpeedtest: %s", m.spinner.View()))
|
||||
} else {
|
||||
if m.quitting {
|
||||
s.WriteString(fmt.Sprintf("\nSpeedtest: %s", m.result.String()))
|
||||
if vstr := m.result.StringVerbose(); vstr != "" {
|
||||
s.WriteString(vstr)
|
||||
@@ -141,5 +144,45 @@ func (m *speedTestUI) View() string {
|
||||
s.WriteString("\n")
|
||||
}
|
||||
}
|
||||
} else if nres != nil {
|
||||
table.SetHeader([]string{"Node", "RX", "TX", ""})
|
||||
data := make([][]string, 0, len(nres.NodeResults))
|
||||
|
||||
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)),
|
||||
"✔",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(data, func(i, j int) bool {
|
||||
return data[i][0] < data[j][0]
|
||||
})
|
||||
|
||||
table.AppendBulk(data)
|
||||
table.Render()
|
||||
|
||||
if m.quitting {
|
||||
s.WriteString("\nNetperf: ✔\n")
|
||||
}
|
||||
}
|
||||
if !m.quitting {
|
||||
if nres != nil {
|
||||
s.WriteString(fmt.Sprintf("\nNetperf: %s", m.spinner.View()))
|
||||
} else if res != nil {
|
||||
s.WriteString(fmt.Sprintf("\nSpeedtest: %s", m.spinner.View()))
|
||||
}
|
||||
}
|
||||
return s.String()
|
||||
}
|
||||
|
@@ -19,12 +19,10 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/briandowns/spinner"
|
||||
humanize "github.com/dustin/go-humanize"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/minio/cli"
|
||||
json "github.com/minio/colorjson"
|
||||
"github.com/minio/madmin-go"
|
||||
@@ -34,15 +32,8 @@ import (
|
||||
type netperfResult madmin.NetperfResult
|
||||
|
||||
func (m netperfResult) String() (msg string) {
|
||||
for _, r := range m.NodeResults {
|
||||
msg += fmt.Sprintf("%s TX: %s/s RX: %s/s", r.Endpoint, humanize.IBytes(uint64(r.TX)), humanize.IBytes(uint64(r.RX)))
|
||||
if r.Error != "" {
|
||||
msg += " Error: " + r.Error
|
||||
}
|
||||
msg += "\n"
|
||||
}
|
||||
msg = strings.TrimSuffix(msg, "\n")
|
||||
return msg
|
||||
// string version is handled by banner.
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m netperfResult) JSON() string {
|
||||
@@ -71,15 +62,54 @@ func mainAdminSpeedtestNetperf(ctx *cli.Context, aliasedURL string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
s := spinner.New(spinner.CharSets[14], 100*time.Millisecond)
|
||||
|
||||
if !globalJSON {
|
||||
s.Start()
|
||||
}
|
||||
|
||||
resultCh := make(chan madmin.NetperfResult)
|
||||
go func() {
|
||||
result, err := client.Netperf(ctxt, duration)
|
||||
s.Stop()
|
||||
fatalIf(probe.NewError(err), "Failed to execute netperf")
|
||||
fatalIf(probe.NewError(err), "Unable to capture network perf results")
|
||||
|
||||
resultCh <- result
|
||||
close(resultCh)
|
||||
}()
|
||||
|
||||
if globalJSON {
|
||||
for {
|
||||
select {
|
||||
case result := <-resultCh:
|
||||
printMsg(netperfResult(result))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
|
||||
p := tea.NewProgram(initSpeedTestUI())
|
||||
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
|
||||
}
|
@@ -105,7 +105,6 @@ EXAMPLES:
|
||||
|
||||
5. Run network throughput test:
|
||||
{{.Prompt}} {{.HelpName}} net myminio
|
||||
|
||||
`,
|
||||
}
|
||||
|
||||
@@ -231,7 +230,7 @@ func mainSupportPerf(ctx *cli.Context) error {
|
||||
continue
|
||||
}
|
||||
printMsg(speedTestResult{
|
||||
result: result,
|
||||
result: &result,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
@@ -250,15 +249,12 @@ func mainSupportPerf(ctx *cli.Context) error {
|
||||
go func() {
|
||||
var result madmin.SpeedTestResult
|
||||
for result = range resultCh {
|
||||
if result.Version == "" {
|
||||
continue
|
||||
}
|
||||
p.Send(speedTestResult{
|
||||
result: result,
|
||||
result: &result,
|
||||
})
|
||||
}
|
||||
p.Send(speedTestResult{
|
||||
result: result,
|
||||
result: &result,
|
||||
final: true,
|
||||
})
|
||||
}()
|
||||
|
Reference in New Issue
Block a user