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:
@ -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", ""})
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user