From b16b83fa5437b637fbd230777f218f12cf771aae Mon Sep 17 00:00:00 2001 From: Andrey Akinshin Date: Mon, 11 Jun 2018 13:09:07 +0300 Subject: [PATCH] docs: samples for setup and cleanup --- docs/articles/features/setup-and-cleanup.md | 171 ++---------------- .../samples/IntroSetupCleanupGlobal.md | 22 +++ .../samples/IntroSetupCleanupIteration.md | 62 +++++++ .../samples/IntroSetupCleanupTarget.md | 35 ++++ docs/articles/samples/toc.yml | 8 +- .../IntroSetupCleanupGlobal.cs | 33 ++++ .../IntroSetupCleanupIteration.cs | 34 ++++ .../IntroSetupCleanupTarget.cs | 35 ++++ 8 files changed, 247 insertions(+), 153 deletions(-) create mode 100644 docs/articles/samples/IntroSetupCleanupGlobal.md create mode 100644 docs/articles/samples/IntroSetupCleanupIteration.md create mode 100644 docs/articles/samples/IntroSetupCleanupTarget.md create mode 100644 samples/BenchmarkDotNet.Samples/IntroSetupCleanupGlobal.cs create mode 100644 samples/BenchmarkDotNet.Samples/IntroSetupCleanupIteration.cs create mode 100644 samples/BenchmarkDotNet.Samples/IntroSetupCleanupTarget.cs diff --git a/docs/articles/features/setup-and-cleanup.md b/docs/articles/features/setup-and-cleanup.md index b6619017ac..5fcd20325a 100644 --- a/docs/articles/features/setup-and-cleanup.md +++ b/docs/articles/features/setup-and-cleanup.md @@ -1,164 +1,31 @@ +--- +uid: docs.setup-and-cleanup +name: Setup And Cleanup +--- + # Setup And Cleanup Sometimes we want to write some logic which should be executed *before* or *after* a benchmark, but we don't want to measure it. -For this purpose, BenchmarkDotNet provides a set of attributes: `[GlobalSetup]`, `[GlobalCleanup]`, `[IterationSetup]`, `[IterationCleanup]`. - -## GlobalSetup - -A method which is marked by the `[GlobalSetup]` attribute will be executed only once per a benchmarked method - after initialization of benchmark parameters and before all the benchmark method invocations. - -```cs -public class GlobalSetupExample -{ - [Params(10, 100, 1000)] - public int N; - - private int[] data; - - [GlobalSetup] - public void GlobalSetup() - { - data = new int[N]; // executed once per each N value - } - - [Benchmark] - public int Logic() - { - int res = 0; - for (int i = 0; i < N; i++) - res += data[i]; - return res; - } -} -``` - -## GlobalCleanup - -A method which is marked by the `[GlobalCleanup]` attribute will be executed only once per a benchmarked method - after all the benchmark method invocations. -If you are using some unmanaged resources (e.g., which were created in the `GlobalSetup` method), they can be disposed in the `GlobalCleanup` method. - -```cs -public void GlobalCleanup() -{ - // Disposing logic -} -``` - -## IterationSetup - -A method which is marked by the `[IterationSetup]` attribute will be executed only once *before each an iteration*. -It's not recommended to use this attribute in microbenchmarks because it can spoil the results. -However, if you are writing a macrobenchmark (e.g. a benchmark which takes at least 100ms) and - you want to prepare some data before each iteration, `[IterationSetup]` can be useful. -BenchmarkDotNet doesn't support setup/cleanup method for a single method invocation (*an operation*), but you can perform only one operation per iteration. -It's recommended to use `RunStrategy.Monitoring` for such cases. -Be careful: if you allocate any objects in the `[IterationSetup]` method, the MemoryDiagnoser results can also be spoiled. - -## IterationCleanup -A method which is marked by the `[IterationCleanup]` attribute will be executed only once *after each an iteration*. -This attribute has the same set of constraint with `[IterationSetup]`: it's not recommended to use `[IterationCleanup]` in microbenchmarks or benchmark which also - -## An example - -```cs -[SimpleJob(RunStrategy.Monitoring, launchCount: 1, warmupCount: 2, targetCount: 3)] -public class SetupAndCleanupExample -{ - private int setupCounter; - private int cleanupCounter; - - [IterationSetup] - public void IterationSetup() => Console.WriteLine("// " + "IterationSetup" + " (" + ++setupCounter + ")"); - - [IterationCleanup] - public void IterationCleanup() => Console.WriteLine("// " + "IterationCleanup" + " (" + ++cleanupCounter + ")"); - - [GlobalSetup] - public void GlobalSetup() => Console.WriteLine("// " + "GlobalSetup"); - - [GlobalCleanup] - public void GlobalCleanup() => Console.WriteLine("// " + "GlobalCleanup"); - - [Benchmark] - public void Benchmark() => Console.WriteLine("// " + "Benchmark"); -} -``` - -The order of method calls: - -``` -// GlobalSetup - -// IterationSetup (1) // IterationSetup Jitting -// IterationCleanup (1) // IterationCleanup Jitting - -// IterationSetup (2) // MainWarmup1 -// Benchmark // MainWarmup1 -// IterationCleanup (2) // MainWarmup1 - -// IterationSetup (3) // MainWarmup2 -// Benchmark // MainWarmup2 -// IterationCleanup (3) // MainWarmup2 - -// IterationSetup (4) // MainTarget1 -// Benchmark // MainTarget1 -// IterationCleanup (4) // MainTarget1 - -// IterationSetup (5) // MainTarget2 -// Benchmark // MainTarget2 -// IterationCleanup (5) // MainTarget2 - -// IterationSetup (6) // MainTarget3 -// Benchmark // MainTarget3 -// IterationCleanup (6) // MainTarget3 - -// GlobalCleanup -``` - -## Target - -Sometimes it's useful to run setup or cleanups for specific benchmarks. All four setup and cleanup attributes have a Target property that allow the setup/cleanup method to be run for one or more specific benchmark methods. +For this purpose, BenchmarkDotNet provides a set of attributes: + [`[GlobalSetup]`](xref:BenchmarkDotNet.Attributes.GlobalSetupAttribute), + [`[GlobalCleanup]`](xref:BenchmarkDotNet.Attributes.GlobalCleanupAttribute), + [`[IterationSetup]`](xref:BenchmarkDotNet.Attributes.IterationSetupAttribute), + [`[IterationCleanup]`](xref:BenchmarkDotNet.Attributes.IterationCleanupAttribute). -```cs -[SimpleJob(RunStrategy.Monitoring, launchCount: 0, warmupCount: 0, targetCount: 1)] -public class SetupAndCleanupExample -{ - [GlobalSetup(Target = nameof(BenchmarkA))] - public void GlobalSetupA() => Console.WriteLine("// " + "GlobalSetup A"); - - [Benchmark] - public void BenchmarkA() => Console.WriteLine("// " + "Benchmark A"); - - [GlobalSetup(Target = nameof(BenchmarkB) + "," + nameof(BenchmarkC))] - public void GlobalSetupB() => Console.WriteLine("// " + "GlobalSetup B"); - - [Benchmark] - public void BenchmarkB() => Console.WriteLine("// " + "Benchmark B"); - - [Benchmark] - public void BenchmarkC() => Console.WriteLine("// " + "Benchmark C"); - - [Benchmark] - public void BenchmarkD() => Console.WriteLine("// " + "Benchmark D"); -} -``` +--- -The order of method calls: +[!include[IntroSetupCleanupGlobal](../samples/IntroSetupCleanupGlobal.md)] -``` -// GlobalSetup A +The link to this sample: @BenchmarkDotNet.Samples.IntroSetupCleanupGlobal -// Benchmark A +--- -// GlobalSetup B +[!include[IntroSetupCleanupIteration](../samples/IntroSetupCleanupIteration.md)] -// Benchmark B +The link to this sample: @BenchmarkDotNet.Samples.IntroSetupCleanupIteration -// GlobalSetup B +--- -// Benchmark C +[!include[IntroSetupCleanupTarget](../samples/IntroSetupCleanupTarget.md)] -// Benchmark D -``` +The link to this sample: @BenchmarkDotNet.Samples.IntroSetupCleanupTarget \ No newline at end of file diff --git a/docs/articles/samples/IntroSetupCleanupGlobal.md b/docs/articles/samples/IntroSetupCleanupGlobal.md new file mode 100644 index 0000000000..c248900774 --- /dev/null +++ b/docs/articles/samples/IntroSetupCleanupGlobal.md @@ -0,0 +1,22 @@ +--- +uid: BenchmarkDotNet.Samples.IntroSetupCleanupGlobal +--- + +## Sample: IntroSetupCleanupGlobal + +A method which is marked by the [`[GlobalSetup]`](xref:BenchmarkDotNet.Attributes.GlobalSetupAttribute) + attribute will be executed only once per a benchmarked method + after initialization of benchmark parameters and before all the benchmark method invocations. +A method which is marked by the [`[GlobalCleanup]`](xref:BenchmarkDotNet.Attributes.GlobalCleanupAttribute) + attribute will be executed only once per a benchmarked method + after all the benchmark method invocations. +If you are using some unmanaged resources (e.g., which were created in the `GlobalSetup` method), + they can be disposed in the `GlobalCleanup` method. + +### Source code + +[!code-csharp[IntroSetupCleanupGlobal.cs](../../../samples/BenchmarkDotNet.Samples/IntroSetupCleanupGlobal.cs)] + +### See also + +* @docs.setup-and-cleanup \ No newline at end of file diff --git a/docs/articles/samples/IntroSetupCleanupIteration.md b/docs/articles/samples/IntroSetupCleanupIteration.md new file mode 100644 index 0000000000..dac30b974d --- /dev/null +++ b/docs/articles/samples/IntroSetupCleanupIteration.md @@ -0,0 +1,62 @@ +--- +uid: BenchmarkDotNet.Samples.IntroSetupCleanupIteration +--- + +## Sample: IntroSetupCleanupIteration + +A method which is marked by the [`[IterationSetup]`](xref:BenchmarkDotNet.Attributes.IterationSetupAttribute) + attribute will be executed only once *before each an iteration*. +It's not recommended to use this attribute in microbenchmarks because it can spoil the results. +However, if you are writing a macrobenchmark (e.g. a benchmark which takes at least 100ms) and + you want to prepare some data before each iteration, + [`[IterationSetup]`](xref:BenchmarkDotNet.Attributes.IterationSetupAttribute) can be useful. +BenchmarkDotNet doesn't support setup/cleanup method for a single method invocation (*an operation*), + but you can perform only one operation per iteration. +It's recommended to use `RunStrategy.Monitoring` for such cases. +Be careful: if you allocate any objects in + the [`[IterationSetup]`](xref:BenchmarkDotNet.Attributes.IterationSetupAttribute) method, + the MemoryDiagnoser results can also be spoiled. + +A method which is marked by the [`[IterationCleanup]`](xref:BenchmarkDotNet.Attributes.IterationCleanupAttribute) + attribute will be executed only once *after each an iteration*. +This attribute has the same set of constraint with `[IterationSetup]`: it's not recommended to use + [`[IterationCleanup]`](xref:BenchmarkDotNet.Attributes.IterationCleanupAttribute) in microbenchmarks. + +### Source code + +[!code-csharp[IntroSetupCleanupIteration.cs](../../../samples/BenchmarkDotNet.Samples/IntroSetupCleanupIteration.cs)] + +### THe order of method calls + +```cs +// GlobalSetup + +// IterationSetup (1) // IterationSetup Jitting +// IterationCleanup (1) // IterationCleanup Jitting + +// IterationSetup (2) // MainWarmup1 +// Benchmark // MainWarmup1 +// IterationCleanup (2) // MainWarmup1 + +// IterationSetup (3) // MainWarmup2 +// Benchmark // MainWarmup2 +// IterationCleanup (3) // MainWarmup2 + +// IterationSetup (4) // MainTarget1 +// Benchmark // MainTarget1 +// IterationCleanup (4) // MainTarget1 + +// IterationSetup (5) // MainTarget2 +// Benchmark // MainTarget2 +// IterationCleanup (5) // MainTarget2 + +// IterationSetup (6) // MainTarget3 +// Benchmark // MainTarget3 +// IterationCleanup (6) // MainTarget3 + +// GlobalCleanup +``` + +### See also + +* @docs.setup-and-cleanup \ No newline at end of file diff --git a/docs/articles/samples/IntroSetupCleanupTarget.md b/docs/articles/samples/IntroSetupCleanupTarget.md new file mode 100644 index 0000000000..29e7ee166c --- /dev/null +++ b/docs/articles/samples/IntroSetupCleanupTarget.md @@ -0,0 +1,35 @@ +--- +uid: BenchmarkDotNet.Samples.IntroSetupCleanupTarget +--- + +## Sample: IntroSetupCleanupTarget + +Sometimes it's useful to run setup or cleanups for specific benchmarks. +All four setup and cleanup attributes have a Target property that allow + the setup/cleanup method to be run for one or more specific benchmark methods. + +### Source code + +[!code-csharp[IntroSetupCleanupTarget.cs](../../../samples/BenchmarkDotNet.Samples/IntroSetupCleanupTarget.cs)] + +### THe order of method calls + +```cs +// GlobalSetup A + +// Benchmark A + +// GlobalSetup B + +// Benchmark B + +// GlobalSetup B + +// Benchmark C + +// Benchmark D +``` + +### See also + +* @docs.setup-and-cleanup \ No newline at end of file diff --git a/docs/articles/samples/toc.yml b/docs/articles/samples/toc.yml index e3a24129b6..fc0333c9bb 100644 --- a/docs/articles/samples/toc.yml +++ b/docs/articles/samples/toc.yml @@ -17,4 +17,10 @@ - name: IntroJobBaseline href: IntroJobBaseline.md - name: IntroEnvVars - href: IntroEnvVars.md \ No newline at end of file + href: IntroEnvVars.md +- name: IntroSetupCleanupGlobal + href: IntroSetupCleanupGlobal.md +- name: IntroSetupCleanupIteration + href: IntroSetupCleanupIteration.md +- name: IntroSetupCleanupTarget + href: IntroSetupCleanupTarget.md \ No newline at end of file diff --git a/samples/BenchmarkDotNet.Samples/IntroSetupCleanupGlobal.cs b/samples/BenchmarkDotNet.Samples/IntroSetupCleanupGlobal.cs new file mode 100644 index 0000000000..d37e0cce8a --- /dev/null +++ b/samples/BenchmarkDotNet.Samples/IntroSetupCleanupGlobal.cs @@ -0,0 +1,33 @@ +using BenchmarkDotNet.Attributes; + +namespace BenchmarkDotNet.Samples +{ + public class IntroSetupCleanupGlobal + { + [Params(10, 100, 1000)] + public int N; + + private int[] data; + + [GlobalSetup] + public void GlobalSetup() + { + data = new int[N]; // executed once per each N value + } + + [Benchmark] + public int Logic() + { + int res = 0; + for (int i = 0; i < N; i++) + res += data[i]; + return res; + } + + [GlobalCleanup] + public void GlobalCleanup() + { + // Disposing logic + } + } +} \ No newline at end of file diff --git a/samples/BenchmarkDotNet.Samples/IntroSetupCleanupIteration.cs b/samples/BenchmarkDotNet.Samples/IntroSetupCleanupIteration.cs new file mode 100644 index 0000000000..aa4e666f7e --- /dev/null +++ b/samples/BenchmarkDotNet.Samples/IntroSetupCleanupIteration.cs @@ -0,0 +1,34 @@ +using System; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Engines; + +namespace BenchmarkDotNet.Samples +{ + [SimpleJob(RunStrategy.Monitoring, launchCount: 1, + warmupCount: 2, targetCount: 3)] + public class IntroSetupCleanupIteration + { + private int setupCounter; + private int cleanupCounter; + + [IterationSetup] + public void IterationSetup() + => Console.WriteLine($"// IterationSetup ({++setupCounter})"); + + [IterationCleanup] + public void IterationCleanup() + => Console.WriteLine($"// IterationCleanup ({++cleanupCounter})"); + + [GlobalSetup] + public void GlobalSetup() + => Console.WriteLine("// " + "GlobalSetup"); + + [GlobalCleanup] + public void GlobalCleanup() + => Console.WriteLine("// " + "GlobalCleanup"); + + [Benchmark] + public void Benchmark() + => Console.WriteLine("// " + "Benchmark"); + } +} \ No newline at end of file diff --git a/samples/BenchmarkDotNet.Samples/IntroSetupCleanupTarget.cs b/samples/BenchmarkDotNet.Samples/IntroSetupCleanupTarget.cs new file mode 100644 index 0000000000..631e29d839 --- /dev/null +++ b/samples/BenchmarkDotNet.Samples/IntroSetupCleanupTarget.cs @@ -0,0 +1,35 @@ +using System; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Engines; + +namespace BenchmarkDotNet.Samples +{ + [SimpleJob(RunStrategy.Monitoring, launchCount: 0, + warmupCount: 0, targetCount: 1)] + public class IntroSetupCleanupTarget + { + [GlobalSetup(Target = nameof(BenchmarkA))] + public void GlobalSetupA() + => Console.WriteLine("// " + "GlobalSetup A"); + + [Benchmark] + public void BenchmarkA() + => Console.WriteLine("// " + "Benchmark A"); + + [GlobalSetup(Target = nameof(BenchmarkB) + "," + nameof(BenchmarkC))] + public void GlobalSetupB() + => Console.WriteLine("// " + "GlobalSetup B"); + + [Benchmark] + public void BenchmarkB() + => Console.WriteLine("// " + "Benchmark B"); + + [Benchmark] + public void BenchmarkC() + => Console.WriteLine("// " + "Benchmark C"); + + [Benchmark] + public void BenchmarkD() + => Console.WriteLine("// " + "Benchmark D"); + } +} \ No newline at end of file