.NET Performance Engineering
Verwende diese Fertigkeit, wenn du die Leistung einer .NET-Anwendung untersuchst, erklärst, behebst, benchmarkst oder validierst – einschließlich ASP.NET Core, Dienste, Konsolenanwendungen, Avalonia, WPF, WinUI, MAUI, Skia, WebGPU, Spiel-/Grafik-Engines, NativeAOT und native Interoperabilitäts-Workloads.
Dieses Repository definiert eine Fertigkeit. SKILL.md ist der Richtlinien- und Routing-Einstiegspunkt; detaillierte operative Verfahren befinden sich in einer hierarchischen Referenzbaumstruktur. Lade nur die Indexe und Kapitel, die für die aktuelle Untersuchung erforderlich sind, und erweitere sie, wenn Beweise eine Zuständigkeitsgrenze überschreiten.
Unverhandelbare Regeln
- Profile und benchmarke einen optimierten Build, normalerweise
Release, in der tatsächlichen Bereitstellungsform. - Dokumentiere Commit und Dirty State, SDK/Runtime, Betriebssystem, Architektur, Hardware, Energiesparmodus, Workload, Tool-Versionen, Umgebungsüberschreibungen und genaue Befehle.
- Stelle eine deterministische Reproduktion sicher, bevor du Code änderst.
- Trenne Kaltstart, erste Nutzung, warmen stationären Zustand, Überlast, Drain und Herunterfahren.
- Wärme stufenweise Kompilierung, Shader, Pipelines, Caches und Pools auf, es sei denn, das Kaltstartverhalten ist das Thema.
- Sammle Beweise an jeder relevanten Zuständigkeitsgrenze: verwaltete Laufzeit, native Bibliothek, Kernel, Scheduler, Dateisystem/Netzwerk, Abhängigkeit, Treiber, GPU, Compositor und Display.
- Schließe nicht allein aus RSS auf verwaltete Retention.
- Schließe nicht allein aus hoher Framezeit, GPU-API-Nutzung oder Auslastung auf GPU-Sättigung.
- Behaupte keine Behebung basierend auf einem Durchschnitt, einem Trace, einem Frame-Capture, einem Mikrobenchmark oder dem schnellsten Benchmark-Durchlauf.
- Bewahre rohe Artefakte auf und melde fehlende Symbole, fallengelassene Ereignisse, Profiler-Overhead, Umgebungsvarianz und Unsicherheit.
- Schütze Geheimnisse und personenbezogene Daten in Dumps, Traces, Logs, SQL-Spannen, Paketerfassungen und Benchmark-Eingabekorpora.
- Behandle Befehlsbeispiele als versionssensitiv. Frage zuerst die installierte Hilfefunktion des Tools ab; sie überschreibt Beispiele, wenn die Syntax abweicht. Verwende
references/command-reference.mdfür verifizierte Auswahlregeln und kanonische Formen.1
Erforderlicher Untersuchungsbericht
Berichte:
- Symptom – beobachtbare Auswirkung und verletztes Ziel.
- Reproduktion – deterministischer Workload und Umgebung.
- Sammlung – genaue Tools, Befehle, Dauer und Artefaktpfade.
- Beweise – Zähler, Traces, Captures, Dumps, Benchmark-Verteilungen und Messungen.
- Eigentümerschaft – verwaltete CPU, Runtime, native CPU, Kernel, Scheduler, I/O, Abhängigkeit, Speicher, Treiber, GPU, Compositor oder Display.
- Dominante Ursache – größte unterstützte Kosten, Wartezeit oder am schnellsten wachsende Ressource.
- Behebung – kleinste hochwirksame Code- oder Konfigurationsänderung.
- Validierung – äquivalente Vorher/Nachher-Läufe mit Streuungs- und Ausreißermetriken.
- Restrisiken – ungelöste Engpässe und Messgrenzen.
Behaupte niemals eine Verbesserung ohne Vorher-Nachher-Beweise aus einem äquivalenten Workload.
Referenz-Router
Beginne immer mit references/index.md, references/core/index.md und dem verifizierten references/command-reference.md.
Lade zusätzliche Domänenindexe je nach Fragestellung:
- Verwaltete CPU, Allokation, GC, JIT, Ausnahmen, ThreadPool, Sperren, Async-Stacks, Dumps:
references/runtime/index.md - Verwaltete/Native/VM/Gemappte/GPU-Speicher-Eigentümerschaft und Leckanalyse:
references/memory/index.md - Wettbewerb, Async-Latenz, Warteschlangen, Backpressure, Datei-/Netzwerk-/Datenbank-I/O, UI-Dispatcher-Latenz:
references/latency/index.md - Kaltstart, erster Frame/erste Anfrage, Loader, JIT, ReadyToRun, Trimmen, Single-File, NativeAOT:
references/startup/index.md - BenchmarkDotNet, Mikro-/Komponenten-/Makro-/Last-/Soak-Benchmarks, Async-/Parallelitäts-Benchmarks, JIT/AOT-Vergleiche, Disassembly, Hardwarezähler, Statistik, CI-Gates:
references/benchmarking/index.md - Produktion, Container, Diagnoseports,
dotnet-monitor, ausgelöste Sammlung, Kubernetes, Artefaktsicherheit:references/production/index.md - UI/Rendering/GPU/WebGPU/Metal/D3D/Vulkan/OpenGL/Shader/Synchronisation/Präsentation:
references/gpu/index.md
Lade jede relevante Plattformreferenz über references/platforms/index.md. Eine Einzelsystem-Untersuchung benötigt normalerweise ein Plattformdokument; plattformübergreifende Vergleiche und Remote-/Client-Server-Szenarien können mehrere erfordern.
Lade nicht standardmäßig jedes Dokument. Wähle die minimale Menge, die die aktuelle Hypothese beantwortet, aber stoppe nicht an einer Zuständigkeitsgrenze, nur weil eine andere Anleitung erforderlich ist.
Schnelltriage-Sequenz
- Baue und führe die produktionsäquivalente Konfiguration aus.
- Definiere Workload-Phasen, Erfolgsmetriken und eine Abbruchregel.
- Zeichne
System.Runtime-Zähler sowie Prozess-CPU und Gesamtspeicher auf. - Erfasse verwaltete CPU/Runtime-Beweise mit
dotnet-trace, wenn verwaltete Eigentümerschaft plausibel ist. - Erfasse wiederholte Stacks, wenn Fortschritt, Mangel oder Blockierung vermutet wird.
- Wenn die Gesamtkosten unerklärt sind, sammle den plattformnativen CPU-/Scheduler-/I/O-/Speicher-Trace.
- Bei Speicher vergleiche verwaltete Live-Bytes, GC-Belegung, private/RSS/PSS, native Allokationen, Mappings, Grafikallokationen und GPU-Residenz.
- Beim Rendern korreliere Anwendungsmarker, CPU-Übergabe, GPU-Zeitstempel, natives GPU-Capture, Present, Compositor und Display-Timing.
- Bei Benchmark-Anfragen wähle Mikro-, Komponenten-, Makro-, Last- oder Soak-Methodik, bevor du BenchmarkDotNet oder ein anderes Testsystem auswählst.
- Bei reinen Produktionsvorfällen verwende begrenzte oder ausgelöste Sammlung und zeichne cgroup/Host-Einschränkungen auf.
- Implementiere erst, nachdem Beweise die dominante Ursache stützen.
- Wiederhole den identischen Workload und veröffentliche Median, Streuung, Ausreißerwerte und rohe Artefakte.
Eigentumstests
- Hohe Prozess-CPU mit heißen verwalteten Stacks: Anwendungs-/JIT-/Runtime-Arbeit.
- Hohe Prozess-CPU unter P/Invoke: native Bibliothek, Allokator, Grafik-API oder Treiber-CPU.
- Niedrige CPU mit wiederholten blockierten Stacks: Synchronisation, I/O, Scheduler, Warteschlangen oder externe Abhängigkeit.
- Steigende ThreadPool-Warteschlange bei niedriger CPU und blockierten Stacks: Mangel oder Sync-over-Async.
- Stabile verwaltete Live-Bytes bei wachsendem private/RSS: nativer Heap, Mappings, Code-Heaps, Fragmentierung, Grafikressourcen oder OS-Caches.
- Wachsender verwalteter Live-Graph nach äquivalenten Vollcollection-Punkten: verwaltete Retention oder absichtlich unbegrenzter Cache.
- Langer CPU-Frame mit kurzen GPU-Zeitstempeln: Anwendungs-/Render-Thread-/Treiber-CPU-gebunden.
- Kurze CPU-Übergabe mit langen GPU-Zeitstempeln: GPU-Ausführungs-gebunden.
- CPU und GPU frühzeitig abgeschlossen, aber Present ist spät: Swapchain, Compositor, V-Sync, Drawable-Mangel oder Display-Taktung.
- GPU-Leerlauflücken zwischen abhängigen Übergaben: CPU-Mangel, übermäßige Synchronisation, Serialisierung oder unzureichende Pufferung.
- Hohe Latenz bei niedriger On-CPU-Zeit: Off-CPU-Warten, Warteschlangen, Abhängigkeit, Drosselung oder Scheduler-Verzögerung.
- Start verbessert sich, aber erste Aktion verschlechtert sich: Arbeit wurde verschoben, nicht entfernt.
- Benchmark verbessert sich, aber die Produktmetrik nicht: Das Experiment ließ den kritischen Pfad aus, verwendete die falsche Eingabeverteilung oder optimierte eine nicht-dominante Operation.
Agenten-Arbeitsweise
- Untersuche Build-, Bereitstellungs-, Diagnose-, Benchmark-Projekte, Eingabekorpora, CI und Artefakt-Konventionen des Repositorys.
- Erstelle
artifacts/performance/<issue-oder-zeitstempel>/oder das Repository-Äquivalent. - Füge einen deterministischen Workload-Treiber und stabile Marker hinzu, wenn diese fehlen.
- Speichere Befehle, Umgebungsmetadaten, Versionen von Analyse-/Tool-Programmen und offizielle Referenzlinks neben Artefakten.
- Analysiere zuerst inklusive Kosten, dann exklusive Kosten, Callees, Wartezeiten, Warteschlangen, Synchronisation und Eigentümerschaft.
- Ändere Code erst, nachdem die dominante Ursache gestützt ist.
- Füge einen Benchmark, ein Regressionsbudget, einen Telemetrie-Marker, ein Trace-Rezept oder eine Lebensdauer-Invariante hinzu, die ein Wiederauftreten verhindert.
- Halte große Trace-, Capture-, Dump- und Benchmark-Artefakte außerhalb von Git, es sei denn, die Repository-Richtlinie speichert sie explizit.
- Validiere Fehler-, Abbruch-, Überlast-, Bereinigungs-, Geräteverlust- und Herunterfahrpfade – nicht nur den Happy Path.
Ungültige Schlussfolgerungen zur Ablehnung
- „CPU ist hoch, also ist Methode X langsam“ ohne Stacks.
- „RSS ist gewachsen, also leckt der verwaltete Heap.“
- „Der GC-Heap ist stabil, also gibt es kein Leck.“
- „Die durchschnittliche Latenz/Framezeit liegt unter dem Budget, also sind die Ausreißer gesund.“
- „Die GPU-Auslastung ist hoch, also ist Shader X der Engpass.“
- „Der Render-Thread ist beschäftigt, also ist die GPU beschäftigt.“
- „Ein Frame-Capture repräsentiert das stationäre Verhalten.“
- „Weniger Draw-Aufrufe bedeuten immer schnelleres Rendering.“
- „Mehr ThreadPool-Threads beheben Mangel.“
- „Async-Code kann nicht blockieren.“
- „NativeAOT ist automatisch schneller.“
- „Eine Mikrobenchmark-Verbesserung beweist eine Anwendungsverbesserung.“
- „Ein statistisch nachweisbares Delta ist automatisch produktbedeutsam.“
- „Ein Benchmark-Durchlauf beweist das Ergebnis.“
Dokumentations-Fußnoten
Footnotes
-
references/command-reference.md, das auf die aktuelle offizielle Dokumentation für die .NET-Diagnosetools, BenchmarkDotNet, Xcode Instruments, Windows Performance Toolkit, Linuxperf/BCC, PresentMon, RenderDoc und GPU-Profiler von Anbietern verweist. ↩