Skip to content

Commit

Permalink
feat: support perf client to show TX from client to server (#4645)
Browse files Browse the repository at this point in the history
  • Loading branch information
jiuker authored Aug 10, 2023
1 parent 01fb7c5 commit 44ca181
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 4 deletions.
28 changes: 28 additions & 0 deletions cmd/speedtest-spinner.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"sort"
"strings"
"time"

"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
Expand Down Expand Up @@ -49,6 +50,7 @@ const (
DrivePerfTest
ObjectPerfTest
SiteReplicationPerfTest
ClientPerfTest
)

// Name - returns name of the performance test
Expand All @@ -62,6 +64,8 @@ func (p PerfTestType) Name() string {
return "ObjectPerf"
case SiteReplicationPerfTest:
return "SiteReplication"
case ClientPerfTest:
return "Client"
}
return "<unknown>"
}
Expand All @@ -72,6 +76,7 @@ type PerfTestResult struct {
ObjectResult *madmin.SpeedTestResult `json:"object,omitempty"`
NetResult *madmin.NetperfResult `json:"network,omitempty"`
SiteReplicationResult *madmin.SiteNetPerfResult `json:"siteReplication,omitempty"`
ClientResult *madmin.ClientPerfResult `json:"client,omitempty"`
DriveResult []madmin.DriveSpeedTestResult `json:"drive,omitempty"`
Err string `json:"err,omitempty"`
Final bool `json:"final,omitempty"`
Expand Down Expand Up @@ -140,6 +145,7 @@ func (m *speedTestUI) View() string {
nres := m.result.NetResult
sres := m.result.SiteReplicationResult
dres := m.result.DriveResult
cres := m.result.ClientResult

trailerIfGreaterThan := func(in string, max int) string {
if len(in) < max {
Expand Down Expand Up @@ -318,6 +324,28 @@ func (m *speedTestUI) View() string {
}
table.AppendBulk(data)
table.Render()
} else if cres != nil {
table.SetHeader([]string{"Endpoint", "Tx"})
data := make([][]string, 0, 2)
tx := uint64(0)
if cres.TimeSpent > 0 {
tx = uint64(float64(cres.BytesSend) / time.Duration(cres.TimeSpent).Seconds())
}
if tx == 0 {
data = append(data, []string{
"...",
whiteStyle.Render("-- KiB/s"),
"",
})
} else {
data = append(data, []string{
cres.Endpoint,
whiteStyle.Render(humanize.IBytes(tx)) + "/s",
cres.Error,
})
}
table.AppendBulk(data)
table.Render()
}

return s.String()
Expand Down
130 changes: 130 additions & 0 deletions cmd/support-perf-client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Copyright (c) 2023 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package cmd

import (
"context"
"os"
"time"

tea "github.com/charmbracelet/bubbletea"
"github.com/minio/cli"
"github.com/minio/madmin-go/v3"
"github.com/minio/mc/pkg/probe"
)

func mainAdminSpeedTestClientPerf(ctx *cli.Context, aliasedURL string, outCh chan<- PerfTestResult) 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
}

resultCh := make(chan madmin.ClientPerfResult)
errorCh := make(chan error)
go func() {
defer close(resultCh)
defer close(errorCh)
result, e := client.ClientPerf(ctxt, duration)
if e != nil {
errorCh <- e
}
resultCh <- result
}()
if globalJSON {
var rsl PerfTestOutput
select {
case e := <-errorCh:
rsl = convertPerfResult(PerfTestResult{
Type: ClientPerfTest,
Err: e.Error(),
Final: true,
})
case result := <-resultCh:
rsl = convertPerfResult(PerfTestResult{
Type: ClientPerfTest,
ClientResult: &result,
Final: true,
})
}
printMsg(rsl)
return nil
}

done := make(chan struct{})

p := tea.NewProgram(initSpeedTestUI())
go func() {
if _, e := p.Run(); e != nil {
os.Exit(1)
}
close(done)
}()

go func() {
for {
select {
case e := <-errorCh:
r := PerfTestResult{
Type: ClientPerfTest,
Err: e.Error(),
Final: true,
}
p.Send(r)
if outCh != nil {
outCh <- r
}
return
case result := <-resultCh:
r := PerfTestResult{
Type: ClientPerfTest,
ClientResult: &result,
Final: true,
}
p.Send(r)
if outCh != nil {
outCh <- r
}
return
default:
p.Send(PerfTestResult{
Type: ClientPerfTest,
ClientResult: &madmin.ClientPerfResult{},
})
time.Sleep(100 * time.Millisecond)
}
}
}()

<-done

return nil
}
27 changes: 26 additions & 1 deletion cmd/support-perf.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ type PerfTestOutput struct {
NetResults *NetTestResults `json:"network,omitempty"`
SiteReplicationResults *SiteReplicationTestResults `json:"siteReplication,omitempty"`
DriveResults *DriveTestResults `json:"drive,omitempty"`
ClientResults *ClientResult `json:"client,omitempty"`
Error string `json:"error,omitempty"`
}

Expand Down Expand Up @@ -196,6 +197,14 @@ type NetTestResults struct {
Results []NetTestResult `json:"servers"`
}

// ClientResult - result of the network from client to server
type ClientResult struct {
BytesSent uint64 `json:"bytesSent"`
TimeSpent int64 `json:"timeSpent"`
Endpoint string `json:"endpoint"`
Error string `json:"error"`
}

// SiteNetStats - status for siteNet
type SiteNetStats struct {
TX uint64 `json:"tx"` // transfer rate in bytes
Expand Down Expand Up @@ -310,6 +319,18 @@ func convertDriveTestResults(driveResults []madmin.DriveSpeedTestResult) *DriveT
return &r
}

func convertClientResult(result *madmin.ClientPerfResult) *ClientResult {
if result == nil || result.TimeSpent <= 0 {
return nil
}
return &ClientResult{
BytesSent: result.BytesSend,
TimeSpent: result.TimeSpent,
Endpoint: result.Endpoint,
Error: result.Error,
}
}

func convertSiteReplicationTestResults(netResults *madmin.SiteNetPerfResult) *SiteReplicationTestResults {
if netResults == nil {
return nil
Expand Down Expand Up @@ -418,6 +439,8 @@ func updatePerfOutput(r PerfTestResult, out *PerfTestOutput) {
out.NetResults = convertNetTestResults(r.NetResult)
case SiteReplicationPerfTest:
out.SiteReplicationResults = convertSiteReplicationTestResults(r.SiteReplicationResult)
case ClientPerfTest:
out.ClientResults = convertClientResult(r.ClientResult)
default:
fatalIf(errDummy().Trace(), fmt.Sprintf("Invalid test type %d", r.Type))
}
Expand Down Expand Up @@ -496,7 +519,7 @@ func runPerfTests(ctx *cli.Context, aliasedURL, perfType string) []PerfTestResul
tests := []string{perfType}
if len(perfType) == 0 {
// by default run all tests
tests = []string{"net", "drive", "object"}
tests = []string{"net", "drive", "object", "client"}
}

for _, t := range tests {
Expand All @@ -509,6 +532,8 @@ func runPerfTests(ctx *cli.Context, aliasedURL, perfType string) []PerfTestResul
mainAdminSpeedTestNetperf(ctx, aliasedURL, resultCh)
case "site-replication":
mainAdminSpeedTestSiteReplication(ctx, aliasedURL, resultCh)
case "client":
mainAdminSpeedTestClientPerf(ctx, aliasedURL, resultCh)
default:
showCommandHelpAndExit(ctx, 1) // last argument is exit code
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ require (
github.com/gdamore/tcell/v2 v2.6.0
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/juju/ratelimit v1.0.2
github.com/minio/madmin-go/v3 v3.0.9
github.com/minio/madmin-go/v3 v3.0.11
github.com/muesli/reflow v0.3.0
github.com/navidys/tvxwidgets v0.3.0
github.com/olekukonko/tablewriter v0.0.5
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ github.com/minio/colorjson v1.0.5 h1:P//d521blE5cKDF5YvsHcpqb9TE8IwCdliSv1naPsgk
github.com/minio/colorjson v1.0.5/go.mod h1:Oq6oB83q+sL08u9wx68+91ELf0nV5G4c6l9pQcH5ElI=
github.com/minio/filepath v1.0.0 h1:fvkJu1+6X+ECRA6G3+JJETj4QeAYO9sV43I79H8ubDY=
github.com/minio/filepath v1.0.0/go.mod h1:/nRZA2ldl5z6jT9/KQuvZcQlxZIMQoFFQPvEXx9T/Bw=
github.com/minio/madmin-go/v3 v3.0.9 h1:Iel1A4Ab+MWEcX3xPrfmDGy/0z2l/PZkCNxmy/B/kHU=
github.com/minio/madmin-go/v3 v3.0.9/go.mod h1:lPrMoc1aeiIWmmrxBthkDqzMPQwC/Lu9ByuyM2wenJk=
github.com/minio/madmin-go/v3 v3.0.11 h1:7QrZkgbQ5+qTKGy6Nok2A8OgLAcn/lcMYYuSgiZrgBE=
github.com/minio/madmin-go/v3 v3.0.11/go.mod h1:DMXyWO670OXwZNN0v4ZrEodl9oLOcaPJIZhpoHpu7aw=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.61 h1:87c+x8J3jxQ5VUGimV9oHdpjsAvy3fhneEBKuoKEVUI=
Expand Down

0 comments on commit 44ca181

Please sign in to comment.