Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
948e28b
:fire: remove repo template files
gimlichael Dec 8, 2025
856dbca
:sparkles: add extensibility layer for benchmarkdotnet
gimlichael Dec 8, 2025
69ad4fe
:test_tube: add comprehensive tests for BenchmarkWorkspaceOptions
gimlichael Dec 8, 2025
e7ec032
:rocket: add dedicated benchmarking suite and runner projects
gimlichael Dec 9, 2025
6aeb59e
:chart_with_upwards_trend: add benchmarkdotnet github reports for wor…
gimlichael Dec 9, 2025
a65dcce
:lock: refactor assembly resolution for thread safety and speed
gimlichael Dec 9, 2025
ed120db
:memo: update ai docs for this repository
gimlichael Dec 9, 2025
54e3de1
:rocket: add console integration for project
gimlichael Dec 9, 2025
bda283c
:heavy_plus_sign: add solution file for project organization
gimlichael Dec 9, 2025
5d35470
:recycle: update branding, frameworks, and benchmark build settings
gimlichael Dec 9, 2025
a1cf015
:wastebasket: remove release notes file prop, add clean for benchmark…
gimlichael Dec 9, 2025
a3a0628
:arrow_up: bump dependencies
gimlichael Dec 9, 2025
42167d2
:sparkles: add benchmark suite for core classes and operations
gimlichael Dec 11, 2025
e37b15d
:recycle: migrate to .slnx format
gimlichael Dec 11, 2025
7eaaa7f
:arrow_up: bump dependencies
gimlichael Dec 11, 2025
f8815ad
:memo: update benchmark naming and placement guidelines
gimlichael Dec 11, 2025
3d430f7
:construction_worker: update ci pipeline for BenchmarkDotNet
gimlichael Dec 11, 2025
bccb3d4
:fire: remove template release notes, readme, and icon from project
gimlichael Dec 11, 2025
f9940f5
:bookmark: update changelog for initial stable release of packages
gimlichael Dec 11, 2025
18608ce
:bookmark: add package release notes for BenchmarkDotNet extensions
gimlichael Dec 11, 2025
d9b5d20
✨ update type parameter in AddBenchmarkWorkspace method for clarity
gimlichael Dec 11, 2025
c524199
:art: add new icon.png image to project
gimlichael Dec 11, 2025
469effd
✨ update docfx to match benchmarkdotnet
gimlichael Dec 11, 2025
9e9288a
:package: updated NuGet package definition
gimlichael Dec 11, 2025
e69f60c
:art: add property group with description and tags to csproj files
gimlichael Dec 11, 2025
4254e60
:art: update exception documentation for ConfigureBenchmarkDotNet method
gimlichael Dec 11, 2025
9300d7d
:art: update readme to reflect benchmarkdotnet extensions
gimlichael Dec 11, 2025
91a2c47
:chart_with_upwards_trend: add benchmark reports
gimlichael Dec 11, 2025
f889f3f
:art: update readme with folder structure and usage examples
gimlichael Dec 11, 2025
4788207
:art: fix os matrix formatting in ci pipeline configuration
gimlichael Dec 11, 2025
0af72cd
:pencil2: fix typo in benchmarkdotnet project/repo names in ci-pipeline
gimlichael Dec 12, 2025
d89b6b1
:adhesive_bandage: handle null GetEntryAssembly in BenchmarkProgram ctor
gimlichael Dec 12, 2025
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
50 changes: 25 additions & 25 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
description: 'Writing Unit Tests in ClassLibrary1'
description: 'Writing Unit Tests in Codebelt.Extensions.BenchmarkDotNet'
applyTo: "**/*.{cs,csproj}"
---

# Writing Unit Tests in ClassLibrary1
This document provides instructions for writing unit tests in the ClassLibrary1 codebase. Please follow these guidelines to ensure consistency and maintainability.
# Writing Unit Tests in Codebelt.Extensions.BenchmarkDotNet
This document provides instructions for writing unit tests in the Codebelt.Extensions.BenchmarkDotNet codebase. Please follow these guidelines to ensure consistency and maintainability.

## 1. Base Class

Expand Down Expand Up @@ -48,33 +48,33 @@ namespace Your.Namespace
## 5. File and Namespace Organization

- Place test files in the appropriate test project and folder structure.
- Use namespaces that mirror the source code structure. The namespace of a test file MUST match the namespace of the System Under Test (SUT). Do NOT append ".Tests", ".Benchmarks" or similar suffixes to the namespace. Only the assembly/project name should indicate that the file is a test/benchmark (for example: ClassLibrary1.Foo.Tests assembly, but namespace ClassLibrary1.Foo).
- Use namespaces that mirror the source code structure. The namespace of a test file MUST match the namespace of the System Under Test (SUT). Do NOT append ".Tests", ".Benchmarks" or similar suffixes to the namespace. Only the assembly/project name should indicate that the file is a test/benchmark (for example: Codebelt.Extensions.BenchmarkDotNet.Foo.Tests assembly, but namespace Codebelt.Extensions.BenchmarkDotNet.Foo).
- Example: If the SUT class is declared as:
```csharp
namespace ClassLibrary1.Foo.Bar
namespace Codebelt.Extensions.BenchmarkDotNet.Foo.Bar
{
public class Zoo { /* ... */ }
}
```
then the corresponding unit test class must use the exact same namespace:
```csharp
namespace ClassLibrary1.Foo.Bar
namespace Codebelt.Extensions.BenchmarkDotNet.Foo.Bar
{
public class ZooTest : Test { /* ... */ }
}
```
- Do NOT use:
```csharp
namespace ClassLibrary1.Foo.Bar.Tests { /* ... */ } // ❌
namespace ClassLibrary1.Foo.Bar.Benchmarks { /* ... */ } // ❌
namespace Codebelt.Extensions.BenchmarkDotNet.Foo.Bar.Tests { /* ... */ } // ❌
namespace Codebelt.Extensions.BenchmarkDotNet.Foo.Bar.Benchmarks { /* ... */ } // ❌
```
- The unit tests for the ClassLibrary1.Foo assembly live in the ClassLibrary1.Foo.Tests assembly.
- The functional tests for the ClassLibrary1.Foo assembly live in the ClassLibrary1.Foo.FunctionalTests assembly.
- Test class names end with Test and live in the same namespace as the class being tested, e.g., the unit tests for the Boo class that resides in the ClassLibrary1.Foo assembly would be named BooTest and placed in the ClassLibrary1.Foo namespace in the ClassLibrary1.Foo.Tests assembly.
- The unit tests for the Codebelt.Extensions.BenchmarkDotNet.Foo assembly live in the Codebelt.Extensions.BenchmarkDotNet.Foo.Tests assembly.
- The functional tests for the Codebelt.Extensions.BenchmarkDotNet.Foo assembly live in the Codebelt.Extensions.BenchmarkDotNet.Foo.FunctionalTests assembly.
- Test class names end with Test and live in the same namespace as the class being tested, e.g., the unit tests for the Boo class that resides in the Codebelt.Extensions.BenchmarkDotNet.Foo assembly would be named BooTest and placed in the Codebelt.Extensions.BenchmarkDotNet.Foo namespace in the Codebelt.Extensions.BenchmarkDotNet.Foo.Tests assembly.
- Modify the associated .csproj file to override the root namespace so the compiled namespace matches the SUT. Example:
```xml
<PropertyGroup>
<RootNamespace>ClassLibrary1.Foo</RootNamespace>
<RootNamespace>Codebelt.Extensions.BenchmarkDotNet.Foo</RootNamespace>
</PropertyGroup>
```
- When generating test scaffolding automatically, resolve the SUT's namespace from the source file (or project/assembly metadata) and use that exact namespace in the test file header.
Expand All @@ -91,7 +91,7 @@ using System.Globalization;
using Codebelt.Extensions.Xunit;
using Xunit;

namespace ClassLibrary1
namespace Codebelt.Extensions.BenchmarkDotNet
{
/// <summary>
/// Tests for the <see cref="DateSpan"/> class.
Expand Down Expand Up @@ -150,29 +150,29 @@ namespace ClassLibrary1
- Never mock IMarshaller; always use a new instance of JsonMarshaller.

---
description: 'Writing Performance Tests in ClassLibrary1'
description: 'Writing Performance Tests in Codebelt.Extensions.BenchmarkDotNet'
applyTo: "tuning/**, **/*Benchmark*.cs"
---

# Writing Performance Tests in ClassLibrary1
This document provides guidance for writing performance tests (benchmarks) in the ClassLibrary1 codebase using BenchmarkDotNet. Follow these guidelines to keep benchmarks consistent, readable, and comparable.
# Writing Performance Tests in Codebelt.Extensions.BenchmarkDotNet
This document provides guidance for writing performance tests (benchmarks) in the Codebelt.Extensions.BenchmarkDotNet codebase using BenchmarkDotNet. Follow these guidelines to keep benchmarks consistent, readable, and comparable.

## 1. Naming and Placement

- Place micro- and component-benchmarks under the `tuning/` folder or in projects named `*.Benchmarks`.
- Place benchmark files in the appropriate benchmark project and folder structure.
- Use namespaces that mirror the source code structure, e.g. do not suffix with `Benchmarks`.
- Namespace rule: DO NOT append `.Benchmarks` to the namespace. Benchmarks must live in the same namespace as the production assembly. Example: if the production assembly uses `namespace ClassLibrary1.Security.Cryptography`, the benchmark file should also use:
- Namespace rule: DO NOT append `.Benchmarks` to the namespace. Benchmarks must live in the same namespace as the production assembly. Example: if the production assembly uses `namespace Codebelt.Extensions.BenchmarkDotNet.Security.Cryptography`, the benchmark file should also use:
```
namespace ClassLibrary1.Security.Cryptography
namespace Codebelt.Extensions.BenchmarkDotNet.Security.Cryptography
{
public class Sha512256Benchmark { /* ... */ }
}
```
The class name may end with `Benchmark`, but the namespace must match the assembly (no `.Benchmarks` suffix).
- The benchmarks for the ClassLibrary1.Bar assembly live in the ClassLibrary1.Bar.Benchmarks assembly.
- Benchmark class names end with Benchmark and live in the same namespace as the class being measured, e.g., the benchmarks for the Zoo class that resides in the ClassLibrary1.Bar assembly would be named ZooBenchmark and placed in the ClassLibrary1.Bar namespace in the ClassLibrary1.Bar.Benchmarks assembly.
- Modify the associated .csproj file to override the root namespace, e.g., <RootNamespace>ClassLibrary1.Bar</RootNamespace>.
The class name must end with `Benchmark`, but the namespace must match the assembly (no `.Benchmarks` suffix).
- The benchmarks for the Codebelt.Extensions.BenchmarkDotNet.Bar assembly live in the Codebelt.Extensions.BenchmarkDotNet.Bar.Benchmarks assembly.
- Benchmark class names end with Benchmark and live in the same namespace as the class being measured, e.g., the benchmarks for the Zoo class that resides in the Codebelt.Extensions.BenchmarkDotNet.Bar assembly would be named ZooBenchmark and placed in the Codebelt.Extensions.BenchmarkDotNet.Bar namespace in the Codebelt.Extensions.BenchmarkDotNet.Bar.Benchmarks assembly.
- Modify the associated .csproj file to override the root namespace, e.g., <RootNamespace>Codebelt.Extensions.BenchmarkDotNet.Bar</RootNamespace>.

## 2. Attributes and Configuration

Expand Down Expand Up @@ -203,7 +203,7 @@ The class name may end with `Benchmark`, but the namespace must match the assemb
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;

namespace ClassLibrary1
namespace Codebelt.Extensions.BenchmarkDotNet
{
[MemoryDiagnoser]
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
Expand Down Expand Up @@ -244,11 +244,11 @@ namespace ClassLibrary1
For further examples, refer to the benchmark files under the `tuning/` folder.

---
description: 'Writing XML documentation in ClassLibrary1'
description: 'Writing XML documentation in Codebelt.Extensions.BenchmarkDotNet'
applyTo: "**/*.cs"
---

# Writing XML documentation in ClassLibrary1
# Writing XML documentation in Codebelt.Extensions.BenchmarkDotNet
This document provides instructions for writing XML documentation.

## 1. Documentation Style
Expand Down
164 changes: 164 additions & 0 deletions .github/prompts/benchmark.prompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
---
mode: agent
description: 'Writing Performance Benchmarks in Codebelt.Extensions.BenchmarkDotNet'
---

# Benchmark Fixture Prompt (Codebelt.Extensions.BenchmarkDotNet Tuning Benchmarks)

This prompt defines how to generate performance tests (“benchmarks”) for the Codebelt.Extensions.BenchmarkDotNet codebase using BenchmarkDotNet.
Benchmarks in Codebelt.Extensions.BenchmarkDotNet are *not* unit tests — they are micro- or component-level performance measurements that belong under the `tuning/` directory and follow strict conventions.

Copilot must follow these guidelines when generating benchmark fixtures.

---

## 1. Naming and Placement

- All benchmark projects live under the `tuning/` folder.
Examples:
- `tuning/Codebelt.Extensions.BenchmarkDotNet.Benchmarks/`
- `tuning/Codebelt.Extensions.BenchmarkDotNet.Console.Benchmarks/`

- **Namespaces must NOT end with `.Benchmarks`.**
They must mirror the production assembly’s namespace.

Example:
If benchmarking a type inside `Codebelt.Extensions.BenchmarkDotNet.Console`, then:

```csharp
namespace Codebelt.Extensions.BenchmarkDotNet.Console
{
public class Sha512256Benchmark { … }
}
```

* **Benchmark class names must end with `Benchmark`.**
Example: `DateSpanBenchmark`, `FowlerNollVoBenchmark`.

* Benchmark files should be located in the matching benchmark project
(e.g., benchmarks for `Codebelt.Extensions.BenchmarkDotNet.Console` go in `Codebelt.Extensions.BenchmarkDotNet.Console.Benchmarks.csproj`).

* In the `.csproj` for each benchmark project, set the root namespace to the production namespace:

```xml
<RootNamespace>Codebelt.Extensions.BenchmarkDotNet.Console</RootNamespace>
```

---

## 2. Attributes and Configuration

Each benchmark class should use:

```csharp
[MemoryDiagnoser]
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
```

Optional but strongly recommended where meaningful:

* `[Params(...)]` — define small, medium, large input sizes.
* `[GlobalSetup]` — deterministic initialization of benchmark data.
* `[Benchmark(Description = "...")]` — always add descriptions.
* `[Benchmark(Baseline = true)]` — when comparing two implementations.

Avoid complex global configs; prefer explicit attributes inside the class.

---

## 3. Structure and Best Practices

A benchmark fixture must:

* Measure a **single logical operation** per benchmark method.
* Avoid I/O, networking, disk access, logging, or side effects.
* Avoid expensive setup inside `[Benchmark]` methods.
* Use deterministic data (e.g., seeded RNG or predefined constants).
* Use `[GlobalSetup]` to allocate buffers, random payloads, or reusable test data only once.
* Avoid shared mutable state unless reset per iteration.

Use representative input sizes such as:

```csharp
[Params(8, 256, 4096)]
public int Count { get; set; }
```

BenchmarkDotNet will run each benchmark for each parameter value.

---

## 4. Method Naming Conventions

Use descriptive names that communicate intent:

* `Parse_Short`
* `Parse_Long`
* `ComputeHash_Small`
* `ComputeHash_Large`
* `Serialize_Optimized`
* `Serialize_Baseline`

When comparing approaches, always list them clearly and tag one as the baseline.

---

## 5. Example Benchmark Fixture

```csharp
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;

namespace Codebelt.Extensions.BenchmarkDotNet
{
[MemoryDiagnoser]
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
public class SampleOperationBenchmark
{
[Params(8, 256, 4096)]
public int Count { get; set; }

private byte[] _payload;

[GlobalSetup]
public void Setup()
{
_payload = new byte[Count];
// deterministic initialization
}

[Benchmark(Baseline = true, Description = "Operation - baseline")]
public int Operation_Baseline() => SampleOperation.Process(_payload);

[Benchmark(Description = "Operation - optimized")]
public int Operation_Optimized() => SampleOperation.ProcessOptimized(_payload);
}
}
```

---

## 6. Reporting and CI

* Benchmark projects live exclusively under `tuning/`. They must not affect production builds.
* Heavy BenchmarkDotNet runs should *not* run in CI unless explicitly configured.
* Reports are produced by the Codebelt.Extensions.BenchmarkDotNet benchmark runner and stored under its configured artifacts directory.

---

## 7. Additional Guidelines

* Keep benchmark fixtures focused and readable.
* Document non-obvious reasoning in short comments.
* Prefer realistic but deterministic data sets.
* When benchmarks reveal regressions or improvements, reference the associated PR or issue in a comment.
* Shared benchmark helpers belong in `tuning/` projects, not in production code.

---

## Final Notes

* Benchmarks are performance tests, not unit tests.
* Use `[Benchmark]` only for pure performance measurement.
* Avoid `MethodImplOptions.NoInlining` unless absolutely necessary.
* Use small sets of meaningful benchmark scenarios — avoid combinatorial explosion.
12 changes: 7 additions & 5 deletions .github/workflows/ci-pipeline.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: ClassLibrary1 CI Pipeline
name: BenchmarkDotNet CI Pipeline
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix YAML newline style (CRLF vs LF) to satisfy yamllint. The lint error suggests the file is committed with \r\n; normalize to \n to avoid CI noise.

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 1-1: wrong new line character: expected \n

(new-lines)

🤖 Prompt for AI Agents
In .github/workflows/ci-pipeline.yml around line 1, the file currently uses CRLF
line endings which triggers yamllint; convert the file to use LF-only newlines.
Open the file in an editor or run a tool (e.g., dos2unix) or git commands (git
config core.autocrlf false; git rm --cached .github/workflows/ci-pipeline.yml;
git add --renormalize .github/workflows/ci-pipeline.yml) to normalize to \n,
commit the change, and optionally add a .gitattributes entry (*.yml text eol=lf)
to prevent future CRLF commits.

on:
pull_request:
branches: [main]
Expand All @@ -25,7 +25,7 @@ jobs:
uses: codebeltnet/jobs-dotnet-build/.github/workflows/default.yml@v3
with:
configuration: ${{ matrix.configuration }}
strong-name-key-filename: classlibrary1.snk
strong-name-key-filename: benchmarkdotnet.snk
secrets: inherit

pack:
Expand All @@ -52,14 +52,16 @@ jobs:
configuration: ${{ matrix.configuration }}
runs-on: ${{ matrix.os }}
build-switches: -p:SkipSignAssembly=true
build: true # we need to build due to xUnitv3
restore: true # we need to restore due to xUnitv3

sonarcloud:
name: call-sonarcloud
needs: [build, test]
uses: codebeltnet/jobs-sonarcloud/.github/workflows/default.yml@v3
with:
organization: yourorg
projectKey: classlibrary1
organization: geekle
projectKey: bemchmarkdotnet
version: ${{ needs.build.outputs.version }}
secrets: inherit

Expand All @@ -68,7 +70,7 @@ jobs:
needs: [build, test]
uses: codebeltnet/jobs-codecov/.github/workflows/default.yml@v1
with:
repository: yourorg/classlibrary1
repository: codebeltnet/bemchmarkdotnet
secrets: inherit

codeql:
Expand Down
9 changes: 0 additions & 9 deletions .nuget/ClassLibrary1/PackageReleaseNotes.txt

This file was deleted.

5 changes: 0 additions & 5 deletions .nuget/ClassLibrary1/README.md

This file was deleted.

Binary file removed .nuget/ClassLibrary1/icon.png
Binary file not shown.
46 changes: 0 additions & 46 deletions ClassLibrary1.sln

This file was deleted.

Loading
Loading