Skip to content

feat(e2e): performance benchmark framework and seed datasets - #1476

Open
olegbet wants to merge 1 commit into
tektoncd:mainfrom
olegbet:performance_benchmark_framework
Open

olegbet wants to merge 1 commit into
tektoncd:mainfrom
olegbet:performance_benchmark_framework

Conversation

@olegbet

@olegbet olegbet commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

Assisted-by: Claude

Changes

Performance benchmark framework and seed datasets.

  • Performance benchmark framework added to monitor throughput performance improvements/regressions of Tekton results API server and database.
  • Generic PipelineRun and TaskRun templates added to benchmark against

Submitter Checklist

These are the criteria that every PR should meet, please check them off as you review them:

  • Has Docs included if any changes are user facing
  • Has Tests included if any functionality added or changed
  • Tested your changes locally (if this is a code change)
  • Follows the commit message standard
  • Meets the Tekton contributor standards (including functionality, content, code)
  • Has a kind label. You can add a comment on this PR that contains /kind <type>. Valid types are bug, cleanup, design, documentation, feature, flake, misc, question, tep
  • Release notes block below has been updated with any user-facing changes (API changes, bug fixes, changes requiring upgrade notices or deprecation warnings)
  • Release notes contain the string "action required" if the change requires additional action from users switching to the new release

Release Notes

NONE

@tekton-robot tekton-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Aug 31, 2026
@tekton-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
To complete the pull request process, please assign enarha after the PR has been reviewed.
You can assign the PR to them by writing /assign @enarha in a comment when ready.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@tekton-robot tekton-robot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Aug 31, 2026
Comment thread test/performance/harness/apiclient.go Fixed
@olegbet
olegbet force-pushed the performance_benchmark_framework branch 2 times, most recently from d653a7c to 6a5db79 Compare September 14, 2026 09:49
@olegbet olegbet changed the title WIP: performance benchmark framework performance benchmark framework Sep 14, 2026
@tekton-robot tekton-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Sep 14, 2026
@olegbet

olegbet commented Sep 14, 2026

Copy link
Copy Markdown
Contributor Author

/kind feature

@tekton-robot tekton-robot added the kind/feature Categorizes issue or PR as related to a new feature. label Sep 14, 2026
@olegbet olegbet changed the title performance benchmark framework performance benchmark framework and seed datasets Sep 14, 2026
@tekton-robot tekton-robot added release-note-none Denotes a PR that doesnt merit a release note. and removed release-note Denotes a PR that will be considered when it comes time to generate release notes. labels Sep 14, 2026
@olegbet olegbet changed the title performance benchmark framework and seed datasets feat(e2e): performance benchmark framework and seed datasets Sep 14, 2026
@olegbet
olegbet force-pushed the performance_benchmark_framework branch from 6a5db79 to ffb328e Compare September 14, 2026 10:57
@olegbet

olegbet commented Sep 14, 2026

Copy link
Copy Markdown
Contributor Author

/retest

@olegbet
olegbet force-pushed the performance_benchmark_framework branch from ffb328e to 9ea8734 Compare September 14, 2026 12:56
Comment thread test/performance/harness/apiclient.go Fixed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

External database setup, dataset provenance, percentile calculation, and JSON output correctness have unresolved defects.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds a deterministic performance-benchmarking framework for measuring Tekton Results API storage and query throughput.

Changes:

  • Adds dataset generators, realistic PipelineRun/TaskRun templates, metrics, and versioned reports.
  • Adds load, store, query, and mixed benchmark workloads.
  • Adds kind environment automation, tests, and documentation.
File summaries
File Description
.gitignore Ignores benchmark outputs.
docs/README.md Links performance documentation.
docs/performance.md Documents benchmark usage.
test/e2e/01-install.sh Extends token lifetime.
test/performance/README.md Documents the framework.
test/performance/baselines/.gitkeep Reserves baseline directory.
test/performance/datasets/seed-small.md Defines the seed dataset.
test/performance/environments/kind/00-kind-up.sh Creates the kind cluster.
test/performance/environments/kind/01-install-localdb.sh Installs local Postgres.
test/performance/environments/kind/02-install-externaldb.sh Installs with external Postgres.
test/performance/environments/kind/03-smoke.sh Runs benchmark smoke checks.
test/performance/environments/kind/postgres-patch.yaml Pins Postgres resources/config.
test/performance/environments/kind/postgresql.conf Defines benchmark DB tuning.
test/performance/generator/definition.go Builds golden dataset definitions.
test/performance/generator/distribution.go Implements deterministic distributions.
test/performance/generator/generator.go Materializes benchmark instances.
test/performance/generator/generator_test.go Tests generator behavior.
test/performance/generator/pipelinerun.go Generates PipelineRuns and TaskRuns.
test/performance/generator/template.go Loads weighted templates.
test/performance/generator/template_mix_test.go Tests template selection.
test/performance/generator/templates/README.md Documents template contracts.
test/performance/generator/templates/default/simple/pipelinerun.yaml Provides default PipelineRun data.
test/performance/generator/templates/default/simple/taskruns/build-container.yaml Provides a build TaskRun.
test/performance/generator/templates/default/simple/taskruns/clone-repository.yaml Provides a clone TaskRun.
test/performance/generator/templates/default/simple/template.yaml Configures the default template.
test/performance/generator/templates/fbc-builder/pipelinerun.yaml Provides a large reference PipelineRun.
test/performance/generator/templates/fbc-builder/taskruns/apply-tags.yaml Adds apply-tags fixture data.
test/performance/generator/templates/fbc-builder/taskruns/build-image-index.yaml Adds image-index fixture data.
test/performance/generator/templates/fbc-builder/taskruns/build.yaml Adds large build fixture data.
test/performance/generator/templates/fbc-builder/taskruns/clone-repository.yaml Adds realistic clone fixture data.
test/performance/generator/templates/fbc-builder/taskruns/deprecated-base-image-check.yaml Adds image-check fixture data.
test/performance/generator/templates/fbc-builder/taskruns/fbc-fips-check-oci-ta.yaml Adds FIPS-check fixture data.
test/performance/generator/templates/fbc-builder/taskruns/fbc-inject-lifecycle.yaml Adds lifecycle fixture data.
test/performance/generator/templates/fbc-builder/taskruns/fbc-target-index-pruning-check.yaml Adds index-pruning fixture data.
test/performance/generator/templates/fbc-builder/taskruns/init.yaml Adds initialization fixture data.
test/performance/generator/templates/fbc-builder/taskruns/validate-fbc.yaml Adds validation fixture data.
test/performance/generator/templates/fbc-builder/template.yaml Configures the FBC template.
test/performance/generator/templates/sample/pipelinerun.yaml Provides sample PipelineRun data.
test/performance/generator/templates/sample/taskrun.yaml Provides sample TaskRun data.
test/performance/generator/templates/sample/template.yaml Configures the sample template.
test/performance/harness/apiclient.go Constructs API clients.
test/performance/harness/config.go Defines benchmark flags.
test/performance/harness/dataset.go Configures deterministic datasets.
test/performance/harness/harness_test.go Tests harness helpers.
test/performance/harness/loader.go Loads and verifies seed data.
test/performance/harness/main.go Implements benchmark commands.
test/performance/harness/mixed.go Runs mixed workloads.
test/performance/harness/output_test.go Tests output handling.
test/performance/harness/query.go Runs paginated query workloads.
test/performance/harness/store.go Replays write lifecycles.
test/performance/harness/worker.go Coordinates benchmark workers.
test/performance/metrics/metrics.go Collects latency/error metrics.
test/performance/metrics/metrics_test.go Tests metric calculations.
test/performance/report/meta.go Captures report provenance.
test/performance/report/report.go Defines the report schema.
test/performance/report/report_test.go Tests report generation.
Review details

Suppressed comments (1)

test/performance/harness/config.go:69

  • The committed seed specification identifies the current dataset as seed-small-v4, but the CLI defaults to seed-small-v1. Every default load and benchmark will therefore label v4-generated content as v1, defeating the version-based comparability contract.
  • Files reviewed: 55/56 changed files
  • Comments generated: 10
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread test/performance/environments/kind/02-install-externaldb.sh Outdated
Comment thread test/performance/harness/config.go Outdated
Comment thread test/performance/metrics/metrics.go Outdated
Comment thread test/performance/harness/loader.go Outdated
Comment thread test/performance/harness/main.go Outdated
Comment thread test/performance/harness/main.go
Comment thread test/performance/harness/mixed.go Outdated
Comment thread test/performance/report/meta.go Outdated
Comment thread docs/performance.md Outdated
Comment thread test/performance/README.md Outdated
@olegbet
olegbet force-pushed the performance_benchmark_framework branch 2 times, most recently from a177dc3 to 4bebd02 Compare September 17, 2026 09:32
@olegbet
olegbet force-pushed the performance_benchmark_framework branch from 4bebd02 to e1bf421 Compare October 4, 2026 21:16
return nil, nil, fmt.Errorf("computing dataset definition: %w", err)
}
m := runIndexed(ctx, cfg.Concurrency, 0, cfg.Count, func(ctx context.Context, index int, m *metrics.MetricSet) {
inst, err := g.At(index)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadSeed never checks if any writes failed, it always returns nil error even if half the records failed to persist. May be we can add a check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadSeed records errors to the metrics object with m.Observe method and is actually not meant to fail on any of the errors so it would probably make sense to let it pass on them.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The metrics capture is good for reporting, but the caller (loadCmd) has no way to know the seed dataset is incomplete. If 50% of records failed to persist, the subsequent query or mixed workload will silently run against a partial dataset, producing misleading benchmark numbers. A middle ground: don't fail hard, but return/log a summary like "X of Y records failed to store" so the user knows the seed is degraded. The metrics file captures per-op errors, but someone running ./harness load from CLI won't see that until they parse the JSON report.

Comment thread test/performance/harness/loader.go Outdated
// compares them to the golden definition. It returns an error describing any
// mismatch so the loader can fail loudly rather than benchmark against a partial
// dataset.
func verifySeed(ctx context.Context, l lister, def *generator.DatasetDefinition) error {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verification uses wildcard parent "-/results/-" and only checks total PipelineRun/TaskRun counts. All records landing in one namespace would pass. I think we should iterate def.PerNamespace and verify counts per namespace.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed

Version: g.cfg.Version,
Seed: g.cfg.Seed,
Count: g.cfg.Count,
GeneratedAt: time.Now().UTC().Format(time.RFC3339),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DatasetDefinition.GeneratedAt changes every call, so bench dataset output differs between runs. Either we can drop the field from the struct, or set it to a fixed sentinel.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed

return nil, nil, err
}
def, err := g.Definition()
if err != nil {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bench load discards storeInstance's returned sendLogEntry, so there's no record of what was sent, the compliance suite needs this for ingest verification. Collect entries the same way newStoreCmd does.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed

Comment thread test/performance/harness/mixed.go Outdated
// splitWorkers divides a worker budget between readers and writers by ratio,
// guaranteeing at least one of each when the budget allows.
func splitWorkers(total, readRatio, writeRatio int) (writers, readers int) {
if total < 2 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function returns (1, 1) = 2 workers when asked for 1, violating the budget. IMO we can return (1, 0) or (0, 1) for total < 2 instead of (1, 1)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed

Comment thread test/performance/harness/main.go Outdated
Short: "Benchmark parallel store (live range) and query (seed range)",
RunE: func(cmd *cobra.Command, _ []string) error {
if cfg.Concurrency <= 1 {
return fmt.Errorf("concurrency for mixed mode must be grater than 1")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo "grater" in the error message.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

// empty, TLS verification is skipped (convenient for a local kind cluster with a
// self-signed cert).

func NewAPIClients(cfg ClientConfig) (*APIClients, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NewAPIClients creates gRPC and REST connections but never exposes a way to close them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment thread docs/performance.md Outdated
```

Run the store, query, and mixed workloads. Each command writes a JSON report
under `test/performance/output/`, which the harness creates on demand. Omit

@enarha enarha Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not really planning to commit in git those results of the performance testing, at least not in the results repo. I would suggest that by default the reports are written somewhere in /tmp, e.g. /tmp/<date>-<commit>. We can later decide for a platform to upload it (it may be some other Git repo or whatever), but that's not part of the current issue.
I see you added the output files to gitignore, but the output directory should not be here either IMO.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed

Comment thread docs/performance.md Outdated
---
-->

# Performance Benchmarking

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Putting the comment here, but it's regarding the performance.md file. IMO the docs folder is more suited for user facing documentation. I'll suggest this file to move to the performance folder. There is a README file there already, so you can combine the content if needed. My point is that if user looks into the docs folder and sees file named performance.md, he/she might think it's about performance related optimizations and guides. That BTW is something else we are missing in our documentation because the default settings are not optimized for performance, but that's just a side note.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread docs/performance.md Outdated
Comment on lines +54 to +56
export API_SERVER_ADDR=https://localhost:8080
CERT=/tmp/tekton-results/ssl/tekton-results-cert.pem
TOKEN=/tmp/tekton-results/tokens/all-namespaces-admin-access

@enarha enarha Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given it's our script creating the environment, we should know the values already. We can still keep the ENV vars for the users to override the default values, but maybe that should not be mandatory. Also the syntax is a bit off, we either need an export on each line or escape the new lines with \.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread docs/performance.md Outdated
--output test/performance/output/mixed.json --duration 60
```

The `load --verify` command recomputes the dataset content hash and reports

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so it only verifies without loading the datasets? Or loads and verifies? It sounds like it's the latter, but can you please confirm?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it load the seed dataset through the API and verify counts, I'll update the documentation comment.

Comment thread docs/performance.md Outdated
export BENCH_DB_URL="postgres://<user>:<pass>@<host>:5432/results?sslmode=require"
./test/performance/environments/kind/02-install-externaldb.sh
# The installer cannot export into this shell; set the report label here:
export BENCH_DB_BACKEND=external

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Both DB and BACKEND to me mean the same, so maybe BENCH_DB_TYPE? If we are only planning to accept one value here external, it could also be BENCH_DB_EXTERNAL=true.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment thread docs/README.md Outdated

- [Roadmap](roadmap.md)
- [Results API Query Cookbook](api/README.md#cookbook)
- [Performance Benchmarking](performance.md)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that should be also removed if you remove the performance.md file from the docs folder.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment thread test/performance/baselines/.gitkeep Outdated
@@ -0,0 +1,3 @@
# Committed baseline reports land here (one JSON per mode/tier/dataset version).

@enarha enarha Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand the purpose here, but as I mentioned earlier, IMO we should not commit any reports nor baselines. I agree it'll be nice to keep track or baselines and specific measurements for comparison, but it should not be in the tekton results repo.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was meant to persist the latest reports to compare the later runs with it, but it does make sense to have some separate temporary repo for that.

Comment thread test/performance/README.md Outdated
```

`generator`, `metrics`, and `report` are importable packages — the compare tool
(Story 02) and compliance suite (Story 03) reuse the generator, datasets, and

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid mentioning stories, they do not have any meaning in code. You can say currently we have X and adding Y and Z is planned, where X, Y and Z are the actual features and not references.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@enarha enarha left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

go run ./test/performance/harness load --verify \
    --cert "${SSL_CERT_PATH}/tekton-results-cert.pem" \
    --token "${SA_TOKEN_PATH}/all-namespaces-admin-access"

seems to be very slow. I waited for ~20 mins and it was far from the finished. So I looked into it and found (expectedly) that with the default qps (5) and burst (10), the k8s api queries were slowing the process down. So I bumped these to 50 and 100 respectively through the tekton-results-api-config configMap and rolled out a new Results API instance. This improved the speed, but eventually the seed verification failed.

go run ./test/performance/harness load --verify --cert "${SSL_CERT_PATH}/tekton-results-cert.pem" --token "${SA_TOKEN_PATH}/all-namespaces-admin-access"
Loading template "simple" from templates/default/simple...
Creating generator...
error: seed verification failed: row-count mismatch: PipelineRuns got 998 want 1000, TaskRuns got 3021 want 3028
exit status 1

I'm assuming this could be result of the roll out of the api pod.
I tried on a new deployment and bumped the api qps and burst before running the seed and this time it was significantly quicker.

time go run ./test/performance/harness load --verify --cert "${SSL_CERT_PATH}/tekton-results-cert.pem" --token "${SA_TOKEN_PATH}/all-namespaces-admin-access"
Loading template "simple" from templates/default/simple...
Creating generator...
seed verified: 1000 PipelineRuns, dataset hash e4e707dbbae0f81b929277f3eee2b8037a692b4f1f0414fce526d30ab852b8c8
{
  "schema_version": "1",
  "meta": {
    "git_commit": "e1bf421d6059798888920de8524ae0a2e8896b69",
    "git_dirty": false,
    "dataset_version": "seed-small-v1",
    "dataset_hash": "e4e707dbbae0f81b929277f3eee2b8037a692b4f1f0414fce526d30ab852b8c8",
    "tier": "tier1",
    "mode": "load",
    "started_at": "2026-10-18T14:16:10Z",
    "duration_ms": 279169,
    "hostname": "xxx",
    "api_server_addr": "https://localhost:8080",
    "db_backend": "local",
    "server_image": ""
  },
  "config": {
    "count": 1000,
    "concurrency": 8,
    "duration_sec": 0,
    "transport": "grpc",
    "read_ratio": 0,
    "write_ratio": 0,
    "dataset": "seed-small",
    "seed": 42
  },
  "metrics": {
    "throughput_per_sec": 25.174705297724294,
    "total_ops": 7028,
    "total_errors": 0,
    "by_op": {
      "create_child_record": {
        "count": 3028,
        "errors": 0,
        "error_codes": {
          "OK": 3028
        },
        "p50_ms": 319.983599,
        "p90_ms": 359.245217,
        "p99_ms": 422.225187,
        "min_ms": 4.241181,
        "max_ms": 491.527029,
        "mean_ms": 317.450755
      },
      "create_record": {
        "count": 1000,
        "errors": 0,
        "error_codes": {
          "OK": 1000
        },
        "p50_ms": 320.21912,
        "p90_ms": 351.638204,
        "p99_ms": 413.343513,
        "min_ms": 4.482895,
        "max_ms": 465.844868,
        "mean_ms": 316.387736
      },
      "create_result": {
        "count": 1000,
        "errors": 0,
        "error_codes": {
          "OK": 1000
        },
        "p50_ms": 319.58464,
        "p90_ms": 353.740945,
        "p99_ms": 424.228629,
        "min_ms": 4.422872,
        "max_ms": 472.725226,
        "mean_ms": 314.84384
      },
      "update_record": {
        "count": 1000,
        "errors": 0,
        "error_codes": {
          "OK": 1000
        },
        "p50_ms": 320.018055,
        "p90_ms": 355.730706,
        "p99_ms": 425.553204,
        "min_ms": 4.450035,
        "max_ms": 470.503902,
        "mean_ms": 317.046036
      },
      "update_result": {
        "count": 1000,
        "errors": 0,
        "error_codes": {
          "OK": 1000
        },
        "p50_ms": 319.781984,
        "p90_ms": 354.168935,
        "p99_ms": 414.655482,
        "min_ms": 4.548607,
        "max_ms": 459.429215,
        "mean_ms": 315.363235
      }
    }
  }
}

real    4m39.653s
user    0m3.457s
sys     0m1.541s

I'm considering making qps=50 and burst=100 the default values, but I need to do more testing. So in the meantime, consider setting these values through the template/kustomize for the testing.
As a separate note, see that I replaced the value of hostname with xxx. We should be very careful with that as it leaks information about hostname and username. Unless you have a good reason to include it and a proper way to sanitize it, I'll suggest you drop it.

Comment thread test/performance/report/report.go Outdated
Mode string `json:"mode"`
StartedAt string `json:"started_at"`
DurationMS int64 `json:"duration_ms"`
Hostname string `json:"hostname"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be either dropped or replaced with a hash, so we can still compare the reports based on where the test was executed without leaking hostname and username.

@enarha

enarha commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor
go run ./test/performance/harness load --verify \
    --cert "${SSL_CERT_PATH}/tekton-results-cert.pem" \
    --token "${SA_TOKEN_PATH}/all-namespaces-admin-access"

seems to be very slow. I waited for ~20 mins and it was far from the finished. So I looked into it and found (expectedly) that with the default qps (5) and burst (10), the k8s api queries were slowing the process down. So I bumped these to 50 and 100 respectively through the tekton-results-api-config configMap and rolled out a new Results API instance. This improved the speed, but eventually the seed verification failed.

go run ./test/performance/harness load --verify --cert "${SSL_CERT_PATH}/tekton-results-cert.pem" --token "${SA_TOKEN_PATH}/all-namespaces-admin-access"
Loading template "simple" from templates/default/simple...
Creating generator...
error: seed verification failed: row-count mismatch: PipelineRuns got 998 want 1000, TaskRuns got 3021 want 3028
exit status 1

I'm assuming this could be result of the roll out of the api pod. I tried on a new deployment and bumped the api qps and burst before running the seed and this time it was significantly quicker.

time go run ./test/performance/harness load --verify --cert "${SSL_CERT_PATH}/tekton-results-cert.pem" --token "${SA_TOKEN_PATH}/all-namespaces-admin-access"
Loading template "simple" from templates/default/simple...
Creating generator...
seed verified: 1000 PipelineRuns, dataset hash e4e707dbbae0f81b929277f3eee2b8037a692b4f1f0414fce526d30ab852b8c8
{
  "schema_version": "1",
  "meta": {
    "git_commit": "e1bf421d6059798888920de8524ae0a2e8896b69",
    "git_dirty": false,
    "dataset_version": "seed-small-v1",
    "dataset_hash": "e4e707dbbae0f81b929277f3eee2b8037a692b4f1f0414fce526d30ab852b8c8",
    "tier": "tier1",
    "mode": "load",
    "started_at": "2026-10-18T14:16:10Z",
    "duration_ms": 279169,
    "hostname": "xxx",
    "api_server_addr": "https://localhost:8080",
    "db_backend": "local",
    "server_image": ""
  },
  "config": {
    "count": 1000,
    "concurrency": 8,
    "duration_sec": 0,
    "transport": "grpc",
    "read_ratio": 0,
    "write_ratio": 0,
    "dataset": "seed-small",
    "seed": 42
  },
  "metrics": {
    "throughput_per_sec": 25.174705297724294,
    "total_ops": 7028,
    "total_errors": 0,
    "by_op": {
      "create_child_record": {
        "count": 3028,
        "errors": 0,
        "error_codes": {
          "OK": 3028
        },
        "p50_ms": 319.983599,
        "p90_ms": 359.245217,
        "p99_ms": 422.225187,
        "min_ms": 4.241181,
        "max_ms": 491.527029,
        "mean_ms": 317.450755
      },
      "create_record": {
        "count": 1000,
        "errors": 0,
        "error_codes": {
          "OK": 1000
        },
        "p50_ms": 320.21912,
        "p90_ms": 351.638204,
        "p99_ms": 413.343513,
        "min_ms": 4.482895,
        "max_ms": 465.844868,
        "mean_ms": 316.387736
      },
      "create_result": {
        "count": 1000,
        "errors": 0,
        "error_codes": {
          "OK": 1000
        },
        "p50_ms": 319.58464,
        "p90_ms": 353.740945,
        "p99_ms": 424.228629,
        "min_ms": 4.422872,
        "max_ms": 472.725226,
        "mean_ms": 314.84384
      },
      "update_record": {
        "count": 1000,
        "errors": 0,
        "error_codes": {
          "OK": 1000
        },
        "p50_ms": 320.018055,
        "p90_ms": 355.730706,
        "p99_ms": 425.553204,
        "min_ms": 4.450035,
        "max_ms": 470.503902,
        "mean_ms": 317.046036
      },
      "update_result": {
        "count": 1000,
        "errors": 0,
        "error_codes": {
          "OK": 1000
        },
        "p50_ms": 319.781984,
        "p90_ms": 354.168935,
        "p99_ms": 414.655482,
        "min_ms": 4.548607,
        "max_ms": 459.429215,
        "mean_ms": 315.363235
      }
    }
  }
}

real    4m39.653s
user    0m3.457s
sys     0m1.541s

I'm considering making qps=50 and burst=100 the default values, but I need to do more testing. So in the meantime, consider setting these values through the template/kustomize for the testing. As a separate note, see that I replaced the value of hostname with xxx. We should be very careful with that as it leaks information about hostname and username. Unless you have a good reason to include it and a proper way to sanitize it, I'll suggest you drop it.

I did a couple of more tests and one good option is disabling the authentication during the test (AUTH_DISABLE=true). Changing that value, the test on 1000 PipelineRuns finishes in ~10 seconds. We can achieve similar performance by bumping the qps and burst to 500 and 1000 respectively and in this case the test on my local machine completed in ~26 seconds. So I see 2 paths forward, one is we simply deploy the performance installation with AUTH_DISABLE=true, that's the simpler one. The other one is we make qps=500 and burst=1000 the default to the test and we expose additional flag which controls the authentication, with the default being enabled. We plan to add caching for authentication results, so being able to test with authentication enabled is a bonus. @adityavshinde FYI.

@olegbet
olegbet force-pushed the performance_benchmark_framework branch from e1bf421 to 56b01c7 Compare October 21, 2026 11:49
@tekton-robot tekton-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Oct 21, 2026
@olegbet

olegbet commented Oct 21, 2026

Copy link
Copy Markdown
Contributor Author

/retest

@tekton-robot tekton-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Oct 21, 2026
Comment thread test/e2e/01-install.sh Outdated
@olegbet
olegbet force-pushed the performance_benchmark_framework branch 2 times, most recently from c9cd6b7 to d7eae5c Compare October 22, 2026 13:43
@olegbet

olegbet commented Oct 26, 2026

Copy link
Copy Markdown
Contributor Author

/ok-to-test

Assisted-by: Claude, Codex

Performance benchmark framework and seed datasets.

- Performance benchmark framework added to monitor throughput performance improvements/regressions of Tekton results API server and database.

- Generic PipelineRun and TaskRun templates added to benchmark against

Signed-off-by: obetsun <obetsun@redhat.com>
@olegbet
olegbet force-pushed the performance_benchmark_framework branch from cdc5fc0 to 847bba4 Compare October 26, 2026 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature Categorizes issue or PR as related to a new feature. release-note-none Denotes a PR that doesnt merit a release note. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants