Skip to content
Development
Skill

/blazing-fast-dotnet

High-performance .NET guidance for writing and tuning C# apps and benchmarks (BenchmarkDotNet, ASP.NET, challenges). Use when asked to make .NET code faster, reduce allocations or GC overhead, fix lock contention or thread pool starvation, inspect JIT codegen, profile apps, or

BOOST
From plugin
managedcode-dotnet-skills
493200 skills17 agents
Install
$ npx -y skills add managedcode/dotnet-skills --skill blazing-fast-dotnet --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/blazing-fast-dotnet

Context preview

The summary Claude sees to decide when to auto-load this skill.

High-performance .NET guidance for writing and tuning C# apps and benchmarks (BenchmarkDotNet, ASP.NET, challenges). Use when asked to make .NET code faster, reduce allocations or GC overhead, fix lock contention or thread pool starvation, inspect JIT codegen, profile apps, or

SKILL.md

blazing-fast-dotnet.SKILL.md
name: blazing-fast-dotnet
description: High-performance .NET guidance for writing and tuning C# apps and benchmarks (BenchmarkDotNet, ASP.NET, challenges). Use when asked to make .NET code faster, reduce allocations or GC overhead, fix lock contention or thread pool starvation, inspect JIT codegen, profile apps, or tune runtime/NativeAOT settings.

Blazing Fast .NET Performance

> [!WARNING] > Much of the advice here might not age well: as .NET evolves, old hacks and custom knobs may become obsolete or even detrimental. Apply only after careful consideration and testing. Revisit periodically to ensure continued relevance.

This skill focuses on optimizing .NET applications for maximum performance, providing tips, techniques, and best practices to achieve blazing-fast execution times. It targets .NET 10.0 and 11.0. Older versions have not been tested.

**Contents**

  • [Profiling and Performance Analysis](#profiling-and-performance-analysis)
  • [dotnet-counters](#dotnet-counters)
  • [dotnet-trace](#dotnet-trace)
  • [Low-level profiling with Linux `perf`](#low-level-profiling-with-linux-perf)
  • [Popular low-level problems](#popular-low-level-problems)
  • [Inspecting JIT codegen](#inspecting-jit-codegen)
  • [Best practices for high-performance C# code](#best-practices-for-high-performance-c-code)
  • [Quick tips](#quick-tips)
  • [Strings and globalization](#strings-and-globalization)
  • [Contention on shared state](#contention-on-shared-state)
  • [False sharing](#false-sharing)
  • [Safe vectorization (SIMD or SWAR)](#safe-vectorization-simd-or-swar)
  • [ASP.NET Core](#aspnet-core)
  • [Magic knobs to Tune .NET Performance](#magic-knobs-to-tune-net-performance)
  • [NativeAOT-specific tuning](#nativeaot-specific-tuning)

Profiling and Performance Analysis

Start cheap and go deeper only when needed: counters (what kind of bottleneck?) → traces (where?) → `perf` and JIT disassembly. Install the tools with:

dotnet tool install -g dotnet-counters
dotnet tool install -g dotnet-trace
dotnet tool install -g dotnet-symbol

dotnet-counters

[dotnet-counters](https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-counters) is a low-overhead, first-level triage tool. Run it while the app is under load:

dotnet-counters monitor -p <pid>                                    # System.Runtime counters by default
dotnet-counters monitor -p <pid> --counters System.Runtime,Microsoft.AspNetCore.Hosting,System.Net.Http
dotnet-counters collect -p <pid> --format csv -o counters.csv      # save for post-processing

See the `System.Runtime` [built-in metrics](https://learn.microsoft.com/dotnet/core/diagnostics/built-in-metrics-runtime) (.NET 9+) for what each counter means.

dotnet-trace

[dotnet-trace](https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-trace) collects EventPipe traces on any OS without root or a native profiler (managed frames only):

dotnet-trace collect -p <pid> --duration 00:00:00:10    # default profiles: dotnet-common + dotnet-sampled-thread-time
dotnet-trace collect -p <pid> --profile gc-verbose      # GCs + sampled allocations: which types/stacks allocate
dotnet-trace collect -p <pid> --clrevents contention    # lock contention events with stacks
dotnet-trace collect -- ./MyApp arg1                    # trace from startup
dotnet-trace list-profiles

dotnet-trace report trace.nettrace topN -n 20           # top methods (exclusive) as plain text
dotnet-trace report trace.nettrace topN -n 20 --inclusive
dotnet-trace convert trace.nettrace --format Speedscope # open in https://www.speedscope.app

For more tips on using `dotnet-trace`, refer to the [dotnet-trace collection skill](https://raw.githubusercontent.com/dotnet/skills/refs/heads/main/plugins/dotnet-diag/skills/dotnet-trace-collect/SKILL.md).

Low-level profiling with Linux `perf`

The instructions below are mostly for CoreCLR/JIT scenarios on Linux with the native `perf` tool. NativeAOT/R2R scenarios should presumably work as is, without `perf inject`.

Typically, the following environment variables need to be set in the context of the running application:

DOTNET_PerfMapEnabled=1
DOTNET_PerfMapStubGranularity=3
DOTNET_JitFramed=1
DOTNET_EnableWriteXorExecute=0

What to profile depends on the scenario. Typically it's steady-state performance, so wait until the process is properly warmed up (e.g. 1 minute), then attach and collect traces:

perf record -k 1 -g -F 3999 -p $PROCESS_PID -o perf.data -- sleep 5

Next, symbolize the collected JIT frames using `perf inject`:

perf inject --input perf.data --jit --output perfjit.data

Then use the resulting `perfjit.data` file as needed, e.g. to generate flame graphs or annotated asm:

# annotated asm & report:
perf report --input perfjit.data --no-children --percent-limit 1 --stdio > perf_report.txt
perf annotate --stdio2 -i perfjit.data --percent-limit 1 -M intel > perf.asm

# Generate flamegraph (svg)
git clone --depth 1 --quiet https://github.com/brendangregg/FlameGraph || true
perf script -i perfjit.data | ./FlameGraph/stackcollapse-perf.pl | ./FlameGraph/flamegraph.pl > flamegraph.svg

Now `perf.asm` contains the annotated assembly output for the hottest methods in your application. Keep in mind that sample attribution is imprecise ("skid"): the cost is often reported on an instruction shortly after the one that actually stalls (e.g. right after a slow load or division), so inspect the neighboring instructions too.

In case of missing symbols you may need to use `dotnet-symbol` to download the necessary debug symbols for .dll/.dylib/.so:

dotnet-symbol --symbols $PUBLISH_FOLDER/*.dll
dotnet-symbol --symbols $PUBLISH_FOLDER/*.so

All other `perf`-related techniques (e.g. c2c, branch profiling, cache misses) can be applied similarly, depending on the performance aspects you want to analyze.

Popular low-level problems

  • Cache contention and false sharing in multi-threaded
Read more
Ships withmanagedcode-dotnet-skills

Stop explaining .NET to your AI. Start building. We've all been there: asking Claude to use Entity Framework, only to get EF6 patterns in a .NET 8 project. Explaining to Copilot that Blazor Server and Blazor WebAssembly aren't the same thing.

Get the whole plugin

Other skills on managedcode-dotnet-skills.