diff --git a/.github/workflows/benchmark-smoke.yml b/.github/workflows/benchmark-smoke.yml new file mode 100644 index 0000000..340f4a2 --- /dev/null +++ b/.github/workflows/benchmark-smoke.yml @@ -0,0 +1,46 @@ +name: Benchmark smoke + +on: + pull_request: + branches: [ master, main ] + workflow_dispatch: + +jobs: + benchmark-smoke: + name: Restore, build, and smoke benchmarks + runs-on: ubuntu-latest + timeout-minutes: 20 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '9.0.x' + + - name: Restore + run: dotnet restore Cerbi-Benchmark-Tests.sln + + - name: Build Release + run: dotnet build Cerbi-Benchmark-Tests.sln --configuration Release --no-restore + + - name: BenchmarkDotNet smoke run + run: >- + dotnet run --project Cerbi-Benchmark-Tests/Cerbi-Benchmark-Tests.csproj + --configuration Release --no-restore --no-build -- + --filter '*MS_Log_Plain*' + --job Dry + --artifacts ./BenchmarkDotNet.Artifacts + + - name: Upload smoke benchmark artifacts + uses: actions/upload-artifact@v4 + if: always() + with: + name: benchmark-smoke-results + path: BenchmarkDotNet.Artifacts/** + if-no-files-found: warn + + - name: Full benchmark note + run: echo "Smoke results prove benchmark discovery/execution only; full performance numbers require the dedicated full benchmark run." diff --git a/Cerbi-Benchmark-Tests/Cerbi-Benchmark-Tests.csproj b/Cerbi-Benchmark-Tests/Cerbi-Benchmark-Tests.csproj index 86d064e..88f5931 100644 --- a/Cerbi-Benchmark-Tests/Cerbi-Benchmark-Tests.csproj +++ b/Cerbi-Benchmark-Tests/Cerbi-Benchmark-Tests.csproj @@ -1,4 +1,4 @@ - + Exe @@ -15,9 +15,9 @@ - - - + + + @@ -37,6 +37,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/Cerbi-Benchmark-Tests/PopularLoggerBenchmarks.cs b/Cerbi-Benchmark-Tests/PopularLoggerBenchmarks.cs index 8306433..bb0040b 100644 --- a/Cerbi-Benchmark-Tests/PopularLoggerBenchmarks.cs +++ b/Cerbi-Benchmark-Tests/PopularLoggerBenchmarks.cs @@ -1,5 +1,4 @@ -using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Running; +using BenchmarkDotNet.Attributes; using CerbiStream.Logging; using CerbiStream.Configuration; using log4net; @@ -391,6 +390,7 @@ private bool GovernanceValidateSchema(Dictionary data) } [Benchmark(Baseline = true)] + [BenchmarkCategory("Baseline", "NoCerbi")] public void MS_Log_Plain() => _msLoggerPlain.LogInformation("MS Logger: Logging at {time}", DateTime.UtcNow); [Benchmark] @@ -447,6 +447,7 @@ public void Cerbi_Log_File() => // --- New Cerbi toggle benchmarks --- [Benchmark] + [BenchmarkCategory("CerbiStream", "GovernanceDisabled")] public void Cerbi_Minimal() => _cerbi_minimal.LogInformation("Cerbi Minimal: Logging at {time}", DateTime.UtcNow); [Benchmark] @@ -459,9 +460,21 @@ public void Cerbi_Log_File() => public void Cerbi_Minimal_Async() => _cerbi_minimal_async.LogInformation("Cerbi Minimal+Async: Logging at {time}", DateTime.UtcNow); // --- Governance simulation scenarios --- + [Benchmark] + [BenchmarkCategory("Governance", "NoViolation")] + public void Cerbi_Governance_NoViolation() + { + const string msg = "User completed operation without sensitive data"; + if (!ContainsPII(msg)) + { + _cerbiPlain.LogInformation("{msg}", msg); + } + } + // Redact simple PII in a single string then log [Benchmark] + [BenchmarkCategory("Governance", "Violation")] public void Cerbi_Governance_Redact_Simple() { var msg = $"User email={_piiEmail} cc={_piiCc} ssn={_piiSsn} note={_piiNoteBig}"; @@ -471,6 +484,7 @@ public void Cerbi_Governance_Redact_Simple() // Validate presence of PII without redacting; drop or log accordingly [Benchmark] + [BenchmarkCategory("Governance", "Violation")] public void Cerbi_Governance_ValidateOnly() { var msg = $"email={_piiEmail} cc={_piiCc} note={_piiNoteBig}"; @@ -600,6 +614,7 @@ public void Log4Net_Log_Batch_1000() // Benchmarks using governance JSON [Benchmark] + [BenchmarkCategory("GovernanceJson", "Violation")] public void Cerbi_GovernanceJson_Redact_Simple() { var msg = $"User email={_piiEmail} cc={_piiCc} ssn={_piiSsn} note={_piiNoteBig}"; @@ -739,6 +754,7 @@ public void Cerbi_Feature_PIIAutoRedact() // This benchmark shows runtime cost is ZERO when using analyzers // Competitors: No Roslyn analyzer for logging governance [Benchmark] + [BenchmarkCategory("Governance", "NoViolation", "Relaxed")] public void Cerbi_Feature_DesignTimeGovernance_RuntimeCost() { // With Roslyn analyzers, unsafe logging is blocked at compile time diff --git a/Cerbi-Benchmark-Tests/Program.cs b/Cerbi-Benchmark-Tests/Program.cs index 7378a14..6fd795e 100644 --- a/Cerbi-Benchmark-Tests/Program.cs +++ b/Cerbi-Benchmark-Tests/Program.cs @@ -1,12 +1,18 @@ using BenchmarkDotNet.Running; +using System.Reflection; public class Program { public static void Main(string[] args) { - Console.WriteLine(">>> Running updated PopularLoggerBenchmarks (subset for quick validation)..."); + if (args is null || args.Length == 0) + { + Console.WriteLine("Running the complete PopularLoggerBenchmarks suite."); + BenchmarkRunner.Run(); + return; + } - // For quicker iteration you can filter benchmarks via BenchmarkSwitcher or regex; left simple here - BenchmarkRunner.Run(); + Console.WriteLine("Running the requested filtered benchmark selection."); + BenchmarkSwitcher.FromAssembly(Assembly.GetExecutingAssembly()).Run(args); } } diff --git a/cerbi-benchmarks-page-v0.md b/cerbi-benchmarks-page-v0.md index 762ac30..9fa456f 100644 --- a/cerbi-benchmarks-page-v0.md +++ b/cerbi-benchmarks-page-v0.md @@ -7,6 +7,18 @@ A comprehensive benchmarks page for cerbi.io showcasing CerbiStream performance --- +## Benchmark Execution Policy + +These benchmark commands intentionally separate full performance runs from pull request smoke validation: + +- Running `dotnet run --project Cerbi-Benchmark-Tests/Cerbi-Benchmark-Tests.csproj --configuration Release` with no BenchmarkDotNet arguments executes the complete `PopularLoggerBenchmarks` suite. This preserves existing non-interactive full-run scripts and reproduction commands. +- Passing BenchmarkDotNet CLI arguments, such as `--filter`, runs only the selected benchmark set requested by the caller. Use this for targeted diagnostics and benchmark discovery checks. +- Pull request CI uses an explicit filtered Dry job for `MS_Log_Plain` only. It proves restore, Release build, benchmark discovery, execution, and artifact generation without running the full long suite on every PR. +- PR smoke results must not be published as performance claims or copied into the website metrics. Dry smoke output is validation evidence only. +- Official published numbers require a dedicated full benchmark run with the complete suite, stable hardware/runtime conditions, and archived BenchmarkDotNet results. + +--- + ## Hero Section ### Headline