Add BenchmarkDotNet performance benchmarks with automated historical tracking#1793
Conversation
…ontainers Agent-Logs-Url: https://github.com/dapr/dotnet-sdk/sessions/31166ce7-5f84-4e35-af61-145e4584855b Co-authored-by: WhitWaldo <2238529+WhitWaldo@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dapr/dotnet-sdk/sessions/31166ce7-5f84-4e35-af61-145e4584855b Co-authored-by: WhitWaldo <2238529+WhitWaldo@users.noreply.github.com>
|
@copilot Can you please resolve the merge conflict? |
…benchmarking-project # Conflicts: # all.sln Co-authored-by: WhitWaldo <2238529+WhitWaldo@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests.
Additional details and impacted files@@ Coverage Diff @@
## master #1793 +/- ##
===========================================
- Coverage 63.54% 47.06% -16.49%
===========================================
Files 313 259 -54
Lines 9431 7945 -1486
Branches 1106 914 -192
===========================================
- Hits 5993 3739 -2254
- Misses 3175 4030 +855
+ Partials 263 176 -87
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@copilot Can you please resolve the git merge conflicts? |
…benchmarking-project # Conflicts: # all.sln Co-authored-by: WhitWaldo <2238529+WhitWaldo@users.noreply.github.com>
Resolved in |
|
@copilot Several packages have been added to this since - can you please revise the PR to reflect the new packages as well? |
…benchmarking-project
…e and resolve namespace collision
Merged latest master (including StateManagement, SecretsManagement, Workflow meta-package restructuring, IntegrationTest.Examples, IntegrationTest.Actors.Generators, etc.) and fixed the resulting build errors in the benchmark project. The |
|
@copilot One of the big goals of this PR is to enable me to capture and publish resource utilization metrics (package size, memory usage, latency) on a per-release basis so I might demonstrate continued package improvement from one release to the next. Ideally, this is validating down to the per-integration test level so I can demonstrate improvement over consistent test code, but if it makes more sense to build out a separate application for benchmarking each of the deployed packages, that's fine. Can you dig into how to best capture and present this sort of information and tie it into the CI pipeline so it's automated? |
…age size metrics - Integrate benchmark-action/github-action-benchmark for historical comparison - Add JSON exporter to BenchmarkDotNet for CI consumption - Add package-size job measuring all NuGet .nupkg files per commit - Track latency, memory allocations, and package sizes over time - Publish interactive charts to gh-pages branch - Alert on >150% latency regression or >120% package size growth - Trigger on releases in addition to master push/schedule
- Use semver-specific regex to avoid stripping dots from package names - Replace placeholder with actual dapr.github.io URL in README
Implemented in the latest commits. Here's the approach: Metrics captured per commit/release:
How it works:
Alerting:
The |
|
@copilot How readily can I go through and essentially ensure that every single integration test in a package matching |
Pretty readily, but not by wrapping every Why not BenchmarkDotNet-wrap every testAcross the What I'd build instead — "tests-as-metrics" harnessA single new job that treats each integration test as a one-shot timed run and emits its duration + allocations as a metric series. This satisfies your three requirements naturally:
Mechanism
Trade-offs you should know going in
Scope of changes if you greenlight this
Want me to go ahead with this design, or would you rather I prototype against one project (say |
|
@copilot At the same time, I don't think it makes much sense to run this for every single PR, but rather it's something worth running for release candidate and GA release builds (e.g. any tagged release). |
- Trigger on tag push (v*, v*-rc*) and release:published instead of master push - Update gh-pages publish gates to match (refs/tags/* or release event) - Update README to reflect tagged-release-only policy - Keep weekly schedule and workflow_dispatch for ad-hoc/drift detection
Agreed. Scoped the workflow to tagged release builds ( This trigger policy will also apply to the per-integration-test metrics job from the previous comment once that's built — same gate, so RC + GA each get one data point per test. Should I go ahead and build the integration-test-as-metrics harness now under this tag-only trigger policy, or prototype it on |
|
@copilot Currently, integration tests often fail due to transient connection issues due to Testcontainers and port issues on the GitHub actions test runners. Until this can be worked out, does it make more sense to build a small benchmark project with some curated "tests" for benchmarking (as these can represent the whole of the project's capabilities but be less dependent on changes from one version to the next? It'd shrink the overall benchmark method count as well. It'd give us some tests that are fairly small and lightweight with others that are more comprehensive and have multiple steps. |
Yes — that aligns with what this PR already does and I'd recommend staying on this path. The curated approach in
The current three suites are intentionally a mix of lightweight and comprehensive:
If you want broader coverage of "the whole of the project's capabilities" without growing the method count much, the natural next additions (one method each, same pattern) would be:
That would land at ~8 benchmark classes / ~15–20 methods total — still well under the integration-test count, with each deployed package represented. Want me to add some/all of these in this PR, or land what's here first and follow up? |
|
I'm going to close this as unnecessary for now and instead focus on benchmarking between the older and newer SDK packages |
Description
Adds a
Dapr.Benchmarksproject that uses BenchmarkDotNet withDapr.Testcontainersto benchmark SDK operations against a real Dapr sidecar — no gRPC mocking required. Includes a GitHub Actions workflow that automatically captures and publishes resource utilization metrics (latency, memory allocations, package size) on a per-release basis via an interactive GitHub Pages dashboard.Benchmark project (
test/Dapr.Benchmarks/)StateStoreBenchmarks— Save/Get/Delete with Small/Medium/Large payloads against Redis state storePubSubBenchmarks— Publish and end-to-end Publish+Receive via RabbitMQWorkflowBenchmarks— Simple single-activity and fan-out (5 parallel activities) workflow executionDaprBenchmarkBase— Shared infrastructure managingDaprTestEnvironmentlifecycle for[GlobalSetup]/[GlobalCleanup][MemoryDiagnoser]for allocation trackingAutomated metrics tracking (
.github/workflows/benchmarks.yml)benchmark-action/github-action-benchmarkfor historical trend visualization[MemoryDiagnoser]dotnet packoutputgh-pagesbranch athttps://dapr.github.io/dotnet-sdk/v*(GA) andv*-rc*(release candidates),release: published, weekly cron for baseline drift detection, andworkflow_dispatchfor ad-hoc runs. Master pushes and PRs do not trigger benchmarks (the per-test sidecar startup cost makes per-PR runs prohibitive, and release-cadence data is what drives the per-release improvement narrative).BenchmarkResults/as artifacts (90-day retention)sdk_build.ymlThe project is
IsPackable=falseand the nameDapr.Benchmarksintentionally does not match theDapr.*.Test.csproj/Dapr.IntegrationTest.*.csprojCI test discovery globs, so it won't be picked up by existing test jobs.Compatibility with latest master — updated to work with the restructured
Dapr.Workflowmeta-package (explicitly referencesDapr.Workflow.Abstractionssince it's bundled withPrivateAssets="all") and resolved namespace collision betweenDapr.Benchmarks.WorkflowandDapr.Workflowtypes via a using alias.Issue reference
Informational benchmarking infrastructure — no prior issue.
Checklist