Skip to content

Commit e2a9202

Browse files
committed
t
1 parent e3150e5 commit e2a9202

File tree

115 files changed

+3862
-149
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+3862
-149
lines changed

.editorconfig

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ indent_style = space
77
indent_size = 4
88
insert_final_newline = true
99
trim_trailing_whitespace = true
10+
end_of_line = lf
1011

1112
# Visual Studio Spell checker configs (https://learn.microsoft.com/en-us/visualstudio/ide/text-spell-checker?view=vs-2022#how-to-customize-the-spell-checker)
1213
spelling_exclusion_path = ./exclusion.dic

.github/workflows/benchmark.yml

+21-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
name: Benchmark
2+
run-name: Benchmark(${{ inputs.configKey }})
23

34
on:
45
workflow_dispatch:
6+
inputs:
7+
configKey:
8+
type: choice
9+
description: Specify benchmark config key
10+
default: Default
11+
options:
12+
- Default
13+
- TargetFrameworks
14+
- SystemLinq
15+
filter:
16+
type: string
17+
description: Specify benchmark filter text
18+
default: '*'
19+
verbose:
20+
type: boolean
21+
description: Set `true` to output BenchmarkDotNet logs to console.
22+
default: false
523

624
jobs:
725
benchmark:
826
runs-on: ubuntu-latest
9-
timeout-minutes: 60 # Default: 360 minutes
27+
timeout-minutes: 360 # Default: 360 minutes
1028
strategy:
1129
fail-fast: true
1230
steps:
@@ -17,7 +35,8 @@ jobs:
1735
- name: Run Benchmarks
1836
working-directory: sandbox/Benchmark
1937
run: |
20-
dotnet run -c Release --framework net9.0 --no-build --no-launch-profile -- --filter "*"
38+
mkdir BenchmarkDotNet.Artifacts
39+
dotnet run -c Release --framework net9.0 --no-build --no-launch-profile -- --filter "${{ github.event.inputs.filter }}" -- ${{ github.event.inputs.configKey }} | tee BenchmarkDotNet.Artifacts/console.log
2140
2241
- name: Upload artifacts
2342
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 #v4.6.1

sandbox/Benchmark/Benchmark.csproj

+35-22
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,9 @@
1919
<!-- Add .NET 10 support when running build inside Visual Studio Preview-->
2020
<PropertyGroup Condition="'$(BuildingInsideVisualStudio)' != '' AND $(VisualStudioDir.Contains('Preview'))">
2121
<!-- TODO: Temporary comment out, because BenchmarkDotNet 0.14.0 don't support .NET 10 -->
22-
<!--<TargetFrameworks>$(TargetFrameworks);net10.0</TargetFrameworks>-->
22+
<!--<TargetFrameworks>net10.0;$(TargetFrameworks)</TargetFrameworks>-->
2323
</PropertyGroup>
2424

25-
<!-- Settings for NuGetVersionsBenchmarkConfig -->
26-
<PropertyGroup>
27-
<!-- Define benchmark target versions.First element is selected as baseline version. -->
28-
<TargetZLinqVersions>0.9.3</TargetZLinqVersions>
29-
</PropertyGroup>
30-
31-
<ItemGroup>
32-
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
33-
<_Parameter1>TargetZLinqVersions</_Parameter1>
34-
<_Parameter2>$(TargetZLinqVersions)</_Parameter2>
35-
</AssemblyAttribute>
36-
</ItemGroup>
37-
3825
<ItemGroup>
3926
<PackageReference Include="AndanteSoft.SpanLinq" Version="1.0.1" />
4027
<PackageReference Include="LinqAF" Version="3.0.0" />
@@ -50,17 +37,43 @@
5037
<PackageReference Include="Kokuban" Version="0.2.0" />
5138
</ItemGroup>
5239

53-
<ItemGroup Condition="'$(UseZLinqNuGetPackage)' != 'true'">
54-
<ProjectReference Include="..\..\src\ZLinq\ZLinq.csproj" />
40+
<ItemGroup>
41+
<!-- Enable implicit usings of BenchmarkDotNet namespaces -->
42+
<Using Include="BenchmarkDotNet.Attributes" />
43+
<Using Include="BenchmarkDotNet.Configs" />
44+
<Using Include="BenchmarkDotNet.Engines" />
45+
<!-- Enable implicit usings for Immutable/Frozen Collections to use System.Linq extension methods -->
46+
<Using Include="System.Collections.Immutable" />
47+
<Using Include="System.Collections.Frozen" />
5548
</ItemGroup>
5649

57-
<!-- If `UseDocfxNuGetPackage` property is enabled. Use baseline NuGet package -->
58-
<ItemGroup Condition="'$(UseZLinqNuGetPackage)' == 'true'">
59-
<PackageReference Include="ZLinq" Version="$(TargetZLinqVersions.Split(';')[0])" />
50+
<ItemGroup>
51+
<ProjectReference Include="..\..\src\ZLinq\ZLinq.csproj" />
6052
</ItemGroup>
6153

62-
<!-- Custom target to cleanup `BenchmarkDotNet.Artifacts` directory-->
63-
<Target Name="CleanBenchmarkDotNetArtifacts" BeforeTargets="Clean" Condition="Exists('BenchmarkDotNet.Artifacts')">
64-
<RemoveDir Directories="BenchmarkDotNet.Artifacts" />
54+
<Choose>
55+
<!-- Settings for NuGetVersionsBenchmarkConfig -->
56+
<When Condition="$(Configuration.StartsWith('UseZLinqNuGetPackage'))">
57+
<PropertyGroup>
58+
<DefineConstants>$(DefineConstants);$(ZLinqDefineConstants)</DefineConstants>
59+
</PropertyGroup>
60+
<ItemGroup>
61+
<ProjectReference Remove="..\..\src\ZLinq\ZLinq.csproj" />
62+
<PackageReference Include="ZLinq" Version="$(TargetZLinqVersion)" />
63+
</ItemGroup>
64+
</When>
65+
<!-- Settings for SystemLinqBenchmarkConfig -->
66+
<When Condition="'$(Configuration)'=='SystemLinq'">
67+
<PropertyGroup>
68+
<DefineConstants>$(DefineConstants);USE_SYSTEM_LINQ</DefineConstants>
69+
</PropertyGroup>
70+
</When>
71+
</Choose>
72+
73+
<!-- Custom target to cleanup `obj`,`bin`, and `BenchmarkDotNet.Artifacts` directories -->
74+
<Target Name="CleanBenchmarkDotNetArtifacts" BeforeTargets="Clean" Condition="Exists('obj')">
75+
<RemoveDir ContinueOnError="WarnAndContinue" Directories="$(MSBuildThisFileDirectory)obj" />
76+
<RemoveDir ContinueOnError="WarnAndContinue" Directories="$(MSBuildThisFileDirectory)bin" />
77+
<RemoveDir ContinueOnError="WarnAndContinue" Directories="$(MSBuildThisFileDirectory)BenchmarkDotNet.Artifacts" />
6578
</Target>
6679
</Project>

sandbox/Benchmark/BenchmarkDotNet/BenchmarkConfigs/BaseBenchmarkConfig.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
using BenchmarkDotNet.Columns;
2-
using BenchmarkDotNet.Configs;
1+
using BenchmarkDotNet.Columns;
32
using BenchmarkDotNet.Diagnosers;
4-
using BenchmarkDotNet.Engines;
53
using BenchmarkDotNet.Exporters;
64
using BenchmarkDotNet.Jobs;
75
using BenchmarkDotNet.Loggers;
@@ -81,6 +79,7 @@ protected virtual void AddColumnProviders()
8179

8280
protected virtual void AddFilters()
8381
{
82+
AddFilter(TargetFrameworkFilter.Instance);
8483
}
8584

8685
protected virtual void AddDiagnosers()
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
using System.Reflection;
2-
using BenchmarkDotNet.Columns;
1+
using BenchmarkDotNet.Columns;
32
using BenchmarkDotNet.Jobs;
3+
using System.Text;
4+
using System.Text.Json.Nodes;
45

56
namespace Benchmark;
67

78
/// <summary>
8-
/// BenchmarkConfig.
9+
/// BenchmarkConfig that run benchmarks to compare performance between LocalBuild/NuGet version.
910
/// </summary>
1011
public class NuGetVersionsBenchmarkConfig : BaseBenchmarkConfig
1112
{
@@ -15,27 +16,35 @@ public NuGetVersionsBenchmarkConfig() : base()
1516
.WithToolchain(Constants.DefaultToolchain)
1617
.Freeze();
1718

19+
string[] targetNuGetVersions = [GetCurrentZLinqVersion()];
20+
21+
// Note: Enable following code when comparing multiple ZLinq versions.
22+
// targetNuGetVersions = GetTargetZlinqVersions();
23+
1824
// 1. Add jobs that use ZLinq NuGet package with specified versions
19-
var targetNugetVersions = GetTargetNuGetVersions();
20-
foreach (var targetVersion in targetNugetVersions)
25+
foreach (var targetVersion in targetNuGetVersions)
2126
{
2227
var job = baseJobConfig
23-
.WithArguments([
24-
new MsBuildArgument("/p:UseZLinqNuGetPackage=true"),
25-
new MsBuildArgument("/p:DefineConstants=" + $"ZLinq_{targetVersion.Replace('.', '_')}"),
26-
])
27-
.WithNuGet("ZLinq", targetVersion)
28+
.WithCustomBuildConfiguration(GetCustomBuildConfigurationName(targetVersion))
29+
.WithArguments(
30+
[
31+
new MsBuildArgument($"/p:{Constants.MSBuildProperties.TargetZLinqVersion}={targetVersion}"),
32+
new MsBuildArgument($"/p:{Constants.MSBuildProperties.ZLinqDefineConstants}={GetDefineConstantsValue(targetVersion)}"),
33+
// TODO: Enable following code and remove settings from csproj after .NET SDK issue is resolved. See:https://github.com/dotnet/sdk/issues/45638
34+
// new MsBuildArgument($"/p:DefineConstants={GetDefineConstantsValue(targetVersion)}"),
35+
])
2836
.WithId($"v{targetVersion}");
2937

30-
bool isBaseline = targetVersion == targetNugetVersions.First();
38+
bool isBaseline = targetVersion == targetNuGetVersions.First();
3139
if (isBaseline)
3240
AddJob(job.AsBaseline());
3341
else
3442
AddJob(job);
3543
}
3644

37-
// 2. Add local build job.
38-
AddJob(baseJobConfig.WithId("vLocalBuild")); // Add `v` prefix to change display order.
45+
// 2. Add LocalBuild job.
46+
if (targetNuGetVersions.Length == 1)
47+
AddJob(baseJobConfig.WithId("vLocalBuild")); // Add `v` prefix to change display order.
3948

4049
// Configure additional settings
4150
AddConfigurations();
@@ -45,16 +54,86 @@ protected override void AddColumnHidingRules()
4554
{
4655
HideColumns(Column.Arguments);
4756
HideColumns(Column.NuGetReferences);
57+
HideColumns(Column.BuildConfiguration);
58+
}
59+
60+
/// <summary>
61+
/// Gets DefineConstants settings for using target ZLinq version.
62+
/// </summary>
63+
private static string GetDefineConstantsValue(string versionText)
64+
{
65+
// Currently it need to escape MSBuild special characters (https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-special-characters)
66+
// Because MSBuildArgument is passed as commandline parameter.
67+
// See: https://github.com/dotnet/BenchmarkDotNet/issues/2719
68+
const string ListSeparator = "%3B"; // Escapec semicolon char.
69+
70+
StringBuilder sb = new();
71+
72+
// Add target package version symbol
73+
sb.Append($"{ListSeparator}ZLINQ_{versionText.Replace('.', '_')}");
74+
75+
// v1.2.0 or later supports Immutable/Frozen collection.
76+
var version = Version.Parse(versionText);
77+
if (version >= new Version(1, 2, 0))
78+
sb.Append($"{ListSeparator}{Constants.DefineConstants.ZLINQ_1_2_0_OR_GREATER}");
79+
80+
// v1.3.1 contains following breaking changes
81+
// - WhereArray signature is changed to ArrayWhere.
82+
// - ArraySelect/ListSelect optimization for Select from Array.
83+
if (version >= new Version(1, 3, 1))
84+
sb.Append($"{ListSeparator}{Constants.DefineConstants.ZLINQ_1_3_1_OR_GREATER}");
85+
86+
// v1.4.0 changes the return value of ToArrayPool to PooledArray<T>,
87+
if (version >= new Version(1, 4, 0))
88+
sb.Append($"{ListSeparator}{Constants.DefineConstants.ZLINQ_1_4_0_OR_GREATER}");
89+
90+
return sb.ToString();
91+
}
92+
93+
private static string GetCurrentZLinqVersion()
94+
{
95+
DirectoryInfo? dirInfo = new DirectoryInfo(AppContext.BaseDirectory);
96+
while (true)
97+
{
98+
if (dirInfo.GetFiles().Any(x => x.Name == "ZLinq.slnx"))
99+
break;
100+
101+
dirInfo = dirInfo.Parent;
102+
if (dirInfo == null)
103+
throw new FileNotFoundException("ZLinq.slnx is not found.");
104+
}
105+
106+
var solutionDir = dirInfo.FullName;
107+
var resolvedPath = Path.Combine(solutionDir, "src/ZLinq.Unity/Assets/ZLinq.Unity/package.json");
108+
if (!File.Exists(resolvedPath) && !Directory.Exists(resolvedPath))
109+
throw new FileNotFoundException($"File is not found. path: {resolvedPath}");
110+
111+
var json = File.ReadAllText(resolvedPath);
112+
var latestVersion = JsonNode.Parse(json)!["version"]!.GetValue<string>();
113+
return latestVersion;
48114
}
49115

50-
private static string[] GetTargetNuGetVersions()
116+
private static string[] GetTargetZlinqVersions()
51117
{
52-
var assembly = Assembly.GetExecutingAssembly();
53-
var assemblyMetadata = assembly.GetCustomAttributes<AssemblyMetadataAttribute>()
54-
.First(x => x.Key == "TargetZLinqVersions")
55-
.Value!;
118+
// Currently multi NuGet versions benchmark is not supported.
119+
// It require following BenchmarkDotNet feature.
120+
// https://github.com/dotnet/BenchmarkDotNet/pull/2676
121+
throw new NotSupportedException("Currently multi NuGet versions benchmark is not supported.");
56122

57-
return assemblyMetadata.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
58-
.ToArray();
123+
// Available package versions: https://api.nuget.org/v3-flatcontainer/ZLinq/index.json
124+
////return
125+
////[
126+
//// "1.0.0",
127+
//// "1.1.0",
128+
//// "1.2.0",
129+
//// "1.3.0",
130+
//// "1.3.1",
131+
//// "1.4.0",
132+
//// "1.4.1",
133+
//// "1.4.2",
134+
////];
59135
}
136+
137+
private static string GetCustomBuildConfigurationName(string targetVersion)
138+
=> $"{Constants.CustomBuildConfigurations.UseZLinqNuGetPackage}_{targetVersion.Replace(".", "_")}";
60139
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
using BenchmarkDotNet.Analysers;
2+
using BenchmarkDotNet.Columns;
3+
using BenchmarkDotNet.Jobs;
4+
using BenchmarkDotNet.Order;
5+
6+
namespace Benchmark;
7+
8+
/// <summary>
9+
/// BenchmarkConfig that run benchmarks with System.Linq
10+
/// </summary>
11+
public class SystemLinqBenchmarkConfig : BaseBenchmarkConfig
12+
{
13+
internal const string SystemLinqJobId = "SystemLinq";
14+
internal const string ZLinqJobId = "ZLinq";
15+
16+
public SystemLinqBenchmarkConfig() : base()
17+
{
18+
var baseJobConfig = GetBaseJobConfig().Freeze();
19+
20+
// Add job for System.Linq benchmarks.
21+
AddJob(baseJobConfig.WithToolchain(Constants.DefaultToolchain)
22+
.WithCustomBuildConfiguration(Constants.CustomBuildConfigurations.SystemLinq)
23+
// TODO: Enable following code and remove settings from csproj after .NET SDK issue is resolved. See:https://github.com/dotnet/sdk/issues/45638
24+
//.WithArguments(
25+
//[
26+
// new MsBuildArgument("/p:DefineConstants=USE_SYSTEM_LINQ")
27+
//])
28+
.WithId(SystemLinqJobId)
29+
.AsBaseline());
30+
31+
// Add job for ZLinq benchmarks.
32+
AddJob(baseJobConfig.WithToolchain(Constants.DefaultToolchain)
33+
.WithId(Options.HasFlag(ConfigOptions.KeepBenchmarkFiles)
34+
? $"{ZLinqJobId}_" // Needs extra suffix to avoid conflict assembly name. // TODO: It can be removed after BenchmarkDotNet v1.40.1 is release.
35+
: ZLinqJobId));
36+
37+
// Show summary with declared order (Default: execution order)
38+
WithOrderer(new DefaultOrderer(summaryOrderPolicy: SummaryOrderPolicy.Declared));
39+
40+
// Configure additional settings.
41+
AddConfigurations();
42+
}
43+
44+
protected override void AddAnalyzers()
45+
{
46+
// Remove BaselineCustomAnalyzer to suppress warning.
47+
// Because baseline benchmark might be excluded by filter.
48+
var analyzers = DefaultConfig.Instance
49+
.GetAnalysers()
50+
.Where(x => x is not BaselineCustomAnalyzer)
51+
.ToArray();
52+
53+
AddAnalyser(analyzers);
54+
}
55+
56+
protected override void AddColumnHidingRules()
57+
{
58+
// HideColumns(Column.Toolchain);
59+
HideColumns(Column.Arguments);
60+
HideColumns(Column.BuildConfiguration);
61+
}
62+
63+
protected override void AddFilters()
64+
{
65+
base.AddFilters();
66+
AddFilter(new ZLinqBenchmarkFilter());
67+
}
68+
69+
protected override void AddLogicalGroupRules()
70+
{
71+
AddLogicalGroupRules(
72+
[
73+
BenchmarkLogicalGroupRule.ByCategory,
74+
BenchmarkLogicalGroupRule.ByMethod,
75+
]);
76+
}
77+
}

0 commit comments

Comments
 (0)