{"id":54228,"date":"2025-11-27T06:12:51","date_gmt":"2025-11-27T06:12:51","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=54228"},"modified":"2025-11-27T06:31:16","modified_gmt":"2025-11-27T06:31:16","slug":"benchmarkdotnet-dotnet-lab-demo","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/benchmarkdotnet-dotnet-lab-demo\/","title":{"rendered":"BenchmarkDotNet: DOTNET Lab &amp; Demo"},"content":{"rendered":"\n<p>Let\u2019s build a <strong>single, clean demo project<\/strong> that you can use in training as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Live demo<\/strong><\/li>\n\n\n\n<li><strong>Hands-on lab<\/strong><\/li>\n\n\n\n<li><strong>Reference code kit<\/strong><\/li>\n<\/ul>\n\n\n\n<p>It will show:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Micro-benchmarks with BenchmarkDotNet<\/li>\n\n\n\n<li>LINQ vs loops, Span vs array<\/li>\n\n\n\n<li>Allocations &amp; GC impact<\/li>\n\n\n\n<li>Time complexity in action (O(N), O(N\u00b2))<\/li>\n\n\n\n<li>Metrics analysis (Mean, Error, StdDev, Allocated, Gen0, etc.)<\/li>\n\n\n\n<li>Async\/await overhead and behavior<\/li>\n<\/ul>\n\n\n\n<p>Let\u2019s build a <strong>single, clean demo project<\/strong> that you can use in training as:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Live demo<\/strong><\/li>\n\n\n\n<li><strong>Hands-on lab<\/strong><\/li>\n\n\n\n<li><strong>Reference code kit<\/strong><\/li>\n<\/ul>\n\n\n\n<p>It will show:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Micro-benchmarks with BenchmarkDotNet<\/li>\n\n\n\n<li>LINQ vs loops, Span vs array<\/li>\n\n\n\n<li>Allocations &amp; GC impact<\/li>\n\n\n\n<li>Time complexity in action (O(N), O(N\u00b2))<\/li>\n\n\n\n<li>Metrics analysis (Mean, Error, StdDev, Allocated, Gen0, etc.)<\/li>\n\n\n\n<li>Async\/await overhead and behavior<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">0. Lab Goals &amp; Target Framework (.NET 10)<\/h2>\n\n\n\n<p>We\u2019ll structure the project so it works with <strong>current .NET (8\/9)<\/strong> and is ready for <strong>.NET 10<\/strong>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Target Framework Moniker for .NET 10 will almost certainly be: <code>net10.0<\/code>.<\/li>\n\n\n\n<li>Until .NET 10 SDK is available on your machine, you can temporarily use <code>net8.0<\/code> or <code>net9.0<\/code>.<\/li>\n\n\n\n<li>All code is \u201cfuture-safe\u201d: no APIs that should break in .NET 10.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">1. Step 1 \u2013 Create the Project<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">dotnet <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">console<\/span> -n BenchmarkDotNetLab\ncd BenchmarkDotNetLab\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Open the <code>.csproj<\/code> and set TargetFramework:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Project<\/span> <span class=\"hljs-attr\">Sdk<\/span>=<span class=\"hljs-string\">\"Microsoft.NET.Sdk\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PropertyGroup<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">OutputType<\/span>&gt;<\/span>Exe<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">OutputType<\/span>&gt;<\/span>\n    <span class=\"hljs-comment\">&lt;!-- For current SDKs, use net8.0 or net9.0 and later switch to net10.0 --&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TargetFramework<\/span>&gt;<\/span>net10.0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">TargetFramework<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ImplicitUsings<\/span>&gt;<\/span>enable<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ImplicitUsings<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Nullable<\/span>&gt;<\/span>enable<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Nullable<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">PropertyGroup<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Project<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>If your SDK doesn\u2019t yet support <code>net10.0<\/code>, swap to <code>net8.0<\/code>\/<code>net9.0<\/code> for now. Everything else stays the same.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">2. Step 2 \u2013 Add BenchmarkDotNet<\/h2>\n\n\n\n<p>Install the package:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">dotnet add package BenchmarkDotNet\n<\/code><\/span><\/pre>\n\n\n<p>(This will pull the latest version, which supports modern .NET.)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">3. Step 3 \u2013 Setup Benchmark Entry Point<\/h2>\n\n\n\n<p>We\u2019ll use <code>BenchmarkSwitcher<\/code> so we can run <strong>all<\/strong> benchmarks or <strong>filter by class<\/strong> from the command line.<\/p>\n\n\n\n<p><strong>Program.cs<\/strong><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">using BenchmarkDotNet.Running;\nusing System;\n\nnamespace BenchmarkDotNetLab\n{\n    public <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">Program<\/span>\n    <\/span>{\n        public <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> Main(string&#91;] args)\n        {\n            <span class=\"hljs-comment\">\/\/ This lets you run: dotnet run -c Release -- --filter *AlgoBenchmarks*<\/span>\n            <span class=\"hljs-keyword\">var<\/span> switcher = BenchmarkSwitcher.FromAssembly(<span class=\"hljs-keyword\">typeof<\/span>(Program).Assembly);\n            switcher.Run(args);\n        }\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">4. Step 4 \u2013 Micro-Benchmarks + LINQ vs Loops + Span vs Array<\/h2>\n\n\n\n<p>Create a new file <strong>AlgoBenchmarks.cs<\/strong>:<\/p>\n\n\n\n<script src=\"https:\/\/gist.github.com\/devops-school\/96f146428df10d8cf26d22963d0c9aca.js\"><\/script>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\"><\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">How to run this lab<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">dotnet run -c Release -- --filter *AlgoBenchmarks*\n<\/code><\/span><\/pre>\n\n\n<p>You\u2019ll see output like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">|              Method       | Mean      | <span class=\"hljs-built_in\">Error<\/span>   | StdDev | Gen0  | Allocated |\n|---------------------------|-----------|---------|--------|------|----------|\n| Sum_ForLoop (Baseline)    |  X ns     |   ...   |  ...   |  <span class=\"hljs-number\">0.0<\/span> |      <span class=\"hljs-number\">0<\/span> B |\n| Sum_Linq                  |  Y ns     |   ...   |  ...   |  <span class=\"hljs-number\">0.1<\/span> |   <span class=\"hljs-number\">240<\/span> B  |\n| SumEven_ArrayFor          |  ...      |         |        |      |      <span class=\"hljs-number\">0<\/span> B |\n| SumEven_SpanFor           |  ...      |         |        |      |      <span class=\"hljs-number\">0<\/span> B |\n| Contains_Linq             |  ...      |         |        |      |   <span class=\"hljs-number\">224<\/span> B  |\n| BinarySearch_Array        |  ...      |         |        |      |      <span class=\"hljs-number\">0<\/span> B |\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">How to understand during training<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Mean<\/strong>: average time per operation (lower = faster).<\/li>\n\n\n\n<li><strong>Allocated<\/strong>: bytes allocated per operation.<\/li>\n\n\n\n<li>Show how:\n<ul class=\"wp-block-list\">\n<li>LINQ often allocates (closures, enumerators).<\/li>\n\n\n\n<li>Raw loops\/Span can be faster and allocate <strong>0 bytes<\/strong>.<\/li>\n\n\n\n<li><code>BinarySearch<\/code> has better <strong>time complexity<\/strong> than <code>Contains<\/code> for large N.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">5. Step 5 \u2013 Time Complexity Lab (O(N) vs O(N\u00b2))<\/h2>\n\n\n\n<p>Create <strong>ComplexityBenchmarks.cs<\/strong>:<\/p>\n\n\n\n<script src=\"https:\/\/gist.github.com\/devops-school\/f698f138b78f2fd8a5792c2dc1e540b8.js\"><\/script>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">\n<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">How to run this lab<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">dotnet run -c Release -- --filter *ComplexityBenchmarks*\n<\/code><\/span><\/pre>\n\n\n<p>You\u2019ll see rows for each value of <code>N<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">|            Method          | N    | Mean   |\n|----------------------------|------|--------|\n| LinearScan (Baseline)      | 100  |  A ns  |\n| Quadratic_ParityPairs      | 100  |  B ns  |\n| LinearScan (Baseline)      | 500  |  C ns  |\n| Quadratic_ParityPairs      | 500  |  D ns  |\n| LinearScan (Baseline)      | 1000 |  E ns  |\n| Quadratic_ParityPairs      | 1000 |  F ns  |\n<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">How to talk about <strong>Time Complexity Equation<\/strong><\/h3>\n\n\n\n<p>Pick LinearScan:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>For N=100 \u2192 Mean \u2248 t\u2081<\/li>\n\n\n\n<li>For N=500 \u2192 Mean \u2248 t\u2082<\/li>\n\n\n\n<li>For N=1000 \u2192 Mean \u2248 t\u2083<\/li>\n<\/ul>\n\n\n\n<p>Explain:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>If algorithm is <strong>O(N)<\/strong>, time grows roughly in proportion to N \u2013 we can approximate:<br><code>T(N) \u2248 k * N<\/code><\/li>\n\n\n\n<li>Ratio example:\n<ul class=\"wp-block-list\">\n<li>N from 100 \u2192 500 (\u00d75), time ~\u00d75<\/li>\n\n\n\n<li>N from 500 \u2192 1000 (\u00d72), time ~\u00d72<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>Then Quadratic:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>O(N\u00b2) behaves more like: <code>T(N) \u2248 k * N\u00b2<\/code><\/li>\n\n\n\n<li>If N \u00d72 \u21d2 time roughly \u00d74<\/li>\n\n\n\n<li>Ask participants to <strong>compute approximate k<\/strong>:\n<ul class=\"wp-block-list\">\n<li><code>k \u2248 T(N) \/ N\u00b2<\/code><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>This makes Big-O <strong>real and visible<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">6. Step 6 \u2013 Allocations &amp; GC Impact Lab<\/h2>\n\n\n\n<p>We already have <code>[MemoryDiagnoser]<\/code> on all classes, but let\u2019s add a dedicated benchmark showing <strong>very heavy allocations<\/strong> vs optimized.<\/p>\n\n\n\n<p>Create <strong>AllocationBenchmarks.cs<\/strong>:<\/p>\n\n\n\n<script src=\"https:\/\/gist.github.com\/devops-school\/307318c65322c3b354af043067882049.js\"><\/script>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">\n<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">How to run this lab<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">dotnet run -c Release -- --filter *AllocationBenchmarks*\n<\/code><\/span><\/pre>\n\n\n<p>Watch the <strong>Allocated<\/strong> and <strong>Gen0<\/strong> columns:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">|                  Method              | N    | Mean   | Gen0   | Allocated |\n|--------------------------------------|------|--------|--------|-----------|\n| StringConcat_PlusOperator (Baseline) | 1000 |  X \u00b5s  |  Y     |  Z KB     |\n| StringConcat_StringBuilder           | 1000 |  A \u00b5s  |  B     |  C KB     |\n<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">How to interpret during training?<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Allocated<\/strong>: total bytes allocated per operation.<\/li>\n\n\n\n<li><strong>Gen0<\/strong>: approximate number of Gen0 GCs per operation.<\/li>\n\n\n\n<li>Show how:\n<ul class=\"wp-block-list\">\n<li><code>+<\/code> concatenation allocates many intermediate strings \u2192 more allocation \u2192 more GC \u2192 slower.<\/li>\n\n\n\n<li><code>StringBuilder<\/code> minimizes allocations \u2192 less GC \u2192 better throughput.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>Connect to <strong>application performance<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>High allocations \u2192 more GC \u2192 pauses \u2192 higher latency in web APIs, services, batch jobs.<\/li>\n\n\n\n<li>Optimizing hot paths can drastically reduce GC overhead.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">7. Step 7 \u2013 Async\/Await Deep Dive Lab<\/h2>\n\n\n\n<p>Create <strong>AsyncBenchmarks.cs<\/strong>:<\/p>\n\n\n\n<p>We\u2019ll compare:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Sync CPU-bound code<\/li>\n\n\n\n<li>CPU-bound wrapped in <code>Task.Run<\/code> (bad practice)<\/li>\n\n\n\n<li>\u201cFake I\/O\u201d with <code>Task.Delay<\/code> to show async cost vs benefits<\/li>\n\n\n\n<li>ValueTask vs Task<\/li>\n<\/ul>\n\n\n\n<script src=\"https:\/\/gist.github.com\/devops-school\/3d97d2ee9a2a980a33f1a20f0df81852.js\"><\/script>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">\n<\/code><\/span><\/pre>\n\n\n<h3 class=\"wp-block-heading\">How to run this lab<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">dotnet run -c Release -- --filter *AsyncBenchmarks*\n<\/code><\/span><\/pre>\n\n\n<p>Interpretation:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>Fibonacci_Sync<\/code> should be <strong>fastest<\/strong> and no allocations (if no closures).<\/li>\n\n\n\n<li><code>Fibonacci_TaskRun<\/code>:\n<ul class=\"wp-block-list\">\n<li>Higher <strong>Mean<\/strong> (async overhead + scheduling).<\/li>\n\n\n\n<li>Non-zero <strong>Allocated<\/strong> (Task object, state machine, closure).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><code>SimulatedIo_Task<\/code> vs <code>SimulatedIo_ValueTask<\/code>:\n<ul class=\"wp-block-list\">\n<li>Similar latency (because of <code>Task.Delay(10)<\/code>), but <code>ValueTask<\/code> may have fewer allocations.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">How to explain Async\/Await deep dive<\/h3>\n\n\n\n<p>Key teaching points:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Async is not \u201cfaster\u201d<\/strong>; it helps <strong>scale<\/strong> I\/O-bound workloads by freeing threads.<\/li>\n\n\n\n<li>For CPU-bound work, adding <code>Task.Run<\/code> introduces <strong>overhead<\/strong> without benefit.<\/li>\n\n\n\n<li>Each <code>async<\/code> method:\n<ul class=\"wp-block-list\">\n<li>Compiles to a <strong>state machine<\/strong><\/li>\n\n\n\n<li>May allocate <code>Task<\/code> \/ <code>State<\/code> objects<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><code>ValueTask<\/code> can reduce allocations in high-throughput paths\u2014but must be used carefully.<\/li>\n<\/ul>\n\n\n\n<p>Connect to real apps:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>CPU-bound APIs: prefer synchronous code or dedicated worker threads.<\/li>\n\n\n\n<li>I\/O-bound APIs: async is necessary to scale (database, HTTP, file I\/O).<\/li>\n\n\n\n<li>Over-using async in very tight loops can harm performance.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">8. Step 8 \u2013 Running Specific Labs in Training<\/h2>\n\n\n\n<p>You can now run each part independently during training:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Micro + LINQ vs loops + Span<\/strong> <code>dotnet run -c Release -- --filter *AlgoBenchmarks*<\/code><\/li>\n\n\n\n<li><strong>Time Complexity O(N) vs O(N\u00b2)<\/strong> <code>dotnet run -c Release -- --filter *ComplexityBenchmarks*<\/code><\/li>\n\n\n\n<li><strong>Allocations &amp; GC<\/strong> <code>dotnet run -c Release -- --filter *AllocationBenchmarks*<\/code><\/li>\n\n\n\n<li><strong>Async\/Await Deep Dive<\/strong> <code>dotnet run -c Release -- --filter *AsyncBenchmarks*<\/code><\/li>\n<\/ol>\n\n\n\n<p>Or run <strong>everything<\/strong>:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">dotnet run -c Release\n<\/code><\/span><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">9. How to Read BenchmarkDotNet Metrics (For Students)<\/h2>\n\n\n\n<p>In each summary table, focus on:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Mean<\/strong><br>Average time per operation. Main metric for latency.<\/li>\n\n\n\n<li><strong>Error \/ StdDev<\/strong><br>How \u201cnoisy\u201d the measurement is.\n<ul class=\"wp-block-list\">\n<li>High StdDev \u2192 unstable environment (CPU throttling, background processes).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Gen0\/Gen1\/Gen2<\/strong><br>Approx GCs per 1,000 operations.\n<ul class=\"wp-block-list\">\n<li>More frequent GCs \u2192 more pauses \u2192 potential latency spikes.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Allocated<\/strong><br>Bytes allocated <strong>per operation<\/strong>.\n<ul class=\"wp-block-list\">\n<li>One of the <strong>most important<\/strong> metrics for high-throughput systems (web APIs, microservices).<\/li>\n\n\n\n<li>Reducing allocated bytes reduces GC overhead and CPU usage.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>Tie everything back to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Latency<\/strong> (how fast a single request completes)<\/li>\n\n\n\n<li><strong>Throughput<\/strong> (how many requests\/second)<\/li>\n\n\n\n<li><strong>GC Pressure<\/strong> (how much CPU time is lost to GC)<\/li>\n\n\n\n<li><strong>Scalability<\/strong> (how well the app handles larger workloads or N)<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">10. Do\u2019s and Don\u2019ts for This Lab (and Real Life)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\u2705 DOs<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u2705 Run benchmarks using <strong>Release<\/strong> configuration: <code>dotnet run -c Release<\/code><\/li>\n\n\n\n<li>\u2705 Close other heavy apps (browsers, VMs) while benchmarking.<\/li>\n\n\n\n<li>\u2705 Use <code>[MemoryDiagnoser]<\/code> on all training benchmarks.<\/li>\n\n\n\n<li>\u2705 Use <code>[GlobalSetup]<\/code> for creating test data \u2013 <strong>don\u2019t<\/strong> measure setup.<\/li>\n\n\n\n<li>\u2705 Use <code>[Params]<\/code> to show time complexity behavior for different N.<\/li>\n\n\n\n<li>\u2705 Compare a <strong>baseline<\/strong> method against alternatives (<code>Baseline = true<\/code>).<\/li>\n\n\n\n<li>\u2705 Explain metrics (Mean, Allocated, Gen0) every time you show a table.<\/li>\n\n\n\n<li>\u2705 Emphasize that benchmarks measure <strong>micro performance<\/strong>, not full system behavior.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">\u274c DON\u2019Ts<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u274c Don\u2019t run benchmarks in <strong>Debug<\/strong> mode.<br>(JIT optimizations are disabled \u2192 meaningless results.)<\/li>\n\n\n\n<li>\u274c Don\u2019t benchmark <strong>I\/O to real network or disk<\/strong> in training demos<br>(noise from the environment will dominate).<\/li>\n\n\n\n<li>\u274c Don\u2019t include <code>Console.WriteLine<\/code> inside <code>[Benchmark]<\/code> methods<br>(I\/O destroys timings).<\/li>\n\n\n\n<li>\u274c Don\u2019t allocate large objects in <code>[GlobalSetup]<\/code> for each benchmark run; use fields.<\/li>\n\n\n\n<li>\u274c Don\u2019t assume async = faster. Show <code>Task.Run<\/code> overhead in the lab.<\/li>\n\n\n\n<li>\u274c Don\u2019t trust a single run; mention that BDN uses multiple iterations + statistics.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\"><\/h2>\n","protected":false},"excerpt":{"rendered":"<p>Let\u2019s build a single, clean demo project that you can use in training as: It will show: Let\u2019s build a single, clean demo project that you can use in training&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[11138],"tags":[],"class_list":["post-54228","post","type-post","status-publish","format-standard","hentry","category-best-tools"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54228","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=54228"}],"version-history":[{"count":6,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54228\/revisions"}],"predecessor-version":[{"id":54235,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54228\/revisions\/54235"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=54228"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=54228"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=54228"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}