mirror of
https://github.com/kastenhq/kubestr.git
synced 2024-12-14 11:57:56 +00:00
Fio object parse and wait animation (#49)
* fio object and wait * fio types * UTs * missed a return * formatting * unneccessary sprintf * blah
This commit is contained in:
parent
f4feadc161
commit
40561bd5a3
7 changed files with 761 additions and 17 deletions
|
@ -167,7 +167,7 @@ func Fio(ctx context.Context, output, storageclass, size, namespace, jobName, fi
|
|||
}); err != nil {
|
||||
result = kubestr.MakeTestOutput(testName, kubestr.StatusError, err.Error(), fioResult)
|
||||
} else {
|
||||
result = kubestr.MakeTestOutput(testName, kubestr.StatusOK, fmt.Sprintf("\n%s\n", fioResult.Result), fioResult)
|
||||
result = kubestr.MakeTestOutput(testName, kubestr.StatusOK, fmt.Sprintf("\n%s", fioResult.Result.Print()), fioResult)
|
||||
}
|
||||
|
||||
if output == "json" {
|
||||
|
|
1
go.mod
1
go.mod
|
@ -7,6 +7,7 @@ replace github.com/graymeta/stow => github.com/kastenhq/stow v0.1.2-kasten
|
|||
require (
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/aws/aws-sdk-go v1.31.6 // indirect
|
||||
github.com/briandowns/spinner v1.12.0
|
||||
github.com/golang/mock v1.4.4
|
||||
github.com/google/go-cmp v0.4.1 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.3 // indirect
|
||||
|
|
5
go.sum
5
go.sum
|
@ -150,6 +150,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
|||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/briandowns/spinner v1.12.0 h1:72O0PzqGJb6G3KgrcIOtL/JAGGZ5ptOMCn9cUHmqsmw=
|
||||
github.com/briandowns/spinner v1.12.0/go.mod h1:QOuQk7x+EaDASo80FEXwlwiA+j/PPIcX3FScO+3/ZPQ=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
|
@ -224,6 +226,7 @@ github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi
|
|||
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
|
||||
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
|
@ -524,6 +527,7 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
|
|||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
|
@ -535,6 +539,7 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
|||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
|
|
|
@ -2,10 +2,13 @@ package fio
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/briandowns/spinner"
|
||||
kankube "github.com/kanisterio/kanister/pkg/kube"
|
||||
"github.com/kastenhq/kubestr/pkg/common"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -76,7 +79,7 @@ type RunFIOResult struct {
|
|||
Size string `json:"size,omitempty"`
|
||||
StorageClass *sv1.StorageClass `json:"storageClass,omitempty"`
|
||||
FioConfig string `json:"fioConfig,omitempty"`
|
||||
Result string `json:"result,omitempty"`
|
||||
Result FioResult `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
func (f *FIOrunner) RunFio(ctx context.Context, args *RunFIOArgs) (*RunFIOResult, error) {
|
||||
|
@ -138,7 +141,6 @@ func (f *FIOrunner) RunFioHelper(ctx context.Context, args *RunFIOArgs) (*RunFIO
|
|||
return nil, errors.Wrap(err, "Failed to create POD")
|
||||
}
|
||||
fmt.Println("Pod created", pod.Name)
|
||||
|
||||
fmt.Printf("Running FIO test (%s) on StorageClass (%s) with a PVC of Size (%s)\n", testFileName, args.StorageClass, args.Size)
|
||||
fioOutput, err := f.fioSteps.runFIOCommand(ctx, pod.Name, ContainerName, testFileName, args.Namespace)
|
||||
if err != nil {
|
||||
|
@ -160,7 +162,7 @@ type fioSteps interface {
|
|||
deletePVC(ctx context.Context, pvcName, namespace string) error
|
||||
createPod(ctx context.Context, pvcName, configMapName, testFileName, namespace string, image string) (*v1.Pod, error)
|
||||
deletePod(ctx context.Context, podName, namespace string) error
|
||||
runFIOCommand(ctx context.Context, podName, containerName, testFileName, namespace string) (string, error)
|
||||
runFIOCommand(ctx context.Context, podName, containerName, testFileName, namespace string) (FioResult, error)
|
||||
deleteConfigMap(ctx context.Context, configMap *v1.ConfigMap, namespace string) error
|
||||
}
|
||||
|
||||
|
@ -299,14 +301,41 @@ func (s *fioStepper) deletePod(ctx context.Context, podName, namespace string) e
|
|||
return s.cli.CoreV1().Pods(namespace).Delete(ctx, podName, metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
func (s *fioStepper) runFIOCommand(ctx context.Context, podName, containerName, testFileName, namespace string) (string, error) {
|
||||
func (s *fioStepper) runFIOCommand(ctx context.Context, podName, containerName, testFileName, namespace string) (FioResult, error) {
|
||||
jobFilePath := fmt.Sprintf("%s/%s", ConfigMapMountPath, testFileName)
|
||||
command := []string{"fio", "--directory", VolumeMountPath, jobFilePath}
|
||||
stdout, stderr, err := s.kubeExecutor.exec(namespace, podName, containerName, command)
|
||||
if err != nil || stderr != "" {
|
||||
return stdout, errors.Wrapf(err, "Error running command:(%v), stderr:(%s)", command, stderr)
|
||||
command := []string{"fio", "--directory", VolumeMountPath, jobFilePath, "--output-format=json"}
|
||||
done := make(chan bool, 1)
|
||||
var fioOut FioResult
|
||||
var stdout string
|
||||
var stderr string
|
||||
var err error
|
||||
timestart := time.Now()
|
||||
go func() {
|
||||
stdout, stderr, err = s.kubeExecutor.exec(namespace, podName, containerName, command)
|
||||
if err != nil || stderr != "" {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("stderr when running FIO")
|
||||
}
|
||||
err = errors.Wrapf(err, "Error running command:(%v), stderr:(%s)", command, stderr)
|
||||
}
|
||||
done <- true
|
||||
}()
|
||||
spin := spinner.New(spinner.CharSets[9], 100*time.Millisecond)
|
||||
spin.Start()
|
||||
<-done
|
||||
spin.Stop()
|
||||
elapsed := time.Since(timestart)
|
||||
fmt.Println("Elapsed time-", elapsed)
|
||||
if err != nil {
|
||||
return fioOut, err
|
||||
}
|
||||
return stdout, nil
|
||||
|
||||
err = json.Unmarshal([]byte(stdout), &fioOut)
|
||||
if err != nil {
|
||||
return fioOut, errors.Wrapf(err, "Unable to parse fio output into json.")
|
||||
}
|
||||
|
||||
return fioOut, nil
|
||||
}
|
||||
|
||||
// deleteConfigMap only deletes a config map if it has the label
|
||||
|
|
|
@ -2,6 +2,7 @@ package fio
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
@ -295,7 +296,7 @@ type fakeFioStepper struct {
|
|||
|
||||
dPodErr error
|
||||
|
||||
rFIOout string
|
||||
rFIOout FioResult
|
||||
rFIOErr error
|
||||
}
|
||||
|
||||
|
@ -332,7 +333,7 @@ func (f *fakeFioStepper) deletePod(ctx context.Context, podName, namespace strin
|
|||
f.steps = append(f.steps, "DPOD")
|
||||
return f.dPodErr
|
||||
}
|
||||
func (f *fakeFioStepper) runFIOCommand(ctx context.Context, podName, containerName, testFileName, namespace string) (string, error) {
|
||||
func (f *fakeFioStepper) runFIOCommand(ctx context.Context, podName, containerName, testFileName, namespace string) (FioResult, error) {
|
||||
f.steps = append(f.steps, "RFIOC")
|
||||
return f.rFIOout, f.rFIOErr
|
||||
}
|
||||
|
@ -693,6 +694,10 @@ func (s *FIOTestSuite) TestFioTestFileName(c *C) {
|
|||
}
|
||||
|
||||
func (s *FIOTestSuite) TestRunFioCommand(c *C) {
|
||||
var parsedout FioResult
|
||||
err := json.Unmarshal([]byte(parsableFioOutput), &parsedout)
|
||||
c.Assert(err, IsNil)
|
||||
|
||||
ctx := context.Background()
|
||||
for _, tc := range []struct {
|
||||
executor *fakeKubeExecutor
|
||||
|
@ -700,28 +705,55 @@ func (s *FIOTestSuite) TestRunFioCommand(c *C) {
|
|||
podName string
|
||||
containerName string
|
||||
testFileName string
|
||||
out FioResult
|
||||
}{
|
||||
{
|
||||
executor: &fakeKubeExecutor{
|
||||
keErr: nil,
|
||||
keStrErr: "",
|
||||
keStdOut: "success",
|
||||
keStdOut: parsableFioOutput,
|
||||
},
|
||||
errChecker: IsNil,
|
||||
podName: "pod",
|
||||
containerName: "container",
|
||||
testFileName: "tfName",
|
||||
out: parsedout,
|
||||
},
|
||||
{
|
||||
executor: &fakeKubeExecutor{
|
||||
keErr: fmt.Errorf("kubeexec err"),
|
||||
keErr: nil,
|
||||
keStrErr: "",
|
||||
keStdOut: "success",
|
||||
keStdOut: "unparsable string",
|
||||
},
|
||||
errChecker: NotNil,
|
||||
podName: "pod",
|
||||
containerName: "container",
|
||||
testFileName: "tfName",
|
||||
out: FioResult{},
|
||||
},
|
||||
{
|
||||
executor: &fakeKubeExecutor{
|
||||
keErr: fmt.Errorf("kubeexec err"),
|
||||
keStrErr: "",
|
||||
keStdOut: "unparsable string",
|
||||
},
|
||||
errChecker: NotNil,
|
||||
podName: "pod",
|
||||
containerName: "container",
|
||||
testFileName: "tfName",
|
||||
out: FioResult{},
|
||||
},
|
||||
{
|
||||
executor: &fakeKubeExecutor{
|
||||
keErr: nil,
|
||||
keStrErr: "execution error",
|
||||
keStdOut: "unparsable string",
|
||||
},
|
||||
errChecker: NotNil,
|
||||
podName: "pod",
|
||||
containerName: "container",
|
||||
testFileName: "tfName",
|
||||
out: FioResult{},
|
||||
},
|
||||
} {
|
||||
stepper := &fioStepper{
|
||||
|
@ -729,10 +761,10 @@ func (s *FIOTestSuite) TestRunFioCommand(c *C) {
|
|||
}
|
||||
out, err := stepper.runFIOCommand(ctx, tc.podName, tc.containerName, tc.testFileName, DefaultNS)
|
||||
c.Check(err, tc.errChecker)
|
||||
c.Assert(out, Equals, tc.executor.keStdOut)
|
||||
c.Assert(out, DeepEquals, tc.out)
|
||||
c.Assert(tc.executor.keInPodName, Equals, tc.podName)
|
||||
c.Assert(tc.executor.keInContainerName, Equals, tc.containerName)
|
||||
c.Assert(len(tc.executor.keInCommand), Equals, 4)
|
||||
c.Assert(len(tc.executor.keInCommand), Equals, 5)
|
||||
c.Assert(tc.executor.keInCommand[0], Equals, "fio")
|
||||
c.Assert(tc.executor.keInCommand[1], Equals, "--directory")
|
||||
c.Assert(tc.executor.keInCommand[2], Equals, VolumeMountPath)
|
||||
|
|
186
pkg/fio/fio_types.go
Normal file
186
pkg/fio/fio_types.go
Normal file
|
@ -0,0 +1,186 @@
|
|||
package fio
|
||||
|
||||
import "fmt"
|
||||
|
||||
type FioResult struct {
|
||||
FioVersion string `json:"fio version,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
TimestampMS int64 `json:"timestamp_ms,omitempty"`
|
||||
Time string `json:"time,omitempty"`
|
||||
GlobalOptions FioGlobalOptions `json:"global options,omitempty"`
|
||||
Jobs []FioJobs `json:"jobs,omitempty"`
|
||||
DiskUtil []FioDiskUtil `json:"disk_util,omitempty"`
|
||||
}
|
||||
|
||||
func (f FioResult) Print() string {
|
||||
var res string
|
||||
res += fmt.Sprintf("FIO version - %s\n", f.FioVersion)
|
||||
res += fmt.Sprintf("Global options - %s\n\n", f.GlobalOptions.Print())
|
||||
for _, job := range f.Jobs {
|
||||
res += fmt.Sprintf("%s\n", job.Print())
|
||||
}
|
||||
res += "Disk stats (read/write):\n"
|
||||
for _, du := range f.DiskUtil {
|
||||
res += fmt.Sprintf("%s\n", du.Print())
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
type FioGlobalOptions struct {
|
||||
Directory string `json:"directory,omitempty"`
|
||||
RandRepeat string `json:"randrepeat,omitempty"`
|
||||
Verify string `json:"verify,omitempty"`
|
||||
IOEngine string `json:"ioengine,omitempty"`
|
||||
Direct string `json:"direct,omitempty"`
|
||||
GtodReduce string `json:"gtod_reduce,omitempty"`
|
||||
}
|
||||
|
||||
func (g FioGlobalOptions) Print() string {
|
||||
return fmt.Sprintf("ioengine=%s verify=%s direct=%s gtod_reduce=%s", g.IOEngine, g.Verify, g.Direct, g.GtodReduce)
|
||||
}
|
||||
|
||||
type FioJobs struct {
|
||||
JobName string `json:"jobname,omitempty"`
|
||||
GroupID int `json:"groupid,omitempty"`
|
||||
Error int `json:"error,omitempty"`
|
||||
Eta int `json:"eta,omitempty"`
|
||||
Elapsed int `json:"elapsed,omitempty"`
|
||||
JobOptions FioJobOptions `json:"job options,omitempty"`
|
||||
Read FioStats `json:"read,omitempty"`
|
||||
Write FioStats `json:"write,omitempty"`
|
||||
Trim FioStats `json:"trim,omitempty"`
|
||||
Sync FioStats `json:"sync,omitempty"`
|
||||
JobRuntime int32 `json:"job_runtime,omitempty"`
|
||||
UsrCpu float32 `json:"usr_cpu,omitempty"`
|
||||
SysCpu float32 `json:"sys_cpu,omitempty"`
|
||||
Ctx int32 `json:"ctx,omitempty"`
|
||||
MajF int32 `json:"majf,omitempty"`
|
||||
MinF int32 `json:"minf,omitempty"`
|
||||
IoDepthLevel FioDepth `json:"iodepth_level,omitempty"`
|
||||
IoDepthSubmit FioDepth `json:"iodepth_submit,omitempty"`
|
||||
IoDepthComplete FioDepth `json:"iodepth_complete,omitempty"`
|
||||
LatencyNs FioLatency `json:"latency_ns,omitempty"`
|
||||
LatencyUs FioLatency `json:"latency_us,omitempty"`
|
||||
LatencyMs FioLatency `json:"latency_ms,omitempty"`
|
||||
LatencyDepth int32 `json:"latency_depth,omitempty"`
|
||||
LatencyTarget int32 `json:"latency_target,omitempty"`
|
||||
LatencyPercentile float32 `json:"latency_percentile,omitempty"`
|
||||
LatencyWindow int32 `json:"latency_window,omitempty"`
|
||||
}
|
||||
|
||||
func (j FioJobs) Print() string {
|
||||
var job string
|
||||
job += fmt.Sprintf("%s\n", j.JobOptions.Print())
|
||||
if j.Read.Iops != 0 || j.Read.BW != 0 {
|
||||
job += fmt.Sprintf("read:\n%s\n", j.Read.Print())
|
||||
}
|
||||
if j.Write.Iops != 0 || j.Write.BW != 0 {
|
||||
job += fmt.Sprintf("write:\n%s\n", j.Write.Print())
|
||||
}
|
||||
return job
|
||||
}
|
||||
|
||||
type FioJobOptions struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
BS string `json:"bs,omitempty"`
|
||||
IoDepth string `json:"iodepth,omitempty"`
|
||||
Size string `json:"size,omitempty"`
|
||||
RW string `json:"rw,omitempty"`
|
||||
RampTime string `json:"ramp_time,omitempty"`
|
||||
RunTime string `json:"runtime,omitempty"`
|
||||
}
|
||||
|
||||
func (o FioJobOptions) Print() string {
|
||||
return fmt.Sprintf("JobName: %s\n blocksize=%s filesize=%s iodepth=%s rw=%s", o.Name, o.BS, o.Size, o.IoDepth, o.RW)
|
||||
}
|
||||
|
||||
type FioStats struct {
|
||||
IOBytes int64 `json:"io_bytes,omitempty"`
|
||||
IOKBytes int64 `json:"io_kbytes,omitempty"`
|
||||
BWBytes int64 `json:"bw_bytes,omitempty"`
|
||||
BW int64 `json:"bw,omitempty"`
|
||||
Iops float32 `json:"iops,omitempty"`
|
||||
Runtime int64 `json:"runtime,omitempty"`
|
||||
TotalIos int64 `json:"total_ios,omitempty"`
|
||||
ShortIos int64 `json:"short_ios,omitempty"`
|
||||
DropIos int64 `json:"drop_ios,omitempty"`
|
||||
SlatNs FioNS `json:"slat_ns,omitempty"`
|
||||
ClatNs FioNS `json:"clat_ns,omitempty"`
|
||||
LatNs FioNS `json:"lat_ns,omitempty"`
|
||||
BwMin int64 `json:"bw_min,omitempty"`
|
||||
BwMax int64 `json:"bw_max,omitempty"`
|
||||
BwAgg float32 `json:"bw_agg,omitempty"`
|
||||
BwMean float32 `json:"bw_mean,omitempty"`
|
||||
BwDev float32 `json:"bw_dev,omitempty"`
|
||||
BwSamples int32 `json:"bw_samples,omitempty"`
|
||||
IopsMin int32 `json:"iops_min,omitempty"`
|
||||
IopsMax int32 `json:"iops_max,omitempty"`
|
||||
IopsMean float32 `json:"iops_mean,omitempty"`
|
||||
IopsStdDev float32 `json:"iops_stddev,omitempty"`
|
||||
IopsSamples int32 `json:"iops_samples,omitempty"`
|
||||
}
|
||||
|
||||
func (s FioStats) Print() string {
|
||||
var stats string
|
||||
stats += fmt.Sprintf(" IOPS=%f BW(KiB/s)=%d\n", s.Iops, s.BW)
|
||||
stats += fmt.Sprintf(" iops: min=%d max=%d avg=%f\n", s.IopsMin, s.IopsMax, s.IopsMean)
|
||||
stats += fmt.Sprintf(" bw(KiB/s): min=%d max=%d avg=%f", s.BwMin, s.BwMax, s.BwMean)
|
||||
return stats
|
||||
}
|
||||
|
||||
type FioNS struct {
|
||||
Min int64 `json:"min,omitempty"`
|
||||
Max int64 `json:"max,omitempty"`
|
||||
Mean float32 `json:"mean,omitempty"`
|
||||
StdDev float32 `json:"stddev,omitempty"`
|
||||
N int64 `json:"N,omitempty"`
|
||||
}
|
||||
|
||||
type FioDepth struct {
|
||||
FioDepth0 float32 `json:"0,omitempty"`
|
||||
FioDepth1 float32 `json:"1,omitempty"`
|
||||
FioDepth2 float32 `json:"2,omitempty"`
|
||||
FioDepth4 float32 `json:"4,omitempty"`
|
||||
FioDepth8 float32 `json:"8,omitempty"`
|
||||
FioDepth16 float32 `json:"16,omitempty"`
|
||||
FioDepth32 float32 `json:"32,omitempty"`
|
||||
FioDepth64 float32 `json:"64,omitempty"`
|
||||
FioDepthGE64 float32 `json:">=64,omitempty"`
|
||||
}
|
||||
|
||||
type FioLatency struct {
|
||||
FioLat2 float32 `json:"2,omitempty"`
|
||||
FioLat4 float32 `json:"4,omitempty"`
|
||||
FioLat10 float32 `json:"10,omitempty"`
|
||||
FioLat20 float32 `json:"20,omitempty"`
|
||||
FioLat50 float32 `json:"50,omitempty"`
|
||||
FioLat100 float32 `json:"100,omitempty"`
|
||||
FioLat250 float32 `json:"250,omitempty"`
|
||||
FioLat500 float32 `json:"500,omitempty"`
|
||||
FioLat750 float32 `json:"750,omitempty"`
|
||||
FioLat1000 float32 `json:"1000,omitempty"`
|
||||
FioLat2000 float32 `json:"2000,omitempty"`
|
||||
FioLatGE2000 float32 `json:">=2000,omitempty"`
|
||||
}
|
||||
|
||||
type FioDiskUtil struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
ReadIos int64 `json:"read_ios,omitempty"`
|
||||
WriteIos int64 `json:"write_ios,omitempty"`
|
||||
ReadMerges int64 `json:"read_merges,omitempty"`
|
||||
WriteMerges int64 `json:"write_merges,omitempty"`
|
||||
ReadTicks int64 `json:"read_ticks,omitempty"`
|
||||
WriteTicks int64 `json:"write_ticks,omitempty"`
|
||||
InQueue int64 `json:"in_queue,omitempty"`
|
||||
Util float32 `json:"util,omitempty"`
|
||||
}
|
||||
|
||||
func (d FioDiskUtil) Print() string {
|
||||
//Disk stats (read/write):
|
||||
//rbd4: ios=30022/11982, merge=0/313, ticks=1028675/1022768, in_queue=2063740, util=99.67%
|
||||
var du string
|
||||
du += fmt.Sprintf(" %s: ios=%d/%d merge=%d/%d ticks=%d/%d in_queue=%d, util=%f%%", d.Name, d.ReadIos,
|
||||
d.WriteIos, d.ReadMerges, d.WriteMerges, d.ReadTicks, d.WriteTicks, d.InQueue, d.Util)
|
||||
return du
|
||||
}
|
491
pkg/fio/parsable_fio_output.go
Normal file
491
pkg/fio/parsable_fio_output.go
Normal file
|
@ -0,0 +1,491 @@
|
|||
package fio
|
||||
|
||||
const parsableFioOutput = `{
|
||||
"fio version" : "fio-3.20",
|
||||
"timestamp" : 1611952282,
|
||||
"timestamp_ms" : 1611952282240,
|
||||
"time" : "Fri Jan 29 20:31:22 2021",
|
||||
"global options" : {
|
||||
"directory" : "/dataset",
|
||||
"randrepeat" : "0",
|
||||
"verify" : "0",
|
||||
"ioengine" : "libaio",
|
||||
"direct" : "1",
|
||||
"gtod_reduce" : "1"
|
||||
},
|
||||
"jobs" : [
|
||||
{
|
||||
"jobname" : "read_iops",
|
||||
"groupid" : 0,
|
||||
"error" : 0,
|
||||
"eta" : 0,
|
||||
"elapsed" : 18,
|
||||
"job options" : {
|
||||
"name" : "read_iops",
|
||||
"bs" : "4K",
|
||||
"iodepth" : "64",
|
||||
"size" : "2G",
|
||||
"rw" : "randread",
|
||||
"ramp_time" : "2s",
|
||||
"runtime" : "15s"
|
||||
},
|
||||
"read" : {
|
||||
"io_bytes" : 61886464,
|
||||
"io_kbytes" : 60436,
|
||||
"bw_bytes" : 4039322,
|
||||
"bw" : 3944,
|
||||
"iops" : 982.050780,
|
||||
"runtime" : 15321,
|
||||
"total_ios" : 15046,
|
||||
"short_ios" : 0,
|
||||
"drop_ios" : 0,
|
||||
"slat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"clat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"lat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"bw_min" : 1919,
|
||||
"bw_max" : 7664,
|
||||
"bw_agg" : 100.000000,
|
||||
"bw_mean" : 3995.000000,
|
||||
"bw_dev" : 1200.820783,
|
||||
"bw_samples" : 30,
|
||||
"iops_min" : 479,
|
||||
"iops_max" : 1916,
|
||||
"iops_mean" : 998.566667,
|
||||
"iops_stddev" : 300.247677,
|
||||
"iops_samples" : 30
|
||||
},
|
||||
"write" : {
|
||||
"io_bytes" : 0,
|
||||
"io_kbytes" : 0,
|
||||
"bw_bytes" : 0,
|
||||
"bw" : 0,
|
||||
"iops" : 0.000000,
|
||||
"runtime" : 0,
|
||||
"total_ios" : 0,
|
||||
"short_ios" : 0,
|
||||
"drop_ios" : 0,
|
||||
"slat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"clat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"lat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"bw_min" : 0,
|
||||
"bw_max" : 0,
|
||||
"bw_agg" : 0.000000,
|
||||
"bw_mean" : 0.000000,
|
||||
"bw_dev" : 0.000000,
|
||||
"bw_samples" : 0,
|
||||
"iops_min" : 0,
|
||||
"iops_max" : 0,
|
||||
"iops_mean" : 0.000000,
|
||||
"iops_stddev" : 0.000000,
|
||||
"iops_samples" : 0
|
||||
},
|
||||
"trim" : {
|
||||
"io_bytes" : 0,
|
||||
"io_kbytes" : 0,
|
||||
"bw_bytes" : 0,
|
||||
"bw" : 0,
|
||||
"iops" : 0.000000,
|
||||
"runtime" : 0,
|
||||
"total_ios" : 0,
|
||||
"short_ios" : 0,
|
||||
"drop_ios" : 0,
|
||||
"slat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"clat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"lat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"bw_min" : 0,
|
||||
"bw_max" : 0,
|
||||
"bw_agg" : 0.000000,
|
||||
"bw_mean" : 0.000000,
|
||||
"bw_dev" : 0.000000,
|
||||
"bw_samples" : 0,
|
||||
"iops_min" : 0,
|
||||
"iops_max" : 0,
|
||||
"iops_mean" : 0.000000,
|
||||
"iops_stddev" : 0.000000,
|
||||
"iops_samples" : 0
|
||||
},
|
||||
"sync" : {
|
||||
"total_ios" : 0,
|
||||
"lat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
}
|
||||
},
|
||||
"job_runtime" : 15322,
|
||||
"usr_cpu" : 1.109516,
|
||||
"sys_cpu" : 3.648349,
|
||||
"ctx" : 17991,
|
||||
"majf" : 1,
|
||||
"minf" : 62,
|
||||
"iodepth_level" : {
|
||||
"1" : 0.000000,
|
||||
"2" : 0.000000,
|
||||
"4" : 0.000000,
|
||||
"8" : 0.000000,
|
||||
"16" : 0.000000,
|
||||
"32" : 0.000000,
|
||||
">=64" : 100.000000
|
||||
},
|
||||
"iodepth_submit" : {
|
||||
"0" : 0.000000,
|
||||
"4" : 100.000000,
|
||||
"8" : 0.000000,
|
||||
"16" : 0.000000,
|
||||
"32" : 0.000000,
|
||||
"64" : 0.000000,
|
||||
">=64" : 0.000000
|
||||
},
|
||||
"iodepth_complete" : {
|
||||
"0" : 0.000000,
|
||||
"4" : 99.993354,
|
||||
"8" : 0.000000,
|
||||
"16" : 0.000000,
|
||||
"32" : 0.000000,
|
||||
"64" : 0.100000,
|
||||
">=64" : 0.000000
|
||||
},
|
||||
"latency_ns" : {
|
||||
"2" : 0.000000,
|
||||
"4" : 0.000000,
|
||||
"10" : 0.000000,
|
||||
"20" : 0.000000,
|
||||
"50" : 0.000000,
|
||||
"100" : 0.000000,
|
||||
"250" : 0.000000,
|
||||
"500" : 0.000000,
|
||||
"750" : 0.000000,
|
||||
"1000" : 0.000000
|
||||
},
|
||||
"latency_us" : {
|
||||
"2" : 0.000000,
|
||||
"4" : 0.000000,
|
||||
"10" : 0.000000,
|
||||
"20" : 0.000000,
|
||||
"50" : 0.000000,
|
||||
"100" : 0.000000,
|
||||
"250" : 0.000000,
|
||||
"500" : 0.000000,
|
||||
"750" : 0.000000,
|
||||
"1000" : 0.000000
|
||||
},
|
||||
"latency_ms" : {
|
||||
"2" : 0.000000,
|
||||
"4" : 0.000000,
|
||||
"10" : 0.000000,
|
||||
"20" : 0.000000,
|
||||
"50" : 0.000000,
|
||||
"100" : 0.000000,
|
||||
"250" : 0.000000,
|
||||
"500" : 0.000000,
|
||||
"750" : 0.000000,
|
||||
"1000" : 0.000000,
|
||||
"2000" : 0.000000,
|
||||
">=2000" : 0.000000
|
||||
},
|
||||
"latency_depth" : 64,
|
||||
"latency_target" : 0,
|
||||
"latency_percentile" : 100.000000,
|
||||
"latency_window" : 0
|
||||
},
|
||||
{
|
||||
"jobname" : "write_iops",
|
||||
"groupid" : 0,
|
||||
"error" : 0,
|
||||
"eta" : 0,
|
||||
"elapsed" : 18,
|
||||
"job options" : {
|
||||
"name" : "write_iops",
|
||||
"bs" : "4K",
|
||||
"iodepth" : "64",
|
||||
"size" : "2G",
|
||||
"rw" : "randwrite",
|
||||
"ramp_time" : "2s",
|
||||
"runtime" : "15s"
|
||||
},
|
||||
"read" : {
|
||||
"io_bytes" : 0,
|
||||
"io_kbytes" : 0,
|
||||
"bw_bytes" : 0,
|
||||
"bw" : 0,
|
||||
"iops" : 0.000000,
|
||||
"runtime" : 0,
|
||||
"total_ios" : 0,
|
||||
"short_ios" : 0,
|
||||
"drop_ios" : 0,
|
||||
"slat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"clat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"lat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"bw_min" : 0,
|
||||
"bw_max" : 0,
|
||||
"bw_agg" : 0.000000,
|
||||
"bw_mean" : 0.000000,
|
||||
"bw_dev" : 0.000000,
|
||||
"bw_samples" : 0,
|
||||
"iops_min" : 0,
|
||||
"iops_max" : 0,
|
||||
"iops_mean" : 0.000000,
|
||||
"iops_stddev" : 0.000000,
|
||||
"iops_samples" : 0
|
||||
},
|
||||
"write" : {
|
||||
"io_bytes" : 24805376,
|
||||
"io_kbytes" : 24224,
|
||||
"bw_bytes" : 1616406,
|
||||
"bw" : 1578,
|
||||
"iops" : 390.525218,
|
||||
"runtime" : 15346,
|
||||
"total_ios" : 5993,
|
||||
"short_ios" : 0,
|
||||
"drop_ios" : 0,
|
||||
"slat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"clat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"lat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"bw_min" : 512,
|
||||
"bw_max" : 2706,
|
||||
"bw_agg" : 100.000000,
|
||||
"bw_mean" : 1581.066667,
|
||||
"bw_dev" : 476.641189,
|
||||
"bw_samples" : 30,
|
||||
"iops_min" : 128,
|
||||
"iops_max" : 676,
|
||||
"iops_mean" : 395.033333,
|
||||
"iops_stddev" : 119.151738,
|
||||
"iops_samples" : 30
|
||||
},
|
||||
"trim" : {
|
||||
"io_bytes" : 0,
|
||||
"io_kbytes" : 0,
|
||||
"bw_bytes" : 0,
|
||||
"bw" : 0,
|
||||
"iops" : 0.000000,
|
||||
"runtime" : 0,
|
||||
"total_ios" : 0,
|
||||
"short_ios" : 0,
|
||||
"drop_ios" : 0,
|
||||
"slat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"clat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"lat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
},
|
||||
"bw_min" : 0,
|
||||
"bw_max" : 0,
|
||||
"bw_agg" : 0.000000,
|
||||
"bw_mean" : 0.000000,
|
||||
"bw_dev" : 0.000000,
|
||||
"bw_samples" : 0,
|
||||
"iops_min" : 0,
|
||||
"iops_max" : 0,
|
||||
"iops_mean" : 0.000000,
|
||||
"iops_stddev" : 0.000000,
|
||||
"iops_samples" : 0
|
||||
},
|
||||
"sync" : {
|
||||
"total_ios" : 0,
|
||||
"lat_ns" : {
|
||||
"min" : 0,
|
||||
"max" : 0,
|
||||
"mean" : 0.000000,
|
||||
"stddev" : 0.000000,
|
||||
"N" : 0
|
||||
}
|
||||
},
|
||||
"job_runtime" : 15345,
|
||||
"usr_cpu" : 0.508309,
|
||||
"sys_cpu" : 2.280873,
|
||||
"ctx" : 7411,
|
||||
"majf" : 1,
|
||||
"minf" : 63,
|
||||
"iodepth_level" : {
|
||||
"1" : 0.000000,
|
||||
"2" : 0.000000,
|
||||
"4" : 0.000000,
|
||||
"8" : 0.000000,
|
||||
"16" : 0.000000,
|
||||
"32" : 0.000000,
|
||||
">=64" : 100.000000
|
||||
},
|
||||
"iodepth_submit" : {
|
||||
"0" : 0.000000,
|
||||
"4" : 100.000000,
|
||||
"8" : 0.000000,
|
||||
"16" : 0.000000,
|
||||
"32" : 0.000000,
|
||||
"64" : 0.000000,
|
||||
">=64" : 0.000000
|
||||
},
|
||||
"iodepth_complete" : {
|
||||
"0" : 0.000000,
|
||||
"4" : 99.983317,
|
||||
"8" : 0.000000,
|
||||
"16" : 0.000000,
|
||||
"32" : 0.000000,
|
||||
"64" : 0.100000,
|
||||
">=64" : 0.000000
|
||||
},
|
||||
"latency_ns" : {
|
||||
"2" : 0.000000,
|
||||
"4" : 0.000000,
|
||||
"10" : 0.000000,
|
||||
"20" : 0.000000,
|
||||
"50" : 0.000000,
|
||||
"100" : 0.000000,
|
||||
"250" : 0.000000,
|
||||
"500" : 0.000000,
|
||||
"750" : 0.000000,
|
||||
"1000" : 0.000000
|
||||
},
|
||||
"latency_us" : {
|
||||
"2" : 0.000000,
|
||||
"4" : 0.000000,
|
||||
"10" : 0.000000,
|
||||
"20" : 0.000000,
|
||||
"50" : 0.000000,
|
||||
"100" : 0.000000,
|
||||
"250" : 0.000000,
|
||||
"500" : 0.000000,
|
||||
"750" : 0.000000,
|
||||
"1000" : 0.000000
|
||||
},
|
||||
"latency_ms" : {
|
||||
"2" : 0.000000,
|
||||
"4" : 0.000000,
|
||||
"10" : 0.000000,
|
||||
"20" : 0.000000,
|
||||
"50" : 0.000000,
|
||||
"100" : 0.000000,
|
||||
"250" : 0.000000,
|
||||
"500" : 0.000000,
|
||||
"750" : 0.000000,
|
||||
"1000" : 0.000000,
|
||||
"2000" : 0.000000,
|
||||
">=2000" : 0.000000
|
||||
},
|
||||
"latency_depth" : 64,
|
||||
"latency_target" : 0,
|
||||
"latency_percentile" : 100.000000,
|
||||
"latency_window" : 0
|
||||
}
|
||||
],
|
||||
"disk_util" : [
|
||||
{
|
||||
"name" : "rbd4",
|
||||
"read_ios" : 16957,
|
||||
"write_ios" : 6896,
|
||||
"read_merges" : 0,
|
||||
"write_merges" : 207,
|
||||
"read_ticks" : 1072290,
|
||||
"write_ticks" : 1043421,
|
||||
"in_queue" : 2119036,
|
||||
"util" : 99.712875
|
||||
}
|
||||
]
|
||||
}`
|
Loading…
Reference in a new issue