1
0
mirror of https://github.com/minio/mc.git synced 2025-07-30 07:23:03 +03:00

support perf to execute all speed tests (#4158)

This commit will make `mc support perf <alias>` to execute all
performance tests, networking, drive and object speed tests.

perf will only have --duration and --verbose flags.

The user can still test with 'drive', 'object', and 'net' but they will
be hidden for now along with their flags.
This commit is contained in:
Anis Elleuch
2022-07-24 02:58:57 +01:00
committed by GitHub
parent 95e6947f9c
commit 657b6315fc
3 changed files with 131 additions and 131 deletions

View File

@ -146,12 +146,13 @@ func (m *speedTestUI) View() string {
table.Render()
if m.quitting {
s.WriteString(fmt.Sprintf("\nSpeedtest: %s", m.result.String()))
s.WriteString("\n" + m.result.String())
if vstr := m.result.StringVerbose(); vstr != "" {
s.WriteString(vstr)
s.WriteString(vstr + "\n")
} else {
s.WriteString("\n")
}
s.WriteString("Objectperf: ✔\n")
}
} else if nres != nil {
table.SetHeader([]string{"Node", "RX", "TX", ""})

View File

@ -18,7 +18,15 @@
package cmd
import (
"context"
"os"
"time"
tea "github.com/charmbracelet/bubbletea"
humanize "github.com/dustin/go-humanize"
"github.com/minio/cli"
"github.com/minio/madmin-go"
"github.com/minio/mc/pkg/probe"
"github.com/minio/pkg/console"
)
@ -37,3 +45,91 @@ func mainAdminSpeedtest(ctx *cli.Context) error {
console.Infoln("Please use 'mc support perf'")
return nil
}
func mainAdminSpeedTestObject(ctx *cli.Context, aliasedURL string) error {
client, perr := newAdminClient(aliasedURL)
if perr != nil {
fatalIf(perr.Trace(aliasedURL), "Unable to initialize admin client.")
return nil
}
ctxt, cancel := context.WithCancel(globalContext)
defer cancel()
duration, e := time.ParseDuration(ctx.String("duration"))
if e != nil {
fatalIf(probe.NewError(e), "Unable to parse duration")
return nil
}
if duration <= 0 {
fatalIf(errInvalidArgument(), "duration cannot be 0 or negative")
return nil
}
size, e := humanize.ParseBytes(ctx.String("size"))
if e != nil {
fatalIf(probe.NewError(e), "Unable to parse object size")
return nil
}
if size < 0 {
fatalIf(errInvalidArgument(), "size is expected to be atleast 0 bytes")
return nil
}
concurrent := ctx.Int("concurrent")
if concurrent <= 0 {
fatalIf(errInvalidArgument(), "concurrency cannot be '0' or negative")
return nil
}
globalPerfTestVerbose = ctx.Bool("verbose")
// Turn-off autotuning only when "concurrent" is specified
// in all other scenarios keep auto-tuning on.
autotune := !ctx.IsSet("concurrent")
resultCh, err := client.Speedtest(ctxt, madmin.SpeedtestOpts{
Size: int(size),
Duration: duration,
Concurrency: concurrent,
Autotune: autotune,
Bucket: ctx.String("bucket"), // This is a hidden flag.
})
fatalIf(probe.NewError(err), "Failed to execute performance test")
if globalJSON {
for result := range resultCh {
if result.Version == "" {
continue
}
printMsg(speedTestResult{
result: &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() {
var result madmin.SpeedTestResult
for result = range resultCh {
p.Send(speedTestResult{
result: &result,
})
}
p.Send(speedTestResult{
result: &result,
final: true,
})
}()
<-done
return nil
}

View File

@ -18,16 +18,11 @@
package cmd
import (
"context"
"fmt"
"os"
"time"
tea "github.com/charmbracelet/bubbletea"
humanize "github.com/dustin/go-humanize"
"github.com/minio/cli"
json "github.com/minio/colorjson"
"github.com/minio/madmin-go"
"github.com/minio/mc/pkg/probe"
)
@ -37,39 +32,44 @@ var supportPerfFlags = []cli.Flag{
Usage: "duration the entire perf tests are run",
Value: "10s",
},
cli.BoolFlag{
Name: "verbose, v",
Usage: "display per-server stats",
},
cli.StringFlag{
Name: "size",
Usage: "size of the object used for uploads/downloads",
Value: "64MiB",
Hidden: true,
},
cli.IntFlag{
Name: "concurrent",
Usage: "number of concurrent requests per server",
Value: 32,
Hidden: true,
},
cli.StringFlag{
Name: "bucket",
Usage: "provide a custom bucket name to use (NOTE: bucket must be created prior)",
Hidden: true, // Hidden for now.
},
cli.BoolFlag{
Name: "verbose, v",
Usage: "display per-server stats",
},
// Drive test specific flags.
cli.StringFlag{
Name: "filesize",
Usage: "total amount of data read/written to each drive",
Value: "1GiB",
Hidden: true,
},
cli.StringFlag{
Name: "blocksize",
Usage: "read/write block size",
Value: "4MiB",
Hidden: true,
},
cli.BoolFlag{
Name: "serial",
Usage: "run tests on drive(s) one-by-one",
Hidden: true,
},
}
@ -87,30 +87,14 @@ var supportPerfCmd = cli.Command{
USAGE:
{{.HelpName}} [COMMAND] [FLAGS] TARGET
COMMAND:
drive measure speed of drive in a cluster
object measure speed of reading and writing object in a cluster
net measure network throughput of all nodes
FLAGS:
{{range .VisibleFlags}}{{.}}
{{end}}
EXAMPLES:
1. Run object speed measurement with autotuning the concurrency to obtain maximum throughput and IOPs:
{{.Prompt}} {{.HelpName}} object myminio/
1. Run performance tests on 'myminio' cluster: networking, drive speed and:
{{.Prompt}} {{.HelpName}} myminio/
2. Run object speed measurement for 20 seconds with object size of 128MiB with autotuning the concurrency to obtain maximum throughput:
{{.Prompt}} {{.HelpName}} object myminio/ --duration 20s --size 128MiB
3. Run drive speed measurements on all drive on all nodes (with default blockSize of 4MiB):
{{.Prompt}} {{.HelpName}} drive myminio/
4. Run drive speed measurements with blocksize of 64KiB, and 2GiB of data read/written from each drive:
{{.Prompt}} {{.HelpName}} drive myminio/ --blocksize 64KiB --filesize 2GiB
5. Run network throughput test:
{{.Prompt}} {{.HelpName}} net myminio
`,
}
@ -165,19 +149,22 @@ func mainSupportPerf(ctx *cli.Context) error {
switch len(args) {
case 1:
// cannot use alias by the name 'drive' or 'net'
if args[0] == "drive" || args[0] == "net" {
if args[0] == "drive" || args[0] == "net" || args[0] == "object" {
cli.ShowCommandHelpAndExit(ctx, "perf", 1)
}
aliasedURL = args[0]
mainAdminSpeedTestNetperf(ctx, aliasedURL)
mainAdminSpeedTestDrive(ctx, aliasedURL)
mainAdminSpeedTestObject(ctx, aliasedURL)
case 2:
aliasedURL := args[1]
switch args[0] {
case "drive":
aliasedURL = args[1]
return mainAdminSpeedTestDrive(ctx, aliasedURL)
case "object":
aliasedURL = args[1]
return mainAdminSpeedTestObject(ctx, aliasedURL)
case "net":
aliasedURL = args[1]
return mainAdminSpeedTestNetperf(ctx, aliasedURL)
default:
cli.ShowCommandHelpAndExit(ctx, "perf", 1) // last argument is exit code
@ -186,89 +173,5 @@ func mainSupportPerf(ctx *cli.Context) error {
cli.ShowCommandHelpAndExit(ctx, "perf", 1) // last argument is exit code
}
client, perr := newAdminClient(aliasedURL)
if perr != nil {
fatalIf(perr.Trace(aliasedURL), "Unable to initialize admin client.")
return nil
}
ctxt, cancel := context.WithCancel(globalContext)
defer cancel()
duration, e := time.ParseDuration(ctx.String("duration"))
if e != nil {
fatalIf(probe.NewError(e), "Unable to parse duration")
return nil
}
if duration <= 0 {
fatalIf(errInvalidArgument(), "duration cannot be 0 or negative")
return nil
}
size, e := humanize.ParseBytes(ctx.String("size"))
if e != nil {
fatalIf(probe.NewError(e), "Unable to parse object size")
return nil
}
if size < 0 {
fatalIf(errInvalidArgument(), "size is expected to be atleast 0 bytes")
return nil
}
concurrent := ctx.Int("concurrent")
if concurrent <= 0 {
fatalIf(errInvalidArgument(), "concurrency cannot be '0' or negative")
return nil
}
globalPerfTestVerbose = ctx.Bool("verbose")
// Turn-off autotuning only when "concurrent" is specified
// in all other scenarios keep auto-tuning on.
autotune := !ctx.IsSet("concurrent")
resultCh, err := client.Speedtest(ctxt, madmin.SpeedtestOpts{
Size: int(size),
Duration: duration,
Concurrency: concurrent,
Autotune: autotune,
Bucket: ctx.String("bucket"), // This is a hidden flag.
})
fatalIf(probe.NewError(err), "Failed to execute performance test")
if globalJSON {
for result := range resultCh {
if result.Version == "" {
continue
}
printMsg(speedTestResult{
result: &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() {
var result madmin.SpeedTestResult
for result = range resultCh {
p.Send(speedTestResult{
result: &result,
})
}
p.Send(speedTestResult{
result: &result,
final: true,
})
}()
<-done
return nil
}