Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions api/types/load_traffic.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ type LoadProfile struct {
Version int `json:"version" yaml:"version"`
// Description is a string value to describe this object.
Description string `json:"description,omitempty" yaml:"description"`
// Spec defines behavior of load profile.
Spec LoadProfileSpec `json:"spec" yaml:"spec"`
// Specs defines behaviors of load profile for time-series replay support.
Specs []LoadProfileSpec `json:"specs" yaml:"specs"`
}

// LoadProfileSpec defines the load traffic for traget resource.
Expand Down Expand Up @@ -198,7 +198,20 @@ func (lp LoadProfile) Validate() error {
if lp.Version != 1 {
return fmt.Errorf("version should be 1")
}
return lp.Spec.Validate()

// Validate that specs is provided
if len(lp.Specs) == 0 {
return fmt.Errorf("specs must be provided")
}

// Validate all specs
for i, spec := range lp.Specs {
if err := spec.Validate(); err != nil {
return fmt.Errorf("specs[%d]: %w", i, err)
}
}

return nil
}

// Validate verifies fields of LoadProfileSpec.
Expand Down
206 changes: 103 additions & 103 deletions api/types/load_traffic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,122 +15,122 @@ func TestLoadProfileUnmarshalFromYAML(t *testing.T) {
in := `
version: 1
description: test
spec:
rate: 100
total: 10000
conns: 2
client: 1
contentType: json
requests:
- staleGet:
group: core
version: v1
resource: pods
namespace: default
name: x1
shares: 100
- quorumGet:
group: core
version: v1
resource: configmaps
namespace: default
name: x2
shares: 150
- staleList:
group: core
version: v1
resource: pods
namespace: default
selector: app=x2
fieldSelector: spec.nodeName=x
shares: 200
- quorumList:
group: core
version: v1
resource: configmaps
namespace: default
limit: 10000
selector: app=x3
shares: 400
- put:
group: core
version: v1
resource: configmaps
namespace: kperf
name: kperf-
keySpaceSize: 1000
valueSize: 1024
shares: 1000
- getPodLog:
namespace: default
name: hello
container: main
tailLines: 1000
limitBytes: 1024
shares: 10
- watchList:
group: core
version: v1
resource: pods
namespace: default
selector: app=x2
fieldSelector: spec.nodeName=x
shares: 250
specs:
- rate: 100
total: 10000
conns: 2
client: 1
contentType: json
requests:
- staleGet:
group: core
version: v1
resource: pods
namespace: default
name: x1
shares: 100
- quorumGet:
group: core
version: v1
resource: configmaps
namespace: default
name: x2
shares: 150
- staleList:
group: core
version: v1
resource: pods
namespace: default
selector: app=x2
fieldSelector: spec.nodeName=x
shares: 200
- quorumList:
group: core
version: v1
resource: configmaps
namespace: default
limit: 10000
selector: app=x3
shares: 400
- put:
group: core
version: v1
resource: configmaps
namespace: kperf
name: kperf-
keySpaceSize: 1000
valueSize: 1024
shares: 1000
- getPodLog:
namespace: default
name: hello
container: main
tailLines: 1000
limitBytes: 1024
shares: 10
- watchList:
group: core
version: v1
resource: pods
namespace: default
selector: app=x2
fieldSelector: spec.nodeName=x
shares: 250
`

target := LoadProfile{}
require.NoError(t, yaml.Unmarshal([]byte(in), &target))
assert.Equal(t, 1, target.Version)
assert.Equal(t, "test", target.Description)
assert.Equal(t, float64(100), target.Spec.Rate)
assert.Equal(t, 10000, target.Spec.Total)
assert.Equal(t, 2, target.Spec.Conns)
assert.Len(t, target.Spec.Requests, 7)
assert.Equal(t, float64(100), target.Specs[0].Rate)
assert.Equal(t, 10000, target.Specs[0].Total)
assert.Equal(t, 2, target.Specs[0].Conns)
assert.Len(t, target.Specs[0].Requests, 7)

assert.Equal(t, 100, target.Spec.Requests[0].Shares)
assert.NotNil(t, target.Spec.Requests[0].StaleGet)
assert.Equal(t, "pods", target.Spec.Requests[0].StaleGet.Resource)
assert.Equal(t, "v1", target.Spec.Requests[0].StaleGet.Version)
assert.Equal(t, "core", target.Spec.Requests[0].StaleGet.Group)
assert.Equal(t, "default", target.Spec.Requests[0].StaleGet.Namespace)
assert.Equal(t, "x1", target.Spec.Requests[0].StaleGet.Name)
assert.Equal(t, 100, target.Specs[0].Requests[0].Shares)
assert.NotNil(t, target.Specs[0].Requests[0].StaleGet)
assert.Equal(t, "pods", target.Specs[0].Requests[0].StaleGet.Resource)
assert.Equal(t, "v1", target.Specs[0].Requests[0].StaleGet.Version)
assert.Equal(t, "core", target.Specs[0].Requests[0].StaleGet.Group)
assert.Equal(t, "default", target.Specs[0].Requests[0].StaleGet.Namespace)
assert.Equal(t, "x1", target.Specs[0].Requests[0].StaleGet.Name)

assert.NotNil(t, target.Spec.Requests[1].QuorumGet)
assert.Equal(t, 150, target.Spec.Requests[1].Shares)
assert.NotNil(t, target.Specs[0].Requests[1].QuorumGet)
assert.Equal(t, 150, target.Specs[0].Requests[1].Shares)

assert.Equal(t, 200, target.Spec.Requests[2].Shares)
assert.NotNil(t, target.Spec.Requests[2].StaleList)
assert.Equal(t, "pods", target.Spec.Requests[2].StaleList.Resource)
assert.Equal(t, "v1", target.Spec.Requests[2].StaleList.Version)
assert.Equal(t, "core", target.Spec.Requests[2].StaleList.Group)
assert.Equal(t, "default", target.Spec.Requests[2].StaleList.Namespace)
assert.Equal(t, 0, target.Spec.Requests[2].StaleList.Limit)
assert.Equal(t, "app=x2", target.Spec.Requests[2].StaleList.Selector)
assert.Equal(t, "spec.nodeName=x", target.Spec.Requests[2].StaleList.FieldSelector)
assert.Equal(t, 200, target.Specs[0].Requests[2].Shares)
assert.NotNil(t, target.Specs[0].Requests[2].StaleList)
assert.Equal(t, "pods", target.Specs[0].Requests[2].StaleList.Resource)
assert.Equal(t, "v1", target.Specs[0].Requests[2].StaleList.Version)
assert.Equal(t, "core", target.Specs[0].Requests[2].StaleList.Group)
assert.Equal(t, "default", target.Specs[0].Requests[2].StaleList.Namespace)
assert.Equal(t, 0, target.Specs[0].Requests[2].StaleList.Limit)
assert.Equal(t, "app=x2", target.Specs[0].Requests[2].StaleList.Selector)
assert.Equal(t, "spec.nodeName=x", target.Specs[0].Requests[2].StaleList.FieldSelector)

assert.NotNil(t, target.Spec.Requests[3].QuorumList)
assert.Equal(t, 400, target.Spec.Requests[3].Shares)
assert.NotNil(t, target.Specs[0].Requests[3].QuorumList)
assert.Equal(t, 400, target.Specs[0].Requests[3].Shares)

assert.Equal(t, 1000, target.Spec.Requests[4].Shares)
assert.NotNil(t, target.Spec.Requests[4].Put)
assert.Equal(t, "configmaps", target.Spec.Requests[4].Put.Resource)
assert.Equal(t, "v1", target.Spec.Requests[4].Put.Version)
assert.Equal(t, "core", target.Spec.Requests[4].Put.Group)
assert.Equal(t, "kperf", target.Spec.Requests[4].Put.Namespace)
assert.Equal(t, "kperf-", target.Spec.Requests[4].Put.Name)
assert.Equal(t, 1000, target.Spec.Requests[4].Put.KeySpaceSize)
assert.Equal(t, 1024, target.Spec.Requests[4].Put.ValueSize)
assert.Equal(t, 1000, target.Specs[0].Requests[4].Shares)
assert.NotNil(t, target.Specs[0].Requests[4].Put)
assert.Equal(t, "configmaps", target.Specs[0].Requests[4].Put.Resource)
assert.Equal(t, "v1", target.Specs[0].Requests[4].Put.Version)
assert.Equal(t, "core", target.Specs[0].Requests[4].Put.Group)
assert.Equal(t, "kperf", target.Specs[0].Requests[4].Put.Namespace)
assert.Equal(t, "kperf-", target.Specs[0].Requests[4].Put.Name)
assert.Equal(t, 1000, target.Specs[0].Requests[4].Put.KeySpaceSize)
assert.Equal(t, 1024, target.Specs[0].Requests[4].Put.ValueSize)

assert.Equal(t, 10, target.Spec.Requests[5].Shares)
assert.NotNil(t, target.Spec.Requests[5].GetPodLog)
assert.Equal(t, "default", target.Spec.Requests[5].GetPodLog.Namespace)
assert.Equal(t, "hello", target.Spec.Requests[5].GetPodLog.Name)
assert.Equal(t, "main", target.Spec.Requests[5].GetPodLog.Container)
assert.Equal(t, int64(1000), *target.Spec.Requests[5].GetPodLog.TailLines)
assert.Equal(t, int64(1024), *target.Spec.Requests[5].GetPodLog.LimitBytes)
assert.Equal(t, 10, target.Specs[0].Requests[5].Shares)
assert.NotNil(t, target.Specs[0].Requests[5].GetPodLog)
assert.Equal(t, "default", target.Specs[0].Requests[5].GetPodLog.Namespace)
assert.Equal(t, "hello", target.Specs[0].Requests[5].GetPodLog.Name)
assert.Equal(t, "main", target.Specs[0].Requests[5].GetPodLog.Container)
assert.Equal(t, int64(1000), *target.Specs[0].Requests[5].GetPodLog.TailLines)
assert.Equal(t, int64(1024), *target.Specs[0].Requests[5].GetPodLog.LimitBytes)

assert.Equal(t, 250, target.Spec.Requests[6].Shares)
assert.NotNil(t, target.Spec.Requests[6].WatchList)
assert.Equal(t, 250, target.Specs[0].Requests[6].Shares)
assert.NotNil(t, target.Specs[0].Requests[6].WatchList)

assert.NoError(t, target.Validate())
}
Expand Down
48 changes: 27 additions & 21 deletions cmd/kperf/commands/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,25 @@ var runCommand = cli.Command{
return err
}

clientNum := profileCfg.Spec.Conns
// Runner only supports single spec
if len(profileCfg.Specs) > 1 {
return fmt.Errorf("runner only supports single spec, but got %d specs", len(profileCfg.Specs))
}
pspec := profileCfg.Specs[0]

clientNum := pspec.Conns
restClis, err := request.NewClients(kubeCfgPath,
clientNum,
request.WithClientUserAgentOpt(cliCtx.String("user-agent")),
request.WithClientQPSOpt(profileCfg.Spec.Rate),
request.WithClientContentTypeOpt(profileCfg.Spec.ContentType),
request.WithClientDisableHTTP2Opt(profileCfg.Spec.DisableHTTP2),
request.WithClientQPSOpt(pspec.Rate),
request.WithClientContentTypeOpt(pspec.ContentType),
request.WithClientDisableHTTP2Opt(pspec.DisableHTTP2),
)
if err != nil {
return err
}

stats, err := request.Schedule(context.TODO(), &profileCfg.Spec, restClis)
stats, err := request.Schedule(context.TODO(), &pspec, restClis)
if err != nil {
return err
}
Expand Down Expand Up @@ -167,36 +173,36 @@ func loadConfig(cliCtx *cli.Context) (*types.LoadProfile, error) {

// override value by flags
if v := "rate"; cliCtx.IsSet(v) {
profileCfg.Spec.Rate = cliCtx.Float64(v)
profileCfg.Specs[0].Rate = cliCtx.Float64(v)
}
if v := "conns"; cliCtx.IsSet(v) || profileCfg.Spec.Conns == 0 {
profileCfg.Spec.Conns = cliCtx.Int(v)
if v := "conns"; cliCtx.IsSet(v) || profileCfg.Specs[0].Conns == 0 {
profileCfg.Specs[0].Conns = cliCtx.Int(v)
}
if v := "client"; cliCtx.IsSet(v) || profileCfg.Spec.Client == 0 {
profileCfg.Spec.Client = cliCtx.Int(v)
if v := "client"; cliCtx.IsSet(v) || profileCfg.Specs[0].Client == 0 {
profileCfg.Specs[0].Client = cliCtx.Int(v)
}
if v := "total"; cliCtx.IsSet(v) {
profileCfg.Spec.Total = cliCtx.Int(v)
profileCfg.Specs[0].Total = cliCtx.Int(v)
}
if v := "duration"; cliCtx.IsSet(v) {
profileCfg.Spec.Duration = cliCtx.Int(v)
profileCfg.Specs[0].Duration = cliCtx.Int(v)
}
if profileCfg.Spec.Total > 0 && profileCfg.Spec.Duration > 0 {
klog.Warningf("both total:%v and duration:%v are set, duration will be ignored\n", profileCfg.Spec.Total, profileCfg.Spec.Duration)
profileCfg.Spec.Duration = 0
if profileCfg.Specs[0].Total > 0 && profileCfg.Specs[0].Duration > 0 {
klog.Warningf("both total:%v and duration:%v are set, duration will be ignored\n", profileCfg.Specs[0].Total, profileCfg.Specs[0].Duration)
profileCfg.Specs[0].Duration = 0
}
if profileCfg.Spec.Total == 0 && profileCfg.Spec.Duration == 0 {
if profileCfg.Specs[0].Total == 0 && profileCfg.Specs[0].Duration == 0 {
// Use default total value
profileCfg.Spec.Total = cliCtx.Int("total")
profileCfg.Specs[0].Total = cliCtx.Int("total")
}
if v := "content-type"; cliCtx.IsSet(v) || profileCfg.Spec.ContentType == "" {
profileCfg.Spec.ContentType = types.ContentType(cliCtx.String(v))
if v := "content-type"; cliCtx.IsSet(v) || profileCfg.Specs[0].ContentType == "" {
profileCfg.Specs[0].ContentType = types.ContentType(cliCtx.String(v))
}
if v := "disable-http2"; cliCtx.IsSet(v) {
profileCfg.Spec.DisableHTTP2 = cliCtx.Bool(v)
profileCfg.Specs[0].DisableHTTP2 = cliCtx.Bool(v)
}
if v := "max-retries"; cliCtx.IsSet(v) {
profileCfg.Spec.MaxRetries = cliCtx.Int(v)
profileCfg.Specs[0].MaxRetries = cliCtx.Int(v)
}

if err := profileCfg.Validate(); err != nil {
Expand Down
9 changes: 5 additions & 4 deletions contrib/cmd/runkperf/commands/bench/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func newLoadProfileFromEmbed(cliCtx *cli.Context, name string) (_name string, _s
reqsTime := cliCtx.Int("duration")
if !cliCtx.IsSet("total") && reqsTime > 0 {
reqs = 0
spec.Profile.Spec.Duration = reqsTime
spec.Profile.Specs[0].Duration = reqsTime
}

rgAffinity := cliCtx.GlobalString("rg-affinity")
Expand All @@ -163,10 +163,11 @@ func newLoadProfileFromEmbed(cliCtx *cli.Context, name string) (_name string, _s
}

if reqs != 0 {
spec.Profile.Spec.Total = reqs
spec.Profile.Specs[0].Total = reqs
}
spec.NodeAffinity = affinityLabels
spec.Profile.Spec.ContentType = types.ContentType(cliCtx.String("content-type"))
spec.Profile.Specs[0].ContentType = types.ContentType(cliCtx.String("content-type"))

data, _ := yaml.Marshal(spec)

// Tweak the load profile for read-update case
Expand Down Expand Up @@ -202,7 +203,7 @@ func tweakReadUpdateProfile(cliCtx *cli.Context, spec *types.RunnerGroupSpec) er
configmapTotal := cliCtx.Int("read-update-configmap-total")

if namePattern != "" || ratio != 0 || namespace != "" || configmapTotal > 0 {
for _, r := range spec.Profile.Spec.Requests {
for _, r := range spec.Profile.Specs[0].Requests {
if r.Patch != nil {
if namePattern != "" {
r.Patch.Name = fmt.Sprintf("runkperf-cm-%s", namePattern)
Expand Down
5 changes: 3 additions & 2 deletions contrib/cmd/runkperf/commands/warmup/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,9 @@ var Command = cli.Command{
return fmt.Errorf("failed to parse %s affinity: %w", rgAffinity, err)
}

spec.Profile.Spec.Total = reqs
spec.Profile.Spec.Rate = rate
spec.Profile.Specs[0].Total = reqs
spec.Profile.Specs[0].Rate = rate

spec.NodeAffinity = affinityLabels

data, _ := yaml.Marshal(spec)
Expand Down
Loading
Loading