Skip to content

Commit 44f986f

Browse files
committed
Merge branch 'master' into reduce-async-overhead
# Conflicts: # src/BenchmarkDotNet/Engines/IEngine.cs
2 parents 70ae58c + 8c963ba commit 44f986f

File tree

109 files changed

+1668
-319
lines changed

Some content is hidden

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

109 files changed

+1668
-319
lines changed

.github/workflows/build.yaml

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ jobs:
1010
steps:
1111
- uses: actions/checkout@v2
1212
- name: Run
13-
run: ./build.ps1
13+
shell: cmd
14+
run: |
15+
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
16+
./build.bat
1417
build-linux:
1518
runs-on: ubuntu-latest
1619
steps:

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ tests/output/*
4848
artifacts/*
4949
BDN.Generated
5050
BenchmarkDotNet.Samples/Properties/launchSettings.json
51-
src/BenchmarkDotNet/Disassemblers/net461/*
51+
src/BenchmarkDotNet/Disassemblers/net462/*
52+
src/BenchmarkDotNet/Disassemblers/BenchmarkDotNet.Disassembler.*.nupkg
5253

5354
# Visual Studio 2015 cache/options directory
5455
.vs/

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ Four aspects define the design of these features:
120120

121121
### Simplicity
122122

123-
You shouldn't be an experience performance engineer if you want to write benchmarks.
123+
You shouldn't be an experienced performance engineer if you want to write benchmarks.
124124
You can design very complicated performance experiments in the declarative style using simple APIs.
125125

126126
For example, if you want to [parameterize](https://benchmarkdotnet.org/articles/features/parameterization.html) your benchmark,

build/Program.cs

+12-2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public class BuildContext : FrostingContext
5858

5959
private IAppVeyorProvider AppVeyor => this.BuildSystem().AppVeyor;
6060
public bool IsOnAppVeyorAndNotPr => AppVeyor.IsRunningOnAppVeyor && !AppVeyor.Environment.PullRequest.IsPullRequest;
61+
public bool IsOnAppVeyorAndBdnNightlyCiCd => IsOnAppVeyorAndNotPr && AppVeyor.Environment.Repository.Branch == "master" && this.IsRunningOnWindows();
6162
public bool IsLocalBuild => this.BuildSystem().IsLocalBuild;
6263
public bool IsCiBuild => !this.BuildSystem().IsLocalBuild;
6364

@@ -201,7 +202,7 @@ public void RunDocfx(FilePath docfxJson, string args = "")
201202

202203
public static class DocumentationHelper
203204
{
204-
public const string DocFxVersion = "2.57.2";
205+
public const string DocFxVersion = "2.59.3";
205206

206207
public static readonly string[] BdnAllVersions =
207208
{
@@ -360,6 +361,11 @@ public class AllTestsTask : FrostingTask<BuildContext>
360361
[IsDependentOn(typeof(BuildTask))]
361362
public class PackTask : FrostingTask<BuildContext>
362363
{
364+
public override bool ShouldRun(BuildContext context)
365+
{
366+
return context.IsOnAppVeyorAndBdnNightlyCiCd;
367+
}
368+
363369
public override void Run(BuildContext context)
364370
{
365371
var settingsSrc = new DotNetCorePackSettings
@@ -447,6 +453,10 @@ public override void Run(BuildContext context)
447453
}
448454
}
449455

456+
// In order to work around xref issues in DocFx, BenchmarkDotNet and BenchmarkDotNet.Annotations must be build
457+
// before running the DocFX_Build target. However, including a dependency on BuildTask here may have unwanted
458+
// side effects (CleanTask).
459+
// TODO: Define dependencies when a CI workflow scenario for using the "DocFX_Build" target exists.
450460
[TaskName("DocFX_Build")]
451461
[IsDependentOn(typeof(DocfxInstallTask))]
452462
[IsDependentOn(typeof(DocfxChangelogGenerateTask))]
@@ -467,4 +477,4 @@ public override void Run(BuildContext context)
467477
{
468478
context.RunDocfx(context.DocfxJsonFile, "--serve");
469479
}
470-
}
480+
}

build/common.props

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<NeutralLanguage>en-US</NeutralLanguage>
77
<Authors>.NET Foundation and contributors</Authors>
88
<PackageTags>benchmark;benchmarking;performance</PackageTags>
9-
<PackageIconUrl>https://raw.githubusercontent.com/dotnet/BenchmarkDotNet/master/docs/guide/logo.png</PackageIconUrl>
9+
<PackageIcon>package-icon.png</PackageIcon>
1010
<PackageProjectUrl>https://github.com/dotnet/BenchmarkDotNet</PackageProjectUrl>
1111
<PackageLicenseExpression>MIT</PackageLicenseExpression>
1212
<RepositoryType>git</RepositoryType>
@@ -20,6 +20,10 @@
2020
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CodingStyle.ruleset</CodeAnalysisRuleSet>
2121
</PropertyGroup>
2222

23+
<ItemGroup>
24+
<None Include="$(MSBuildThisFileDirectory)package-icon.png" Pack="True" PackagePath="" />
25+
</ItemGroup>
26+
2327
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
2428
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)strongNameKey.snk</AssemblyOriginatorKeyFile>
2529
<SignAssembly>true</SignAssembly>

build/package-icon.png

13.8 KB
Loading

docs/articles/configs/toolchains.md

+112-29
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,21 @@ Example: `dotnet run -c Release -- --coreRun "C:\Projects\corefx\bin\testhost\ne
190190

191191
## NativeAOT
192192

193-
BenchmarkDotNet supports [NativeAOT](https://github.com/dotnet/runtime/tree/main/src/coreclr/nativeaot/docs)! However, you might want to know how it works to get a better understanding of the results that you get.
193+
BenchmarkDotNet supports [NativeAOT](https://github.com/dotnet/runtime/tree/main/src/coreclr/nativeaot)! However, you might want to know how it works to get a better understanding of the results that you get.
194194

195-
* NativeAOT is a flavor of .NET Core. Which means that:
196-
* you have to target .NET Core to be able to build NativeAOT benchmarks (example: `<TargetFramework>net7.0</TargetFramework>` in the .csproj file)
197-
* you have to specify the NativeAOT runtime in an explicit way, either by using `[SimpleJob]` attribute or by using the fluent Job config API `Job.ShortRun.With(NativeAotRuntime.$version)` or console line arguments `--runtimes nativeaot7.0`
198-
* to run NativeAOT benchmark you run the app as a .NET Core/.NET process (example: `dotnet run -c Release -f net5.01`) and BenchmarkDotNet does all the NativeAOT compilation for you. If you want to check what files are generated you need to apply `[KeepBenchmarkFiles]` attribute to the class which defines benchmarks.
195+
As every AOT solution, NativeAOT has some [limitations](https://github.com/dotnet/runtime/blob/main/src/coreclr/nativeaot/docs/limitations.md) like limited reflection support or lack of dynamic assembly loading. Because of that, the host process (what you run from command line) is never an AOT process, but just a regular .NET process. This process (called Host process) uses reflection to read benchmarks metadata (find all `[Benchmark]` methods etc), generates a new project that references the benchmarks and compiles it using ILCompiler. Such compilation produces a native executable, which is later started by the Host process. This process (called Benchmark or Child process) performs the actual benchmarking and reports the results back to the Host process. By default BenchmarkDotNet uses the latest version of `Microsoft.DotNet.ILCompiler` to build the NativeAOT benchmark according to [this instructions](https://github.com/dotnet/runtime/blob/main/src/coreclr/nativeaot/docs/compiling.md).
199196

200-
By default BenchmarkDotNet uses the latest version of `Microsoft.DotNet.ILCompiler` to build the NativeAOT benchmark according to [this instructions](https://github.com/dotnet/runtime/blob/main/src/coreclr/nativeaot/docs/compiling.md).
197+
This is why you need to:
198+
- install [pre-requisites](https://github.com/dotnet/runtime/blob/main/src/coreclr/nativeaot/docs/prerequisites.md) required by NativeAOT compiler
199+
- target .NET to be able to run NativeAOT benchmarks (example: `<TargetFramework>net7.0</TargetFramework>` in the .csproj file)
200+
- run the app as a .NET process (example: `dotnet run -c Release -f net7.0`).
201+
- specify the NativeAOT runtime in an explicit way, either by using console line arguments `--runtimes nativeaot7.0` (the recommended approach), or by using`[SimpleJob]` attribute or by using the fluent Job config API `Job.ShortRun.With(NativeAotRuntime.Net70)`:
202+
203+
```cmd
204+
dotnet run -c Release -f net7.0 --runtimes nativeaot7.0
205+
```
206+
207+
or:
201208

202209
```cs
203210
var config = DefaultConfig.Instance
@@ -208,6 +215,8 @@ BenchmarkSwitcher
208215
.Run(args, config);
209216
```
210217

218+
or:
219+
211220
```cs
212221
[SimpleJob(RuntimeMoniker.NativeAot70)] // compiles the benchmarks as net7.0 and uses the latest NativeAOT to build a native app
213222
public class TheTypeWithBenchmarks
@@ -216,7 +225,7 @@ public class TheTypeWithBenchmarks
216225
}
217226
```
218227

219-
**Note**: BenchmarkDotNet is going to run `dotnet restore` on the auto-generated project. The first time it does so, it's going to take a **LOT** of time to download all the dependencies (few minutes). Just give it some time and don't press `Ctrl+C` too fast ;)
228+
### Customization
220229

221230
If you want to benchmark some particular version of NativeAOT (or from a different NuGet feed) you have to specify it in an explicit way:
222231

@@ -228,45 +237,119 @@ var config = DefaultConfig.Instance
228237
microsoftDotNetILCompilerVersion: "7.0.0-*", // the version goes here
229238
nuGetFeedUrl: "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json") // this address might change over time
230239
.DisplayName("NativeAOT NuGet")
231-
.TargetFrameworkMoniker("net5.0")
240+
.TargetFrameworkMoniker("net7.0")
232241
.ToToolchain()));
233242
```
234243

244+
The builder allows to configure more settings:
245+
- specify packages restore path by using `PackagesRestorePath($path)`
246+
- rooting all application assemblies by using `RootAllApplicationAssemblies($bool)`. This is disabled by default.
247+
- generating complete type metadata by using `IlcGenerateCompleteTypeMetadata($bool)`. This option is enabled by default.
248+
- generating stack trace metadata by using `IlcGenerateStackTraceData($bool)`. This option is enabled by default.
249+
- set optimization preference by using `IlcOptimizationPreference($value)`. The default is `Speed`, you can configure it to `Size` or nothing
250+
- set instruction set for the target OS, architecture and hardware by using `IlcInstructionSet($value)`. By default BDN recognizes most of the instruction sets on your machine and enables them.
251+
252+
BenchmarkDotNet supports [rd.xml](https://github.com/dotnet/runtime/blob/main/src/coreclr/nativeaot/docs/rd-xml-format.md) files. To get given file respected by BenchmarkDotNet you need to place it in the same folder as the project that defines benchmarks and name it `rd.xml` or in case of multiple files give them `.rd.xml` extension. The alternative to `rd.xml` files is annotating types with [DynamicallyAccessedMembers](https://devblogs.microsoft.com/dotnet/app-trimming-in-net-5/) attribute.
253+
254+
If given benchmark is not supported by NativeAOT, you need to apply `[AotFilter]` attribute for it. Example:
255+
256+
```cs
257+
[Benchmark]
258+
[AotFilter("Not supported by design.")]
259+
public object CreateInstanceNames() => System.Activator.CreateInstance(_assemblyName, _typeName);
260+
```
261+
262+
### Generated files
263+
264+
By default BenchmarkDotNet removes the generates files after finishing the run. To keep them on the disk you need to pass `--keepFiles true` command line argument or apply `[KeepBenchmarkFiles]` attribute to the class which defines benchmark(s). Then, read the folder from the tool output. In the example below it's `D:\projects\performance\artifacts\bin\MicroBenchmarks\Release\net7.0\Job-KRLVKQ`:
265+
266+
```log
267+
// ***** Building 1 exe(s) in Parallel: Start *****
268+
// start dotnet restore -r win-x64 /p:UseSharedCompilation=false /p:BuildInParallel=false /m:1 /p:Deterministic=true /p:Optimize=true in D:\projects\performance\artifacts\bin\MicroBenchmarks\Release\net7.0\Job-KRLVKQ
269+
// command took 2.74s and exited with 0
270+
// start dotnet build -c Release -r win-x64 --no-restore /p:UseSharedCompilation=false /p:BuildInParallel=false /m:1 /p:Deterministic=true /p:Optimize=true in D:\projects\performance\artifacts\bin\MicroBenchmarks\Release\net7.0\Job-KRLVKQ
271+
// command took 3.82s and exited with 0
272+
```
273+
274+
If you go to `D:\projects\performance\artifacts\bin\MicroBenchmarks\Release\net7.0\Job-KRLVKQ`, you can see the generated project file (named `BenchmarkDotNet.Autogenerated.csproj`), code (file name ends with `.notcs`) and find the native executable (in the `bin\**\native` subfolder). Example:
275+
276+
```cmd
277+
cd D:\projects\performance\artifacts\bin\MicroBenchmarks\Release\net7.0\Job-KRLVKQ
278+
cat .\BenchmarkDotNet.Autogenerated.csproj
279+
```
280+
281+
```log
282+
<Project Sdk="Microsoft.NET.Sdk">
283+
<PropertyGroup>
284+
<ImportDirectoryBuildProps>false</ImportDirectoryBuildProps>
285+
<ImportDirectoryBuildTargets>false</ImportDirectoryBuildTargets>
286+
<OutputType>Exe</OutputType>
287+
<TargetFramework>net7.0</TargetFramework>
288+
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
289+
<RuntimeFrameworkVersion></RuntimeFrameworkVersion>
290+
<AssemblyName>Job-KRLVKQ</AssemblyName>
291+
<AssemblyTitle>Job-KRLVKQ</AssemblyTitle>
292+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
293+
<PlatformTarget>x64</PlatformTarget>
294+
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
295+
<DebugSymbols>false</DebugSymbols>
296+
<UseSharedCompilation>false</UseSharedCompilation>
297+
<Deterministic>true</Deterministic>
298+
<RunAnalyzers>false</RunAnalyzers>
299+
<IlcOptimizationPreference>Speed</IlcOptimizationPreference>
300+
<TrimMode>link</TrimMode><TrimmerDefaultAction>link</TrimmerDefaultAction>
301+
<IlcGenerateCompleteTypeMetadata>True</IlcGenerateCompleteTypeMetadata>
302+
<IlcGenerateStackTraceData>True</IlcGenerateStackTraceData>
303+
<EnsureNETCoreAppRuntime>false</EnsureNETCoreAppRuntime>
304+
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
305+
</PropertyGroup>
306+
<PropertyGroup>
307+
<ServerGarbageCollection>false</ServerGarbageCollection>
308+
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
309+
</PropertyGroup>
310+
<ItemGroup>
311+
<Compile Include="Job-KRLVKQ.notcs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
312+
</ItemGroup>
313+
<ItemGroup>
314+
<PackageReference Include="Microsoft.DotNet.ILCompiler" Version="7.0.0-*" />
315+
<ProjectReference Include="D:\projects\performance\src\benchmarks\micro\MicroBenchmarks.csproj" />
316+
</ItemGroup>
317+
<ItemGroup>
318+
<RdXmlFile Include="bdn_generated.rd.xml" />
319+
</ItemGroup>
320+
<ItemGroup>
321+
<IlcArg Include="--instructionset:base,sse,sse2,sse3,sse4.1,sse4.2,avx,avx2,aes,bmi,bmi2,fma,lzcnt,pclmul,popcnt" />
322+
</ItemGroup>
323+
</Project>
324+
```
325+
235326
### Compiling source to native code using the ILCompiler you built
236327

237-
If you are a NativeAOT contributor and you want to benchmark your local build of NativeAOT you have to provide necessary info (IlcPath):
328+
If you are a NativeAOT contributor and you want to benchmark your local build of NativeAOT you have to provide necessary info (path to shipping packages).
329+
330+
You can do that from command line:
331+
332+
```cmd
333+
dotnet run -c Release -f net7.0 --runtimes nativeaot7.0 --ilcPackages D:\projects\runtime\artifacts\packages\Release\Shipping\
334+
```
335+
336+
or explicitly in the code:
337+
238338

239339
```cs
240340
var config = DefaultConfig.Instance
241341
.With(Job.ShortRun
242342
.With(NativeAotToolchain.CreateBuilder()
243-
.UseLocalBuild(@"C:\Projects\corert\bin\Windows_NT.x64.Release") // IlcPath
343+
.UseLocalBuild(@"C:\Projects\runtime\artifacts\packages\Release\Shipping\")
244344
.DisplayName("NativeAOT local build")
245345
.TargetFrameworkMoniker("net7.0")
246346
.ToToolchain()));
247347
```
248348

249-
BenchmarkDotNet is going to follow [these instructrions](https://github.com/dotnet/corert/blob/7f902d4d8b1c3280e60f5e06c71951a60da173fb/Documentation/how-to-build-and-run-ilcompiler-in-console-shell-prompt.md#compiling-source-to-native-code-using-the-ilcompiler-you-built) to get it working for you.
250-
251-
### Using CPP Code Generator
252-
253-
> This approach uses transpiler to convert IL to C++, and then uses platform specific C++ compiler and linker for compiling/linking the application. The transpiler is a lot less mature than the RyuJIT path. If you came here to give CoreRT a try on your .NET Core program, use the RyuJIT option above.
349+
BenchmarkDotNet is going to follow [these instructrions](https://github.com/dotnet/runtime/blob/main/docs/workflow/building/coreclr/nativeaot.md#building) to get it working for you.
254350

255-
If you want to test [CPP Code Generator](https://github.com/dotnet/corert/blob/7f902d4d8b1c3280e60f5e06c71951a60da173fb/Documentation/how-to-build-and-run-ilcompiler-in-console-shell-prompt.md#using-cpp-code-generator) you have to use `UseCppCodeGenerator` method:
256-
257-
```cs
258-
var config = DefaultConfig.Instance
259-
.With(Job.Default
260-
.With(
261-
NativeAotToolchain.CreateBuilder()
262-
.UseLocalBuild(@"C:\Projects\corert\bin\Windows_NT.x64.Release") // IlcPath
263-
.UseCppCodeGenerator() // ENABLE IT
264-
.TargetFrameworkMoniker("net7.0")
265-
.DisplayName("CPP")
266-
.ToToolchain()));
267-
```
351+
**Note**: BenchmarkDotNet is going to run `dotnet restore` on the auto-generated project and restore the packages to a temporary folder. It might take some time, but the next time you rebuild dotnet/runtime repo and run the same command BenchmarkDotNet is going to use the new ILCompiler package.
268352

269-
**Note**: You might get some `The method or operation is not implemented.` errors as of today if the code that you are trying to benchmark is using some features that are not implemented by NativeAOT/transpiler yet...
270353

271354
## Wasm
272355

docs/docfx.json

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
}
1616
],
1717
"dest": "api",
18+
"filter": "filter.yml",
1819
"properties": {
1920
"TargetFramework": "netstandard2.0"
2021
},
@@ -55,6 +56,9 @@
5556
"default",
5657
"template"
5758
],
59+
"xrefService": [
60+
"https://xref.docs.microsoft.com/query?uid={uid}"
61+
],
5862
"postProcessors": ["ExtractSearchIndex"],
5963
"markdownEngineName": "markdig",
6064
"noLangKeyword": false,

docs/filter.yml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
apiRules:
2+
- exclude:
3+
uidRegex: ^System\.Object
4+
type: member # Avoid list of inherited Object members for each type.

docs/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ Four aspects define the design of these features:
121121

122122
### Simplicity
123123

124-
You shouldn't be an experience performance engineer if you want to write benchmarks.
124+
You shouldn't be an experienced performance engineer if you want to write benchmarks.
125125
You can design very complicated performance experiments in the declarative style using simple APIs.
126126

127127
For example, if you want to [parameterize](https://benchmarkdotnet.org/articles/features/parameterization.html) your benchmark,

samples/BenchmarkDotNet.Samples.FSharp/BenchmarkDotNet.Samples.FSharp.fsproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
</PropertyGroup>
66
<PropertyGroup>
77
<OutputType>Exe</OutputType>
8-
<TargetFrameworks>net461;net6.0</TargetFrameworks>
8+
<TargetFrameworks>net462;net6.0</TargetFrameworks>
99
</PropertyGroup>
1010
<ItemGroup>
1111
<Compile Include="Program.fs" />

samples/BenchmarkDotNet.Samples/BenchmarkDotNet.Samples.csproj

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22
<Import Project="..\..\build\common.props" />
33
<PropertyGroup>
44
<AssemblyTitle>BenchmarkDotNet.Samples</AssemblyTitle>
5-
<TargetFrameworks>net461;net6.0</TargetFrameworks>
5+
<TargetFrameworks>net462;net6.0</TargetFrameworks>
66
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
77
<AssemblyName>BenchmarkDotNet.Samples</AssemblyName>
88
<OutputType>Exe</OutputType>
99
<PackageId>BenchmarkDotNet.Samples</PackageId>
1010
<GenerateDocumentationFile>false</GenerateDocumentationFile>
1111
<PlatformTarget>AnyCPU</PlatformTarget>
12-
<DebugType>pdbonly</DebugType>
1312
<DebugSymbols>true</DebugSymbols>
1413
<NoWarn>$(NoWarn);CA1018;CA5351</NoWarn>
1514
</PropertyGroup>
@@ -19,7 +18,7 @@
1918
<ItemGroup>
2019
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
2120
<PackageReference Include="System.Drawing.Common" Version="4.5.1" />
22-
<PackageReference Include="System.Memory" Version="4.5.3" />
21+
<PackageReference Include="System.Memory" Version="4.5.5" />
2322
</ItemGroup>
2423
<ItemGroup>
2524
<ProjectReference Include="..\..\src\BenchmarkDotNet\BenchmarkDotNet.csproj" />

0 commit comments

Comments
 (0)