Automated spellcheck for docs via GitHub Actions (and address all raised issues) (#2144)

* Add GH Action

* add cSpell Config

* Ignore team page

Mostly names

* capitalize GUID

* add some terms

* add known terms

* fix: "disassemblers"

* add known words

* ignore changelog

many names and many link to issues that will be copy/paste and could contain spelling errors

* more known terms

* Known terms.

* Fix: "priorities"

* fix: priorities

* known term

* add back-ticks

* fix: characteristic / minor grammar

* fix: variance

* add word

* back-ticks

* fix: "specify"

* back-ticks

* add terms

* front-matter ignore of configoptions

* back-ticks

* back-ticks

* add terms

* frontmatter ignore

Since term is only in front-matte

* fix: "log file"

* separate words from ignoreWords

* Fix branch for GH Action

* ignores of runstrategy in frontmatter
This commit is contained in:
Sean Killeen 2022-10-13 03:55:17 -04:00 коммит произвёл GitHub
Родитель 8d2379626e
Коммит f8e0a5c238
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
15 изменённых файлов: 208 добавлений и 49 удалений

28
.github/workflows/spellcheck.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,28 @@
name: Documentation Checks
on:
push:
branches:
- master
paths:
- "docs/**/*"
pull_request:
branches:
- master
paths:
- "docs/**/*"
jobs:
spellcheck:
name: "Docs: Spellcheck"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
name: Check out the code
- uses: actions/setup-node@v1
name: Setup node
with:
node-version: "16"
- run: npm install -g cspell
name: Install cSpell
- run: cspell --config ./cSpell.json "docs/**/*.md" --no-progress
name: Run cSpell

108
cSpell.json Normal file
Просмотреть файл

@ -0,0 +1,108 @@
{
"version": "0.2",
"language": "en",
"words": [
"Alloc",
"analyse",
"analyser",
"Analysers",
"Autofac",
"bitness",
"corlib",
"Cygwin",
"Diagnoser",
"diagnosers",
"disassemblers",
"disassm",
"Jits",
"Jitting",
"LINQ",
"microbenchmarking",
"microbenchmarks",
"Mispredict",
"Mispredictions",
"msbuild",
"Multimodal",
"multimodality",
"netcoreapp",
"powerplans",
"Pseudocode",
"runtimes",
"Serilog",
"Tailcall",
"toolchains",
"unmanaged"
],
"ignoreWords": [
"Akinshin",
"Andrey",
"Expecto",
"Jint",
"LoongArch64",
"macrobenchmark",
"MediatR",
"Nagórski's",
"Newtonsoft",
"NodaTime",
"Npgsql",
"Sitnik's",
"Wojciech",
"Avalonia",
"Gitter"
],
"patterns": [
{
"name": "Markdown links",
"pattern": "\\((.*)\\)",
"description": ""
},
{
"name": "Markdown code blocks",
"pattern": "/^(\\s*`{3,}).*[\\s\\S]*?^\\1/gmx",
"description": "Taken from the cSpell example at https://cspell.org/configuration/patterns/#verbose-regular-expressions"
},
{
"name": "Inline code blocks",
"pattern": "\\`([^\\`\\r\\n]+?)\\`",
"description": "https://stackoverflow.com/questions/41274241/how-to-capture-inline-markdown-code-but-not-a-markdown-code-fence-with-regex"
},
{
"name": "Link contents",
"pattern": "\\<a(.*)\\>",
"description": ""
},
{
"name": "Snippet references",
"pattern": "-- snippet:(.*)",
"description": ""
},
{
"name": "Snippet references 2",
"pattern": "\\<\\[sample:(.*)",
"description": "another kind of snippet reference"
},
{
"name": "Multi-line code blocks",
"pattern": "/^\\s*```[\\s\\S]*?^\\s*```/gm"
},
{
"name": "HTML Tags",
"pattern": "<[^>]*>",
"description": "Reference: https://stackoverflow.com/questions/11229831/regular-expression-to-remove-html-tags-from-a-string"
}
],
"ignoreRegExpList": [
"Markdown links",
"Markdown code blocks",
"Inline code blocks",
"Link contents",
"Snippet references",
"Snippet references 2",
"Multi-line code blocks",
"HTML Tags"
],
"ignorePaths": [
"docs/_changelog/**/*.md",
"docs/articles/team.md"
]
}

Просмотреть файл

@ -1,4 +1,5 @@
---
#cspell:ignore configoptions
uid: docs.configoptions
name: Configoptions
---

Просмотреть файл

@ -10,16 +10,16 @@ In this case, you can *filter* some of them with the help of *filters*.
Predefined filters:
| Filter Type | Filters benchmarks by | Console argument | Console example |
|---------------------|-----------------------------|------------------|----------------------------------|
| GlobFilter | Provided glob pattern | filter | --filter *Serializer*.ToStream |
| AttributesFilter | Provided attribute names | attribute | --attribute STAThread |
| AllCategoriesFilter | All Provided category names | categories | --allCategories Priority1 CoreFX |
| AnyCategoriesFilter | Any provided category names | anycategories | --anyCategories Json Xml |
| SimpleFilter | Provided lambda predicate | - | |
| NameFilter | Provided lambda predicate | - | |
| UnionFilter | Logical AND | - | |
| DisjunctionFilter | Logical OR | - | |
| Filter Type | Filters benchmarks by | Console argument | Console example |
|---------------------|-----------------------------|--------------------|----------------------------------|
| GlobFilter | Provided glob pattern | `filter` | --filter *Serializer*.ToStream |
| AttributesFilter | Provided attribute names | `attribute` | --attribute STAThread |
| AllCategoriesFilter | All Provided category names | `categories` | --allCategories Priority1 CoreFX |
| AnyCategoriesFilter | Any provided category names | `anycategories` | --anyCategories Json Xml |
| SimpleFilter | Provided lambda predicate | - | |
| NameFilter | Provided lambda predicate | - | |
| UnionFilter | Logical AND | - | |
| DisjunctionFilter | Logical OR | - | |
---
@ -27,4 +27,4 @@ Predefined filters:
[!include[IntroCategories](../samples/IntroCategories.md)]
[!include[IntroJoin](../samples/IntroJoin.md)]
[!include[IntroJoin](../samples/IntroJoin.md)]

Просмотреть файл

@ -12,9 +12,11 @@ Basically, a *job* describes how to run your benchmark. Practically, it's a set
There are several categories of characteristics which you can specify. Let's consider each category in detail.
### Id
It's a single string characteristic. It allows to name your job. This name will be used in logs and a part of a folder name with generated files for this job. `Id` doesn't affect benchmark results, but it can be useful for diagnostics. If you don't specify `Id`, random value will be chosen based on other characteristics
### Environment
`Environment` specifies an environment of the job. You can specify the following characteristics:
* `Platform`: `x86` or `x64`
@ -41,7 +43,8 @@ It's a single string characteristic. It allows to name your job. This name will
BenchmarkDotNet will use host process environment characteristics for non specified values.
### Run
In this category, you can specifiy how to benchmark each method.
In this category, you can specify how to benchmark each method.
* `RunStrategy`:
* `Throughput`: default strategy which allows to get good precision level
@ -61,16 +64,18 @@ In this category, you can specifiy how to benchmark each method.
Usually, you shouldn't specify such characteristics like `LaunchCount`, `WarmupCount`, `TargetCount`, or `IterationTime` because BenchmarkDotNet has a smart algorithm to choose these values automatically based on received measurements. You can specify it for testing purposes or when you are damn sure that you know the right characteristics for your benchmark (when you set `TargetCount` = `20` you should understand why `20` is a good value for your case).
### Accuracy
If you want to change the accuracy level, you should use the following characteristics instead of manually adjusting values of `WarmupCount`, `TargetCount`, and so on.
* `MaxRelativeError`, `MaxAbsoluteError`: Maximum acceptable error for a benchmark (by default, BenchmarkDotNet continue iterations until the actual error is less than the specified error). *In these two characteristics*, the error means half of 99.9% confidence interval. `MaxAbsoluteError` is an absolute `TimeInterval`; doesn't have a default value. `MaxRelativeError` defines max acceptable (`(<half of CI 99.9%>) / Mean`).
* `MinIterationTime`: Minimum time of a single iteration. Unlike `Run.IterationTime`, this characteristic specifies only the lower limit. In case of need, BenchmarkDotNet can increase this value.
* `MinInvokeCount`: Minimum about of target method invocation. Default value if `4` but you can decrease this value for cases when single invocations takes a lot of time.
* `EvaluateOverhead`: if you benchmark method takes nanoseconds, BenchmarkDotNet overhead can significantly affect measurements. If this characterics is enable, the overhead will be evaluated and subtracted from the result measurements. Default value is `true`.
* `EvaluateOverhead`: if your benchmark method takes nanoseconds, BenchmarkDotNet overhead can significantly affect measurements. If this characteristic is enabled, the overhead will be evaluated and subtracted from the result measurements. Default value is `true`.
* `WithOutlierMode`: sometimes you could have outliers in your measurements. Usually these are unexpected outliers which arose because of other processes activities. By default (`OutlierMode.RemoveUpper`), all upper outliers (which is larger than Q3) will be removed from the result measurements. However, some of benchmarks have *expected* outliers. In these situation, you expect that some of invocation can produce outliers measurements (e.g. in case of network activities, cache operations, and so on). If you want to see result statistics with these outliers, you should use `OutlierMode.DontRemove`. If you can also choose `OutlierMode.RemoveLower` (outliers which are smaller than Q1 will be removed) or `OutlierMode.RemoveAll` (all outliers will be removed). See also: @BenchmarkDotNet.Mathematics.OutlierMode
* `AnalyzeLaunchVariance`: this characteristic makes sense only if `Run.LaunchCount` is default. If this mode is enabled and, BenchmarkDotNet will try to perform several launches and detect if there is a veriance between launches. If this mode is disable, only one launch will be performed.
* `AnalyzeLaunchVariance`: this characteristic makes sense only if `Run.LaunchCount` is default. If this mode is enabled and, BenchmarkDotNet will try to perform several launches and detect if there is a variance between launches. If this mode is disable, only one launch will be performed.
### Infrastructure
Usually, you shouldn't specify any characteristics from this section, it can be used for advanced cases only.
* `Toolchain`: a toolchain which generates source code for target benchmark methods, builds it, and executes it. BenchmarkDotNet has own toolchains for .NET, .NET Core, Mono and CoreRT projects. If you want, you can define own toolchain.
@ -121,18 +126,24 @@ Basically, it's a good idea to start with predefined values (e.g. `EnvMode.RyuJi
Note that the job cannot be modified after it's added into config. Trying to set a value on property of the frozen job will throw an `InvalidOperationException`. Use the `Job.Frozen` property to determine if the code properties can be altered.
If you do want to create a new job based on frozen one (all predefined job values are frozen) you can use the `.With()` extension method
If you do want to create a new job based on frozen one (all predefined job values are frozen) you can use the `.With()` extension method
```cs
var newJob = Job.Dry.With(Platform.X64);
```
or pass the frozen value as a constructor argument
```c#
var newJob = new Job(Job.Dry) { Env = { Platform = Platform.X64 } };
```
or use the `.Apply()` method on unfrozen job
```c#
var newJob = new Job() { Env = { Platform = Platform.X64 } }.Apply(Job.Dry);
```
in any case the Id property will not be transfered and you must pass it explicitly (using the .ctor id argument or the `.WithId()` extension method).
### Attribute style

Просмотреть файл

@ -5,12 +5,12 @@ name: Validators
# Validators
A **validator** can validate your benchmarks before they are executed and produce validation errors.
If any of the validation errors is critical, then none of the benchmarks will get executed.
A **validator** can validate your benchmarks before they are executed and produce validation errors.
If any of the validation errors is critical, then none of the benchmarks will get executed.
Available validators are:
* `BaselineValidator.FailOnError` - it checks if more than 1 Benchmark per class has `Baseline = true` applied. This validator is mandatory.
* `JitOptimizationsValidator.(Dont)FailOnError` - it checks whether any of the referenced assemblies is non-optimized. DontFailOnError version is enabled by default.
* `JitOptimizationsValidator.(Dont)FailOnError` - it checks whether any of the referenced assemblies is non-optimized. `DontFailOnError` version is enabled by default.
* `ExecutionValidator.(Dont)FailOnError` - it checks if it is possible to run your benchmarks by executing each of them once. Optional.
* `ReturnValueValidator.(Dont)FailOnError` - it checks if non-void benchmarks return equal values. Optional.

Просмотреть файл

@ -25,11 +25,11 @@ The build currently depends on the following prerequisites:
- Install [Mono version 5 or higher](https://www.mono-project.com/download/stable/#download-lin)
- Install [fsharp package](https://fsharp.org/use/linux/)
- Install packages required to .NET Core SDK
- gettext
- libcurl4-openssl-dev
- libicu-dev
- libssl-dev
- libunwind8
- `gettext`
- `libcurl4-openssl-dev`
- `libicu-dev`
- `libssl-dev`
- `libunwind8`
- macOS
- Install [Mono version 5 or higher](https://www.mono-project.com/download/stable/#download-mac)
@ -40,15 +40,15 @@ After you have installed these pre-requisites, you can build the BenchmarkDotNet
Build has a number of options that you use. Some of the more important options are
- **skiptests** - do not run the tests. This can shorten build times quite a bit. On Windows: `.\build.ps1 --SkipTests=True` or `./build.sh --skiptests=true` on Linux/macOS.
- **`skiptests`** - do not run the tests. This can shorten build times quite a bit. On Windows: `.\build.ps1 --SkipTests=True` or `./build.sh --skiptests=true` on Linux/macOS.
- **configuration** - build the 'Release' or 'Debug' build type. Default value is 'Release'. On Windows: `.\build.ps1 -Configuration Debug` or `./build.sh --configuration debug` on Linux/macOS.
- **`configuration`** - build the 'Release' or 'Debug' build type. Default value is 'Release'. On Windows: `.\build.ps1 -Configuration Debug` or `./build.sh --configuration debug` on Linux/macOS.
- **target** - with this parameter you can run a specific target from build pipeline. Default value is 'Default' target. On Windows: `.\build.ps1 -Target Default` or `./build.sh --target default` on Linux/macOS. Available targets:
- **Default** - run all actions one by one.
- **Clean** - clean all `obj`, `bin` and `artifacts` directories.
- **Restore** - automatically execute `Clean` action and after that restore all NuGet dependencies.
- **Build** - automatically execute `Restore` action, then run MSBuild for the solution file.
- **FastTests** - automatically execute `Build` action, then run all tests from the BenchmarkDotNet.Tests project.
- **SlowTests** - automatically execute `Build` action, then run all tests from the BenchmarkDotNet.IntegrationTests project.
- **Pack** - automatically execute `Build` action and after that creates local NuGet packages.
- **`target`** - with this parameter you can run a specific target from build pipeline. Default value is 'Default' target. On Windows: `.\build.ps1 -Target Default` or `./build.sh --target default` on Linux/macOS. Available targets:
- **`Default`** - run all actions one by one.
- **`Clean`** - clean all `obj`, `bin` and `artifacts` directories.
- **`Restore`** - automatically execute `Clean` action and after that restore all NuGet dependencies.
- **`Build`** - automatically execute `Restore` action, then run MSBuild for the solution file.
- **`FastTests`** - automatically execute `Build` action, then run all tests from the BenchmarkDotNet.Tests project.
- **`SlowTests`** - automatically execute `Build` action, then run all tests from the BenchmarkDotNet.IntegrationTests project.
- **`Pack`** - automatically execute `Build` action and after that creates local NuGet packages.

Просмотреть файл

@ -13,11 +13,10 @@ We have 3 disassemblers:
The MonoDisassembler is very simple: it spawns Mono with the right arguments to get the asm, Mono prints the output to the console and we just parse it. Single class does the job: `MonoDisassembler`.
When it comes to Windows disassemblers it's not so easy. To obtain the disassm we are using ClrMD. ClrMD can attach only to the process of same bitness (architecture).
This is why we have two dissasemblers: x64 and x86. The code is the same (single class, linked in two projects) but compiled for two different architectures. We keep both disassemblers in the resources of the BenchmarkDotNet.dll. When we need the disassembler, we search for it in the resources, copy it to the disk and run (it's an exe).
This is why we have two disassemblers: x64 and x86. The code is the same (single class, linked in two projects) but compiled for two different architectures. We keep both disassemblers in the resources of the BenchmarkDotNet.dll. When we need the disassembler, we search for it in the resources, copy it to the disk and run (it's an exe).
On Linux it's simpler (only x64 is supported) and we don't spawn a new process (everything is done in-proc).
### How to debug the disassembler
You need to create a new console app project which executes the code that you would like to disassemble. In this app, you need to run the desired code (to get it jitted) and just don't exit before attaching the disassembler and getting the disassembly.

Просмотреть файл

@ -1,4 +1,5 @@
---
#cspell:ignore etwprofiler
uid: docs.etwprofiler
name: EtwProfiler
---
@ -60,7 +61,6 @@ class Program
* Passing `-p ETW` or `--profiler ETW` command line argument to `BenchmarkSwitcher`
## Configuration
To configure the new diagnoser you need to create an instance of `EtwProfilerConfig` class and pass it to the `EtwProfiler` constructor. The parameters that `EtwProfilerConfig` ctor takes are:

Просмотреть файл

@ -1,4 +1,5 @@
---
#cspell:ignore runstrategy
uid: docs.runstrategy
name: Choosing RunStrategy
---
@ -28,4 +29,4 @@ public class MyBenchmarkClass
[!include[IntroColdStart](../samples/IntroColdStart.md)]
[!include[IntroMonitoring](../samples/IntroMonitoring.md)]
[!include[IntroMonitoring](../samples/IntroMonitoring.md)]

Просмотреть файл

@ -31,9 +31,10 @@ Examples:
## List of benchmarks
The `--list` allows you to print all of the available benchmark names. Available options are:
The `--list` allows you to print all of the available benchmark names. Available options are:
* `flat` - prints list of the available benchmarks: `--list flat`
```ini
BenchmarkDotNet.Samples.Algo_Md5VsSha256.Md5
BenchmarkDotNet.Samples.Algo_Md5VsSha256.Sha256
@ -45,7 +46,9 @@ BenchmarkDotNet.Samples.IntroArrayParam.ManualIndexOf
BenchmarkDotNet.Samples.IntroBasic.Sleep
[...]
```
* `tree` - prints tree of the available benchmarks: `--list tree`
```ini
BenchmarkDotNet
└─Samples
@ -68,6 +71,7 @@ BenchmarkDotNet
The `--list` option works with the `--filter` option. Examples:
* `--list flat --filter *IntroSetupCleanup*` prints:
```ini
BenchmarkDotNet.Samples.IntroSetupCleanupGlobal.Logic
BenchmarkDotNet.Samples.IntroSetupCleanupIteration.Benchmark
@ -76,7 +80,9 @@ BenchmarkDotNet.Samples.IntroSetupCleanupTarget.BenchmarkB
BenchmarkDotNet.Samples.IntroSetupCleanupTarget.BenchmarkC
BenchmarkDotNet.Samples.IntroSetupCleanupTarget.BenchmarkD
```
* `--list tree --filter *IntroSetupCleanup*` prints:
```ini
BenchmarkDotNet
└─Samples
@ -103,12 +109,12 @@ You can also filter the benchmarks by categories:
* `-m`, `--memory` - enables MemoryDiagnoser and prints memory statistics
* `-t`, `--threading` - enables `ThreadingDiagnoser` and prints threading statistics
* `-d`, `--disasm`- enables DisassemblyDiagnoser and exports diassembly of benchmarked code. When you enable this option, you can use:
- `--disasmDepth` - Sets the recursive depth for the disassembler.
- `--disasmDiff` - Generates diff reports for the disassembler.
* `--disasmDepth` - Sets the recursive depth for the disassembler.
* `--disasmDiff` - Generates diff reports for the disassembler.
## Runtimes
The `--runtimes` or just `-r` allows you to run the benchmarks for selected Runtimes. Available options are:
The `--runtimes` or just `-r` allows you to run the benchmarks for selected Runtimes. Available options are:
* Clr - BDN will either use Roslyn (if you run it as .NET app) or latest installed .NET SDK to build the benchmarks (if you run it as .NET Core app).
* Core - if you run it as .NET Core app, BDN will use the same target framework moniker, if you run it as .NET app it's going to use netcoreapp2.1.
@ -174,7 +180,7 @@ static IConfig GetGlobalConfig()
.AsDefault()); // the KEY to get it working
```
Now, the default settings are: `WarmupCount=1` but you might still overwrite it from console args like in the example below:
Now, the default settings are: `WarmupCount=1` but you might still overwrite it from console args like in the example below:
```log
dotnet run -c Release -- --warmupCount 2
@ -198,7 +204,7 @@ dotnet run -c Release -- --filter * --runtimes netcoreapp2.0 netcoreapp2.1 --sta
* `-e`, `--exporters` GitHub/StackOverflow/RPlot/CSV/JSON/HTML/XML.
* `-i`, `--inProcess` (default: false) run benchmarks in the same process, without spawning child process per benchmark.
* `-a`, `--artifacts` valid path to an accessible directory where output artifacts will be stored.
* `--outliers` (default: RemoveUpper) DontRemove/RemoveUpper/RemoveLower/RemoveAll.
* `--outliers` (default: RemoveUpper) `DontRemove`/`RemoveUpper`/`RemoveLower`/`RemoveAll`.
* `--affinity` affinity mask to set for the benchmark process.
* `--allStats` (default: false) Displays all statistics (min, max & more).
* `--allCategories` categories to run. If few are provided, only the benchmarks which belong to all of them are going to be executed.
@ -214,7 +220,7 @@ dotnet run -c Release -- --filter * --runtimes netcoreapp2.0 netcoreapp2.1 --sta
* `--version` display version information.
* `--keepFiles` (default: false) determines if all auto-generated files should be kept or removed after running the benchmarks.
* `--noOverwrite` (default: false) determines if the exported result files should not be overwritten.
* `--disableLogFile` disables the logfile.
* `--disableLogFile` disables the log file.
* `--maxWidth` max parameter column width, the default is 20.
* `--envVars` colon separated environment variables (key:value).
* `--strategy` the RunStrategy that should be used. Throughput/ColdStart/Monitoring.

Просмотреть файл

@ -1,4 +1,5 @@
---
#cspell:ignore runstrategy
uid: BenchmarkDotNet.Samples.IntroColdStart
---
@ -38,4 +39,4 @@ Result 5: 1 op, 10449400.00 ns, 10.4494 ms/op
* @docs.runstrategy
* The permanent link to this sample: @BenchmarkDotNet.Samples.IntroColdStart
---
---

Просмотреть файл

@ -1,4 +1,5 @@
---
#cspell:ignore runstrategy
uid: BenchmarkDotNet.Samples.IntroMonitoring
---
@ -47,4 +48,4 @@ Result 10: 1 op, 70496300.00 ns, 70.4963 ms/op
* @docs.runstrategy
* The permanent link to this sample: @BenchmarkDotNet.Samples.IntroMonitoring
---
---

Просмотреть файл

@ -4,7 +4,7 @@ uid: BenchmarkDotNet.Samples.IntroParamsPriority
## Sample: IntroParamsPriority
In order to sort columns of parameters in the results table you can use the Property `Priority` inside the params attribute. The priority range is `[Int32.MinValue;Int32.MaxValue]`, lower priorites will appear earlier in the column order. The default priority is set to `0`.
In order to sort columns of parameters in the results table you can use the Property `Priority` inside the params attribute. The priority range is `[Int32.MinValue;Int32.MaxValue]`, lower priorities will appear earlier in the column order. The default priority is set to `0`.
### Source code

Просмотреть файл

@ -5,15 +5,18 @@ uid: BenchmarkDotNet.Samples.IntroPowerPlan
## Sample: IntroPowerPlan
This sample shows how we can manipulate with power plans. In BenchmarkDotNet we could change power plan in two ways. The first one is to set one from the list:
* PowerSaver, guid: a1841308-3541-4fab-bc81-f71556f20b4a
* Balanced, guid: 381b4222-f694-41f0-9685-ff5bb260df2e
* High-Performance, guid: 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c (the default one)
* Ultimate Performance, guid: e9a42b02-d5df-448d-aa00-03f14749eb61
* UserPowerPlan (a current power plan set in computer)
The second one rely on guid string. We could easily found currently set guids with cmd command
The second one rely on guid string. We could easily found currently set GUIDs with cmd command
```cmd
powercfg /list
```
If we set power plans in two ways at the same time, the second one will be used.
### Source code
@ -25,4 +28,4 @@ If we set power plans in two ways at the same time, the second one will be used.
* @docs.powerplans
* The permanent link to this sample: @BenchmarkDotNet.Samples.IntroPowerPlan
---
---