github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/support-perf-object.go (about) 1 // Copyright (c) 2015-2022 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "context" 22 "os" 23 "time" 24 25 tea "github.com/charmbracelet/bubbletea" 26 "github.com/dustin/go-humanize" 27 "github.com/minio/cli" 28 "github.com/minio/madmin-go/v3" 29 "github.com/minio/mc/pkg/probe" 30 ) 31 32 var adminSpeedtestCmd = cli.Command{ 33 Name: "speedtest", 34 Usage: "Run server side speed test", 35 Action: mainAdminSpeedtest, 36 OnUsageError: onUsageError, 37 Before: setGlobalsFromContext, 38 HideHelpCommand: true, 39 Hidden: true, 40 CustomHelpTemplate: "Please use 'mc support perf'", 41 } 42 43 func mainAdminSpeedtest(_ *cli.Context) error { 44 deprecatedError("mc support perf") 45 return nil 46 } 47 48 func mainAdminSpeedTestObject(ctx *cli.Context, aliasedURL string, outCh chan<- PerfTestResult) error { 49 client, perr := newAdminClient(aliasedURL) 50 if perr != nil { 51 fatalIf(perr.Trace(aliasedURL), "Unable to initialize admin client.") 52 return nil 53 } 54 55 ctxt, cancel := context.WithCancel(globalContext) 56 defer cancel() 57 58 duration, e := time.ParseDuration(ctx.String("duration")) 59 if e != nil { 60 fatalIf(probe.NewError(e), "Unable to parse duration") 61 return nil 62 } 63 if duration <= 0 { 64 fatalIf(errInvalidArgument(), "duration cannot be 0 or negative") 65 return nil 66 } 67 size, e := humanize.ParseBytes(ctx.String("size")) 68 if e != nil { 69 fatalIf(probe.NewError(e), "Unable to parse object size") 70 return nil 71 } 72 if size <= 0 { 73 fatalIf(errInvalidArgument(), "size is expected to be more than 0 bytes") 74 return nil 75 } 76 concurrent := ctx.Int("concurrent") 77 if concurrent <= 0 { 78 fatalIf(errInvalidArgument(), "concurrency cannot be '0' or negative") 79 return nil 80 } 81 globalPerfTestVerbose = ctx.Bool("verbose") 82 83 // Turn-off autotuning only when "concurrent" is specified 84 // in all other scenarios keep auto-tuning on. 85 autotune := !ctx.IsSet("concurrent") 86 87 resultCh, e := client.Speedtest(ctxt, madmin.SpeedtestOpts{ 88 Size: int(size), 89 Duration: duration, 90 Concurrency: concurrent, 91 Autotune: autotune, 92 Bucket: ctx.String("bucket"), // This is a hidden flag. 93 NoClear: ctx.Bool("noclear"), 94 }) 95 96 if globalJSON { 97 if e != nil { 98 printMsg(convertPerfResult(PerfTestResult{ 99 Type: ObjectPerfTest, 100 Err: e.Error(), 101 Final: true, 102 })) 103 return nil 104 } 105 106 var result madmin.SpeedTestResult 107 for result = range resultCh { 108 if result.Version == "" { 109 continue 110 } 111 } 112 113 printMsg(convertPerfResult(PerfTestResult{ 114 Type: ObjectPerfTest, 115 ObjectResult: &result, 116 Final: true, 117 })) 118 119 return nil 120 } 121 122 done := make(chan struct{}) 123 124 p := tea.NewProgram(initSpeedTestUI()) 125 go func() { 126 if _, e := p.Run(); e != nil { 127 os.Exit(1) 128 } 129 close(done) 130 }() 131 132 go func() { 133 if e != nil { 134 r := PerfTestResult{ 135 Type: ObjectPerfTest, 136 Err: e.Error(), 137 Final: true, 138 } 139 p.Send(r) 140 if outCh != nil { 141 outCh <- r 142 } 143 return 144 } 145 146 var result madmin.SpeedTestResult 147 for result = range resultCh { 148 p.Send(PerfTestResult{ 149 Type: ObjectPerfTest, 150 ObjectResult: &result, 151 }) 152 } 153 r := PerfTestResult{ 154 Type: ObjectPerfTest, 155 ObjectResult: &result, 156 Final: true, 157 } 158 p.Send(r) 159 if outCh != nil { 160 outCh <- r 161 } 162 }() 163 164 <-done 165 166 return nil 167 }