From e0ed94526eca5bbbebabb389c2bdc00bca84ce43 Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Thu, 14 Aug 2025 15:40:43 +1000 Subject: [PATCH 01/13] Add configurable read/update benchmark with watch support Add read_update benchmark command for mixed workload testing --- .../runkperf/commands/bench/read_update.go | 187 ++++++++++++++++++ contrib/cmd/runkperf/commands/bench/root.go | 1 + contrib/cmd/runkperf/commands/bench/utils.go | 34 ++++ .../manifests/loadprofile/read_update.yaml | 34 ++++ 4 files changed, 256 insertions(+) create mode 100644 contrib/cmd/runkperf/commands/bench/read_update.go create mode 100644 contrib/internal/manifests/loadprofile/read_update.yaml diff --git a/contrib/cmd/runkperf/commands/bench/read_update.go b/contrib/cmd/runkperf/commands/bench/read_update.go new file mode 100644 index 00000000..705429c5 --- /dev/null +++ b/contrib/cmd/runkperf/commands/bench/read_update.go @@ -0,0 +1,187 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +package bench + +import ( + "context" + "fmt" + "sync" + "time" + _ "unsafe" + + internaltypes "github.com/Azure/kperf/contrib/internal/types" + "github.com/Azure/kperf/contrib/utils" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/klog/v2" + + "github.com/urfave/cli" +) + +var appLabel = "runkperf" + +var benchReadUpdateCase = cli.Command{ + Name: "read_update", + Usage: ` +The test suite sets up a benchmark that simulates a mix of read, watch, and update operations on ConfigMaps. +It creates ConfigMaps, establishes watch connections, and then issues concurrent read and update requests based on a specified ratio to evaluate API server performance under combined load. +`, + Flags: append( + []cli.Flag{ + cli.IntFlag{ + Name: "total", + Usage: "Total requests per runner (There are 10 runners totally and runner's rate is 10)", + Value: 3600, + }, + cli.StringFlag{ + Name: "read-update-namespace", + Usage: "Kubernetes namespace to use. If not specified, it will use the default namespace.", + Value: "default", + }, + cli.IntFlag{ + Name: "read-update-configmap-total", + Usage: "Total ConfigMaps need to create", + Value: 100, + }, + cli.IntFlag{ + Name: "read-update-configmap-size", + Usage: "Size of each ConfigMap. ConfigMap must not exceed 3 MiB.", + Value: 1024, // 1 MiB + }, + cli.StringFlag{ + Name: "read-update-name-pattern", + Usage: "Name pattern for the resources to create", + Value: "kperf-read-update", + }, + cli.Float64Flag{ + Name: "read-ratio", + Usage: "Proportion of read requests among all requests (range: 0.0 to 1.0). For example, 0.5 indicates 50% of the requests are reads.", + Value: 0.5, + }, + }, + commonFlags..., + ), + Action: func(cliCtx *cli.Context) error { + _, err := renderBenchmarkReportInterceptor( + addAPIServerCoresInfoInterceptor(benchReadUpdateRun), + )(cliCtx) + return err + }, +} + +// benchReadUpdateRun is for subcommand benchReadUpdateRun. +func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, error) { + ctx := context.Background() + kubeCfgPath := cliCtx.GlobalString("kubeconfig") + + // Load the load profile + rgCfgFile, rgSpec, rgCfgFileDone, err := newLoadProfileFromEmbed(cliCtx, + "loadprofile/read_update.yaml") + + if err != nil { + return nil, err + } + defer func() { _ = rgCfgFileDone() }() + + dpCtx, dpCancel := context.WithCancel(ctx) + defer dpCancel() + + total := cliCtx.Int("read-update-configmap-total") + size := cliCtx.Int("read-update-configmap-size") + namespace := cliCtx.String("read-update-namespace") + namePattern := cliCtx.String("read-update-name-pattern") + if total <= 0 || size <= 0 || total*size > 2*1024*1024 || size > 3*1024 { + return nil, fmt.Errorf("invalid total (%d) or size (%d) for configmaps: total must be > 0, size must be > 0, and total*size must not exceed 2 GiB, size must not exceed 3 MiB", total, size) + } + + // Create configmaps with specified name pattern + client, err := utils.BuildClientset(kubeCfgPath) + if err != nil { + return nil, fmt.Errorf("failed to build clientset: %w", err) + } + + err = utils.CreateConfigmaps(dpCtx, kubeCfgPath, namespace, namePattern, total, size, 2, 0) + + if err != nil { + return nil, fmt.Errorf("failed to create configmaps: %w", err) + } + + defer utils.DeleteConfigmaps(ctx, kubeCfgPath, namespace, namePattern, 0) + + // Start to watch the configmaps + watches := make([]watch.Interface, 0) + var wg sync.WaitGroup + for i := 0; i < total; i++ { + wg.Add(1) + go func(index int) { + defer wg.Done() + watchReq, err := client.CoreV1().ConfigMaps(namespace). + Watch(context.TODO(), metav1.ListOptions{ + Watch: true, + FieldSelector: fmt.Sprintf("metadata.name=%s-cm-%s-%d", appLabel, namePattern, i), + }) + + watches = append(watches, watchReq) + if err != nil { + fmt.Printf("Error starting watch for configmap %s: %v\n", fmt.Sprintf("%s-cm-%s-%d", appLabel, namePattern, i), err) + return + } + + klog.V(5).Infof("Starting watch for configmap: %s\n", fmt.Sprintf("%s-cm-%s-%d", appLabel, namePattern, i)) + for { + select { + case <-dpCtx.Done(): + klog.V(5).Infof("Stopping watch for configmap: %s\n", fmt.Sprintf("%s-cm-%s-%d", appLabel, namePattern, i)) + return + case event := <-watchReq.ResultChan(): + if event.Type == watch.Error { + klog.Errorf("Error event received for configmap %s: %v", fmt.Sprintf("%s-cm-%s-%d", appLabel, namePattern, i), event.Object) + return + } + klog.V(5).Infof("Event received for configmap %s: %v", fmt.Sprintf("%s-cm-%s-%d", appLabel, namePattern, i), event.Type) + } + time.Sleep(2 * time.Second) + } + + }(i) + } + // Stop all the watches when the function returns + defer stopWatches(watches) + + // Deploy the runner group + rgResult, derr := utils.DeployRunnerGroup(ctx, + cliCtx.GlobalString("kubeconfig"), + cliCtx.GlobalString("runner-image"), + rgCfgFile, + cliCtx.GlobalString("runner-flowcontrol"), + cliCtx.GlobalString("rg-affinity"), + ) + + // Cancel the context to stop all watches + dpCancel() + wg.Wait() + + if derr != nil { + return nil, derr + } + + return &internaltypes.BenchmarkReport{ + Description: fmt.Sprintf(` +Environment: Combine %d read requests and %d update requests during benchmarking. Workload: Deploy %d configmaps in %d KiB`, + 100*int(cliCtx.Float64("read-ratio")), 100-100*(1-int(cliCtx.Float64("read-ratio"))), total, size*total), + LoadSpec: *rgSpec, + Result: *rgResult, + Info: map[string]interface{}{}, + }, nil +} + +// StopWatches stops all the watches +func stopWatches(watches []watch.Interface) { + for _, w := range watches { + if w != nil { + klog.V(5).Infof("Stopping watch: %v", w) + w.Stop() + } + } +} diff --git a/contrib/cmd/runkperf/commands/bench/root.go b/contrib/cmd/runkperf/commands/bench/root.go index ea752af4..3d019dba 100644 --- a/contrib/cmd/runkperf/commands/bench/root.go +++ b/contrib/cmd/runkperf/commands/bench/root.go @@ -62,6 +62,7 @@ var Command = cli.Command{ benchListConfigmapsCase, benchNode10Job1Pod1kCase, benchNode100Job10Pod10kCase, + benchReadUpdateCase, }, } diff --git a/contrib/cmd/runkperf/commands/bench/utils.go b/contrib/cmd/runkperf/commands/bench/utils.go index 927d113b..2354bc95 100644 --- a/contrib/cmd/runkperf/commands/bench/utils.go +++ b/contrib/cmd/runkperf/commands/bench/utils.go @@ -169,6 +169,40 @@ func newLoadProfileFromEmbed(cliCtx *cli.Context, name string) (_name string, _s spec.Profile.Spec.ContentType = types.ContentType(cliCtx.String("content-type")) data, _ := yaml.Marshal(spec) + // Tweak the load profile for read-update case + namePattern := cliCtx.String("read-update-name-pattern") + ratio := cliCtx.Float64("read-ratio") + if ratio <= 0 || ratio > 1 { + return fmt.Errorf("invalid read-ratio: %.2f, must be between 0 and 1", ratio) + } + + namespace := cliCtx.String("read-update-namespace") + configmapTotal := cliCtx.Int("read-update-configmap-total") + + if namePattern != "" || ratio != 0 || namespace != "" || configmapTotal > 0 { + for _, r := range spec.Profile.Spec.Requests { + if r.Patch != nil { + if namePattern != "" { + r.Patch.Name = fmt.Sprintf("runkperf-cm-%s", namePattern) + } + if ratio != 0 { + r.Shares = 100 - int(ratio*100) + } + if namespace != "" { + r.Patch.Namespace = namespace + } + if configmapTotal > 0 { + r.Patch.KeySpaceSize = configmapTotal + } + } + if r.QuorumList != nil { + if ratio != 0 { + r.Shares = int(ratio * 100) + } + } + } + } + log.GetLogger(context.TODO()). WithKeyValues("level", "info"). LogKV("msg", "dump load profile", "config", string(data)) diff --git a/contrib/internal/manifests/loadprofile/read_update.yaml b/contrib/internal/manifests/loadprofile/read_update.yaml new file mode 100644 index 00000000..c1171ba2 --- /dev/null +++ b/contrib/internal/manifests/loadprofile/read_update.yaml @@ -0,0 +1,34 @@ +count: 10 +loadProfile: + version: 1 + description: "read_update" + spec: + rate: 10 + total: 3000 + conns: 10 + client: 10 + contentType: json + disableHTTP2: false + maxRetries: 0 + requests: + - quorumList: + version: v1 + resource: configmaps + namespace: default + shares: 20 + - patch: + version: v1 + resource: configmaps + namespace: default + patchType: merge + name: runkperf-cm-kperf-read-update + keySpaceSize: 10 + body: | + { + "metadata": { + "labels": { + "test-label": "mutation-test" + } + } + } + shares: 80 From 6c84a577d95aff4aaf55552e592fce0806b8879f Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Thu, 14 Aug 2025 16:06:27 +1000 Subject: [PATCH 02/13] Use staleList in read_update.yaml --- contrib/internal/manifests/loadprofile/read_update.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/internal/manifests/loadprofile/read_update.yaml b/contrib/internal/manifests/loadprofile/read_update.yaml index c1171ba2..e93b4300 100644 --- a/contrib/internal/manifests/loadprofile/read_update.yaml +++ b/contrib/internal/manifests/loadprofile/read_update.yaml @@ -11,7 +11,7 @@ loadProfile: disableHTTP2: false maxRetries: 0 requests: - - quorumList: + - staleList: version: v1 resource: configmaps namespace: default From 647704039872c900e1f56b7b2f73e0ead7a12260 Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Thu, 14 Aug 2025 16:27:30 +1000 Subject: [PATCH 03/13] Add comment --- contrib/cmd/runkperf/commands/bench/read_update.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contrib/cmd/runkperf/commands/bench/read_update.go b/contrib/cmd/runkperf/commands/bench/read_update.go index 705429c5..dd0125aa 100644 --- a/contrib/cmd/runkperf/commands/bench/read_update.go +++ b/contrib/cmd/runkperf/commands/bench/read_update.go @@ -127,8 +127,9 @@ func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, er fmt.Printf("Error starting watch for configmap %s: %v\n", fmt.Sprintf("%s-cm-%s-%d", appLabel, namePattern, i), err) return } - klog.V(5).Infof("Starting watch for configmap: %s\n", fmt.Sprintf("%s-cm-%s-%d", appLabel, namePattern, i)) + + // Process watch events proactively to prevent cache oversizing. for { select { case <-dpCtx.Done(): From 2ca62a7f003b908bbfb0e2371c308da57cd5a899 Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Thu, 14 Aug 2025 16:37:30 +1000 Subject: [PATCH 04/13] Change to StaleList and tweak StaleList --- contrib/cmd/runkperf/commands/bench/utils.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/cmd/runkperf/commands/bench/utils.go b/contrib/cmd/runkperf/commands/bench/utils.go index 2354bc95..8bf9b3f8 100644 --- a/contrib/cmd/runkperf/commands/bench/utils.go +++ b/contrib/cmd/runkperf/commands/bench/utils.go @@ -195,7 +195,7 @@ func newLoadProfileFromEmbed(cliCtx *cli.Context, name string) (_name string, _s r.Patch.KeySpaceSize = configmapTotal } } - if r.QuorumList != nil { + if r.StaleList != nil { if ratio != 0 { r.Shares = int(ratio * 100) } From c148ea5191c981e6e1a6c416183eb15d2576f30d Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Thu, 14 Aug 2025 16:40:51 +1000 Subject: [PATCH 05/13] Set keySpaceSize to read-update-configmap-total in read_update.go --- contrib/internal/manifests/loadprofile/read_update.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/internal/manifests/loadprofile/read_update.yaml b/contrib/internal/manifests/loadprofile/read_update.yaml index e93b4300..c0fca18a 100644 --- a/contrib/internal/manifests/loadprofile/read_update.yaml +++ b/contrib/internal/manifests/loadprofile/read_update.yaml @@ -22,7 +22,7 @@ loadProfile: namespace: default patchType: merge name: runkperf-cm-kperf-read-update - keySpaceSize: 10 + keySpaceSize: 100 body: | { "metadata": { From 27c10f133339114a3249034d049942eaa4c39a34 Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Thu, 14 Aug 2025 16:44:04 +1000 Subject: [PATCH 06/13] Set shares to read-ratio in read_update.go --- contrib/internal/manifests/loadprofile/read_update.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/internal/manifests/loadprofile/read_update.yaml b/contrib/internal/manifests/loadprofile/read_update.yaml index c0fca18a..bdb43c97 100644 --- a/contrib/internal/manifests/loadprofile/read_update.yaml +++ b/contrib/internal/manifests/loadprofile/read_update.yaml @@ -15,7 +15,7 @@ loadProfile: version: v1 resource: configmaps namespace: default - shares: 20 + shares: 50 - patch: version: v1 resource: configmaps @@ -31,4 +31,4 @@ loadProfile: } } } - shares: 80 + shares: 50 From 75c6f18b22b1ed79dd3743cd641f078901c2dd89 Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Thu, 14 Aug 2025 16:58:48 +1000 Subject: [PATCH 07/13] Fix linter --- contrib/cmd/runkperf/commands/bench/read_update.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/contrib/cmd/runkperf/commands/bench/read_update.go b/contrib/cmd/runkperf/commands/bench/read_update.go index dd0125aa..523d9c7c 100644 --- a/contrib/cmd/runkperf/commands/bench/read_update.go +++ b/contrib/cmd/runkperf/commands/bench/read_update.go @@ -8,7 +8,6 @@ import ( "fmt" "sync" "time" - _ "unsafe" internaltypes "github.com/Azure/kperf/contrib/internal/types" "github.com/Azure/kperf/contrib/utils" @@ -107,14 +106,20 @@ func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, er return nil, fmt.Errorf("failed to create configmaps: %w", err) } - defer utils.DeleteConfigmaps(ctx, kubeCfgPath, namespace, namePattern, 0) + defer func() { + // Delete the configmaps after the benchmark + err = utils.DeleteConfigmaps(ctx, kubeCfgPath, namespace, namePattern, 0) + if err != nil { + klog.Errorf("Failed to delete configmaps: %v", err) + } + }() // Start to watch the configmaps watches := make([]watch.Interface, 0) var wg sync.WaitGroup for i := 0; i < total; i++ { wg.Add(1) - go func(index int) { + go func() { defer wg.Done() watchReq, err := client.CoreV1().ConfigMaps(namespace). Watch(context.TODO(), metav1.ListOptions{ @@ -145,7 +150,7 @@ func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, er time.Sleep(2 * time.Second) } - }(i) + }() } // Stop all the watches when the function returns defer stopWatches(watches) From 178e5b9a2312379917cbc99116dd2832eb527903 Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Fri, 15 Aug 2025 13:35:35 +1000 Subject: [PATCH 08/13] Refactor configmap context handling in benchReadUpdateRun --- .../runkperf/commands/bench/read_update.go | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/contrib/cmd/runkperf/commands/bench/read_update.go b/contrib/cmd/runkperf/commands/bench/read_update.go index 523d9c7c..9458188e 100644 --- a/contrib/cmd/runkperf/commands/bench/read_update.go +++ b/contrib/cmd/runkperf/commands/bench/read_update.go @@ -83,9 +83,6 @@ func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, er } defer func() { _ = rgCfgFileDone() }() - dpCtx, dpCancel := context.WithCancel(ctx) - defer dpCancel() - total := cliCtx.Int("read-update-configmap-total") size := cliCtx.Int("read-update-configmap-size") namespace := cliCtx.String("read-update-namespace") @@ -100,7 +97,7 @@ func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, er return nil, fmt.Errorf("failed to build clientset: %w", err) } - err = utils.CreateConfigmaps(dpCtx, kubeCfgPath, namespace, namePattern, total, size, 2, 0) + err = utils.CreateConfigmaps(ctx, kubeCfgPath, namespace, namePattern, total, size, 2, 0) if err != nil { return nil, fmt.Errorf("failed to create configmaps: %w", err) @@ -114,9 +111,17 @@ func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, er } }() - // Start to watch the configmaps + // Stop all the watches when the function returns watches := make([]watch.Interface, 0) + defer stopWatches(watches) + var wg sync.WaitGroup + defer wg.Wait() + + dpCtx, dpCancel := context.WithCancel(ctx) + defer dpCancel() + + // Start to watch the configmaps for i := 0; i < total; i++ { wg.Add(1) go func() { @@ -152,8 +157,6 @@ func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, er }() } - // Stop all the watches when the function returns - defer stopWatches(watches) // Deploy the runner group rgResult, derr := utils.DeployRunnerGroup(ctx, @@ -164,12 +167,8 @@ func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, er cliCtx.GlobalString("rg-affinity"), ) - // Cancel the context to stop all watches - dpCancel() - wg.Wait() - if derr != nil { - return nil, derr + return nil, fmt.Errorf("failed to deploy runner group: %w", derr) } return &internaltypes.BenchmarkReport{ From 538c687d84665efb77c22a6c244e895882d28a92 Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Fri, 15 Aug 2025 13:36:25 +1000 Subject: [PATCH 09/13] Remove unused time import and redundant sleep in configmap watcher --- contrib/cmd/runkperf/commands/bench/read_update.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/contrib/cmd/runkperf/commands/bench/read_update.go b/contrib/cmd/runkperf/commands/bench/read_update.go index 9458188e..dd2a4c79 100644 --- a/contrib/cmd/runkperf/commands/bench/read_update.go +++ b/contrib/cmd/runkperf/commands/bench/read_update.go @@ -7,7 +7,6 @@ import ( "context" "fmt" "sync" - "time" internaltypes "github.com/Azure/kperf/contrib/internal/types" "github.com/Azure/kperf/contrib/utils" @@ -152,7 +151,6 @@ func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, er } klog.V(5).Infof("Event received for configmap %s: %v", fmt.Sprintf("%s-cm-%s-%d", appLabel, namePattern, i), event.Type) } - time.Sleep(2 * time.Second) } }() From a7ed403745ca35c96842444dbd0fd51f22c82e3c Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Fri, 15 Aug 2025 13:57:50 +1000 Subject: [PATCH 10/13] Make a new tweak fun for read_update pipeline --- contrib/cmd/runkperf/commands/bench/utils.go | 73 ++++++++++++-------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/contrib/cmd/runkperf/commands/bench/utils.go b/contrib/cmd/runkperf/commands/bench/utils.go index 8bf9b3f8..3995db55 100644 --- a/contrib/cmd/runkperf/commands/bench/utils.go +++ b/contrib/cmd/runkperf/commands/bench/utils.go @@ -170,36 +170,10 @@ func newLoadProfileFromEmbed(cliCtx *cli.Context, name string) (_name string, _s data, _ := yaml.Marshal(spec) // Tweak the load profile for read-update case - namePattern := cliCtx.String("read-update-name-pattern") - ratio := cliCtx.Float64("read-ratio") - if ratio <= 0 || ratio > 1 { - return fmt.Errorf("invalid read-ratio: %.2f, must be between 0 and 1", ratio) - } - - namespace := cliCtx.String("read-update-namespace") - configmapTotal := cliCtx.Int("read-update-configmap-total") - - if namePattern != "" || ratio != 0 || namespace != "" || configmapTotal > 0 { - for _, r := range spec.Profile.Spec.Requests { - if r.Patch != nil { - if namePattern != "" { - r.Patch.Name = fmt.Sprintf("runkperf-cm-%s", namePattern) - } - if ratio != 0 { - r.Shares = 100 - int(ratio*100) - } - if namespace != "" { - r.Patch.Namespace = namespace - } - if configmapTotal > 0 { - r.Patch.KeySpaceSize = configmapTotal - } - } - if r.StaleList != nil { - if ratio != 0 { - r.Shares = int(ratio * 100) - } - } + if cliCtx.Command.Name == "read_update" { + err = tweakReadUpdateProfile(cliCtx, spec) + if err != nil { + return fmt.Errorf("failed to tweak read-update profile: %w", err) } } @@ -216,3 +190,42 @@ func newLoadProfileFromEmbed(cliCtx *cli.Context, name string) (_name string, _s } return rgCfgFile, &rgSpec, rgCfgFileDone, nil } + +func tweakReadUpdateProfile(cliCtx *cli.Context, spec *types.RunnerGroupSpec) error { + namePattern := cliCtx.String("read-update-name-pattern") + ratio := cliCtx.Float64("read-ratio") + if ratio <= 0 || ratio > 1 { + return fmt.Errorf("invalid read-ratio: %.2f, must be between 0 and 1", ratio) + } + + namespace := cliCtx.String("read-update-namespace") + configmapTotal := cliCtx.Int("read-update-configmap-total") + + if namePattern != "" || ratio != 0 || namespace != "" || configmapTotal > 0 { + for _, r := range spec.Profile.Spec.Requests { + if r.Patch != nil { + if namePattern != "" { + r.Patch.Name = fmt.Sprintf("runkperf-cm-%s", namePattern) + } + if ratio != 0 { + r.Shares = 100 - int(ratio*100) + } + if namespace != "" { + r.Patch.Namespace = namespace + } + if configmapTotal > 0 { + r.Patch.KeySpaceSize = configmapTotal + } + } + if r.StaleList != nil { + if ratio != 0 { + r.Shares = int(ratio * 100) + } + if namespace != "" { + r.StaleList.Namespace = namespace + } + } + } + } + return nil +} From 73c1bfdc37f859856b9d5ce4d9cda8e42ac5bf23 Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Fri, 15 Aug 2025 14:06:59 +1000 Subject: [PATCH 11/13] Fix bugs in output --- contrib/cmd/runkperf/commands/bench/read_update.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/cmd/runkperf/commands/bench/read_update.go b/contrib/cmd/runkperf/commands/bench/read_update.go index dd2a4c79..dea327ec 100644 --- a/contrib/cmd/runkperf/commands/bench/read_update.go +++ b/contrib/cmd/runkperf/commands/bench/read_update.go @@ -171,8 +171,8 @@ func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, er return &internaltypes.BenchmarkReport{ Description: fmt.Sprintf(` -Environment: Combine %d read requests and %d update requests during benchmarking. Workload: Deploy %d configmaps in %d KiB`, - 100*int(cliCtx.Float64("read-ratio")), 100-100*(1-int(cliCtx.Float64("read-ratio"))), total, size*total), +Environment: Combine %d%% read requests and %d%% update requests during benchmarking. Workload: Deploy %d configmaps in %d KiB`, + int(100*cliCtx.Float64("read-ratio")), 100-int(100*cliCtx.Float64("read-ratio")), total, size*total), LoadSpec: *rgSpec, Result: *rgResult, Info: map[string]interface{}{}, From 910cb9a682d7242bd9bad9793668316e38850a3c Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Mon, 18 Aug 2025 17:06:49 +1000 Subject: [PATCH 12/13] Limit configmaps size to 1 MiB --- contrib/cmd/runkperf/commands/bench/read_update.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/cmd/runkperf/commands/bench/read_update.go b/contrib/cmd/runkperf/commands/bench/read_update.go index dea327ec..8128828b 100644 --- a/contrib/cmd/runkperf/commands/bench/read_update.go +++ b/contrib/cmd/runkperf/commands/bench/read_update.go @@ -86,8 +86,8 @@ func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, er size := cliCtx.Int("read-update-configmap-size") namespace := cliCtx.String("read-update-namespace") namePattern := cliCtx.String("read-update-name-pattern") - if total <= 0 || size <= 0 || total*size > 2*1024*1024 || size > 3*1024 { - return nil, fmt.Errorf("invalid total (%d) or size (%d) for configmaps: total must be > 0, size must be > 0, and total*size must not exceed 2 GiB, size must not exceed 3 MiB", total, size) + if total <= 0 || size <= 0 || total*size > 2*1024*1024 || size > 1024 { + return nil, fmt.Errorf("invalid total (%d) or size (%d) for configmaps: total must be > 0, size must be > 0, and total*size must not exceed 2 GiB, size must not exceed 1 MiB", total, size) } // Create configmaps with specified name pattern From dfff7e5a95c4831fd10cdf71d197de742f20a39f Mon Sep 17 00:00:00 2001 From: Xinwei Liu Date: Wed, 20 Aug 2025 09:10:24 +1000 Subject: [PATCH 13/13] Wrap stopWatches in an anonymous deferred function --- contrib/cmd/runkperf/commands/bench/read_update.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contrib/cmd/runkperf/commands/bench/read_update.go b/contrib/cmd/runkperf/commands/bench/read_update.go index 8128828b..40741121 100644 --- a/contrib/cmd/runkperf/commands/bench/read_update.go +++ b/contrib/cmd/runkperf/commands/bench/read_update.go @@ -112,7 +112,9 @@ func benchReadUpdateRun(cliCtx *cli.Context) (*internaltypes.BenchmarkReport, er // Stop all the watches when the function returns watches := make([]watch.Interface, 0) - defer stopWatches(watches) + defer func() { + stopWatches(watches) + }() var wg sync.WaitGroup defer wg.Wait()