{"id":54193,"date":"2025-11-25T17:48:41","date_gmt":"2025-11-25T17:48:41","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=54193"},"modified":"2025-11-25T17:48:41","modified_gmt":"2025-11-25T17:48:41","slug":"dottrace-a-complete-tutorial-guide","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/dottrace-a-complete-tutorial-guide\/","title":{"rendered":"dotTrace: A Complete Tutorial Guide"},"content":{"rendered":"\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">1. What is dotTrace?<\/h2>\n\n\n\n<p><strong>Definition<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>dotTrace<\/strong> is a .NET performance profiler from JetBrains.<\/li>\n\n\n\n<li>It supports:\n<ul class=\"wp-block-list\">\n<li>.NET Framework, .NET Core, modern .NET<\/li>\n\n\n\n<li>ASP.NET \/ ASP.NET Core (IIS, Kestrel)<\/li>\n\n\n\n<li>Desktop (WPF, WinForms, Windows Services)<\/li>\n\n\n\n<li>Unity \/ Mono<\/li>\n\n\n\n<li>Remote and command-line scenarios. ()<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><strong>What it actually does<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Hooks into your process and samples\/traces function calls.<\/li>\n\n\n\n<li>Collects data like:\n<ul class=\"wp-block-list\">\n<li>Which methods ran<\/li>\n\n\n\n<li>How many times<\/li>\n\n\n\n<li>How much <strong>CPU time<\/strong> and <strong>wall-clock time<\/strong> they consumed<\/li>\n\n\n\n<li>How threads were blocked, waiting or contending for resources (Timeline mode).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Produces a <strong>snapshot<\/strong> file which you open in dotTrace Viewer (stand-alone, Rider, or Visual Studio integration) and analyze using:\n<ul class=\"wp-block-list\">\n<li>Call Tree \/ Hotspots<\/li>\n\n\n\n<li>Threads \/ Timeline view<\/li>\n\n\n\n<li>Filters (by thread, time range, namespace, etc.). ()<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><strong>Profiling modes (high level)<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Sampling<\/strong> \u2013 low overhead, good for finding hot methods (CPU).<\/li>\n\n\n\n<li><strong>Tracing<\/strong> \u2013 higher overhead, more precise call details.<\/li>\n\n\n\n<li><strong>Line-by-line<\/strong> \u2013 very detailed but expensive; used on small scopes.<\/li>\n\n\n\n<li><strong>Timeline<\/strong> \u2013 shows CPU, async, GC, I\/O, blocking, context switching over time; great for ASP.NET, services, UI freezes. ()<\/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\">2. Why and When to Use dotTrace<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Why use dotTrace?<\/h3>\n\n\n\n<p>Use dotTrace when you need answers to questions like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em>\u201cWhy is this request taking 2 seconds instead of 100 ms?\u201d<\/em><\/li>\n\n\n\n<li><em>\u201cWhich method is burning the CPU?\u201d<\/em><\/li>\n\n\n\n<li><em>\u201cWhy does my WPF UI freeze for 3 seconds when I click this button?\u201d<\/em><\/li>\n\n\n\n<li><em>\u201cIs my app blocked on I\/O, locks, or GC?\u201d<\/em><\/li>\n<\/ul>\n\n\n\n<p>Typical problems it helps you solve:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Slow HTTP endpoints \/ APIs<\/li>\n\n\n\n<li>High CPU usage on servers or background services<\/li>\n\n\n\n<li>Long-running batch jobs<\/li>\n\n\n\n<li>UI freezes \/ jank in WPF\/WinForms<\/li>\n\n\n\n<li>Thread contention, lock issues, sync-over-async<\/li>\n\n\n\n<li>Excessive database or network calls (e.g., N+1 queries).<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">When to use (scenarios in lifecycle)<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>During development<\/strong>\n<ul class=\"wp-block-list\">\n<li>New feature feels slow \u2192 profile locally before even committing.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>On a performance test \/ staging environment<\/strong>\n<ul class=\"wp-block-list\">\n<li>Performance tests show regressions \u2192 run dotTrace against test environment.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>On production (carefully)<\/strong>\n<ul class=\"wp-block-list\">\n<li>Use <strong>Timeline or sampling mode<\/strong> with as little overhead as possible.<\/li>\n\n\n\n<li>Or collect snapshots using <strong>dotTrace command line \/ self-profiling API<\/strong> and download the snapshot for analysis offline. ()<\/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\">3. How dotTrace Works (Conceptual Model)<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>You <strong>start a profiling session<\/strong>:\n<ul class=\"wp-block-list\">\n<li>From <strong>standalone dotTrace<\/strong>, <strong>Visual Studio<\/strong>, or <strong>Rider<\/strong>, or via <strong>command line<\/strong>. ()<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>You <strong>run or attach<\/strong> to the target:\n<ul class=\"wp-block-list\">\n<li>Start a new process (standalone app, web app) <strong>or<\/strong><\/li>\n\n\n\n<li>Attach to an already running .NET process.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>dotTrace <strong>collects a snapshot<\/strong> while you reproduce the problem.<\/li>\n\n\n\n<li>You <strong>stop or detach<\/strong> \u2192 snapshot is saved.<\/li>\n\n\n\n<li>You open the snapshot in <strong>dotTrace Viewer<\/strong> and:\n<ul class=\"wp-block-list\">\n<li>Navigate hotspots<\/li>\n\n\n\n<li>Drill down into call stacks and threads<\/li>\n\n\n\n<li>Filter by thread, time range, namespace, or method.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>You <strong>change code<\/strong> based on findings, redeploy, and <strong>re-profile<\/strong> to verify improvement.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">4. How to Install dotTrace<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">4.1 Options<\/h3>\n\n\n\n<p>You can get dotTrace in several ways: ()<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>JetBrains Toolbox (recommended)<\/strong>\n<ul class=\"wp-block-list\">\n<li>Install <em>JetBrains Toolbox<\/em>.<\/li>\n\n\n\n<li>From Toolbox, install <strong>dotTrace<\/strong> as a standalone tool.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Part of ReSharper Ultimate \/ Rider<\/strong>\n<ul class=\"wp-block-list\">\n<li>If you use <strong>ReSharper<\/strong> in Visual Studio or <strong>Rider<\/strong>, dotTrace profiling is integrated.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Standalone installer<\/strong>\n<ul class=\"wp-block-list\">\n<li>Download installer from JetBrains dotTrace site (32\/64-bit).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>dotTrace Command Line Tools<\/strong>\n<ul class=\"wp-block-list\">\n<li>Free redistributable <strong>console profiler<\/strong>, useful for CI, servers, and automation. ()<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">4.2 Basic installation steps (Windows)<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Go to JetBrains profiler site and download dotTrace installer. ()<\/li>\n\n\n\n<li>Run installer (requires admin privileges).<\/li>\n\n\n\n<li>Follow wizard \u2192 choose:\n<ul class=\"wp-block-list\">\n<li>Standalone dotTrace<\/li>\n\n\n\n<li>Integration with Visual Studio (if ReSharper installed).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Finish and launch <strong>dotTrace<\/strong> from:\n<ul class=\"wp-block-list\">\n<li>Start Menu \u2192 JetBrains \u2192 dotTrace, or<\/li>\n\n\n\n<li>JetBrains Toolbox.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>(For Rider\/VS integration, dotTrace features appear in menus like <strong>ReSharper | Profile<\/strong> or Rider\u2019s <strong>Run | Profile<\/strong>.)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">5. Step-by-Step: Using dotTrace to Troubleshoot an App<\/h2>\n\n\n\n<p>I\u2019ll structure this as a concrete <strong>lab<\/strong> you can reuse in training:<\/p>\n\n\n\n<p>We\u2019ll assume:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>.NET 6\/7\/8 API: <code>Orders.Api.exe<\/code> (or any app)<\/li>\n\n\n\n<li>Running on Windows, profiling locally<\/li>\n\n\n\n<li>Using <strong>Standalone dotTrace<\/strong> + <strong>Timeline<\/strong> mode (good for web apps).<\/li>\n<\/ul>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>You can adapt the same logic for WPF, ASP.NET under IIS, services, etc. The run configuration types differ but the flow is identical. ()<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Step 0 \u2013 Prepare<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Install dotTrace.<\/li>\n\n\n\n<li>Build your app in <strong>Release<\/strong> configuration.<\/li>\n\n\n\n<li>Have a <strong>clear repro scenario<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Example: calling <code>\/api\/orders?customerId=123<\/code> is slow.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1 \u2013 Start dotTrace<\/h3>\n\n\n\n<p><strong>Standalone mode<\/strong> (recommended for generic training): ()<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Open <strong>JetBrains Toolbox<\/strong>.<\/li>\n\n\n\n<li>Click <strong>dotTrace<\/strong>.<\/li>\n\n\n\n<li>You\u2019ll see the <strong>Home<\/strong> window with \u201cNew Process Run \/ Attach to Process \/ \u2026\u201d.<\/li>\n<\/ol>\n\n\n\n<p><strong>Visual Studio mode<\/strong> (if you prefer integrated):<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Open your solution in Visual Studio.<\/li>\n\n\n\n<li>Use menu: <strong>ReSharper | Profile | Run Startup Configuration Performance Profiling\u2026<\/strong>. ()<\/li>\n<\/ol>\n\n\n\n<p>(For your training, show both once; then standardize on standalone to keep steps universal.)<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2 \u2013 Create a Run Configuration<\/h3>\n\n\n\n<p>This tells dotTrace how to run your app. ()<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>In dotTrace Home \u2192 under <strong>New Process Run<\/strong>, click <strong>Add run configuration<\/strong>.<\/li>\n\n\n\n<li>Choose <strong>application type<\/strong>:\n<ul class=\"wp-block-list\">\n<li>For console \/ worker \/ self-hosting web \u2192 <strong>\u201c.NET and .NET Core\u201d<\/strong>.<\/li>\n\n\n\n<li>For IIS\/IIS Express \u2192 choose <strong>IIS<\/strong> or <strong>IIS Express<\/strong>.<\/li>\n\n\n\n<li>For Windows service, WCF, etc. there are dedicated types.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>For .NET\/.NET Core:\n<ul class=\"wp-block-list\">\n<li><strong>Path to executable<\/strong>: e.g. <code>C:\\Apps\\Orders.Api\\Orders.Api.exe<\/code>\n<ul class=\"wp-block-list\">\n<li>Or the <code>dll<\/code> if framework-dependent deployment.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Command-line arguments<\/strong> (if any).<\/li>\n\n\n\n<li><strong>Working directory<\/strong>: usually where your exe\/dll lives.<\/li>\n\n\n\n<li>Any <strong>environment variables<\/strong> if needed (connection strings, ASPNETCORE_ENVIRONMENT, etc.).<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>Save the configuration as <code>Orders.Api \u2013 Timeline<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3 \u2013 Choose Profiling Type and Options<\/h3>\n\n\n\n<p>Decide what you want to see vs overhead. <\/p>\n\n\n\n<p>For <strong>web\/API performance<\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Profiling type<\/strong>: choose <strong>Timeline<\/strong>.<\/li>\n\n\n\n<li>(Optional) Adjust:\n<ul class=\"wp-block-list\">\n<li><strong>Sampling rate<\/strong> \u2013 trade-off between detail and snapshot size.<\/li>\n\n\n\n<li><strong>Process filters<\/strong> \u2013 to focus only on your process (exclude child processes).<\/li>\n\n\n\n<li><strong>Scope<\/strong> \u2013 if there are multiple processes (IIS w3wp, etc.).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p>For a basic first run, keep defaults and use Timeline.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4 \u2013 Start Profiling Session<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>From dotTrace Home, select your run configuration (<code>Orders.Api \u2013 Timeline<\/code>).<\/li>\n\n\n\n<li>Click <strong>Run<\/strong> (or <strong>Run | Local<\/strong>).<\/li>\n\n\n\n<li>dotTrace:\n<ul class=\"wp-block-list\">\n<li>Starts your app.<\/li>\n\n\n\n<li>Opens the <strong>profiling controller window<\/strong> (a separate small window). ()<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>In the controller you\u2019ll see buttons like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Get Snapshot and Start<\/strong> \/ <strong>Get Snapshot and Save<\/strong><\/li>\n\n\n\n<li><strong>Detach<\/strong><\/li>\n\n\n\n<li><strong>Kill Process<\/strong><\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5 \u2013 Reproduce the Problem Under Profiling<\/h3>\n\n\n\n<p>With your app now under profiler:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Use your test client:\n<ul class=\"wp-block-list\">\n<li><code>curl<\/code>, Postman, browser, or load test tool.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Hit the problematic endpoint:\n<ul class=\"wp-block-list\">\n<li>e.g., <code>GET \/api\/orders?customerId=123<\/code> 5\u201310 times, or trigger your scenario.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Watch for the app to behave slowly as usual (you\u2019re now capturing profiling data for that period).<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Step 6 \u2013 Capture a Snapshot<\/h3>\n\n\n\n<p>While the issue is being reproduced:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>In the <strong>controller<\/strong> window, click:\n<ul class=\"wp-block-list\">\n<li><strong>Get Snapshot<\/strong> (wording may differ slightly; e.g., \u201cGet Snapshot and Wait\u201d). ()<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>dotTrace:\n<ul class=\"wp-block-list\">\n<li>Freezes collection momentarily<\/li>\n\n\n\n<li>Saves a <strong>snapshot file (.dtp \/ .dt)<\/strong>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>You can:\n<ul class=\"wp-block-list\">\n<li><strong>Continue profiling<\/strong> (take multiple snapshots for different scenarios), or<\/li>\n\n\n\n<li><strong>Detach \/ Stop<\/strong> to end the session.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>Once done, stop the app OR detach the profiler.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Step 7 \u2013 Open Snapshot in dotTrace Viewer<\/h3>\n\n\n\n<p>If you used standalone dotTrace, it automatically opens <strong>dotTrace Viewer<\/strong> with your snapshot. ()<\/p>\n\n\n\n<p>You\u2019ll see:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Overview<\/strong> of the snapshot<\/li>\n\n\n\n<li><strong>Thread list<\/strong> and <strong>timeline<\/strong> (for Timeline mode)<\/li>\n\n\n\n<li>Options to switch to:\n<ul class=\"wp-block-list\">\n<li><strong>Call Tree<\/strong><\/li>\n\n\n\n<li><strong>Top Methods \/ Hotspots<\/strong><\/li>\n\n\n\n<li><strong>Events<\/strong> (GC, I\/O, etc.)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Step 8 \u2013 Basic Analysis Workflow (Timeline)<\/h3>\n\n\n\n<p>The core training story: \u201cFollow the time\u201d.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Identify the time range of the slow operation<\/strong>\n<ul class=\"wp-block-list\">\n<li>In <strong>Timeline view<\/strong>, find the spike where CPU or execution for relevant thread is high.<\/li>\n\n\n\n<li>You can zoom\/select a <strong>time range<\/strong>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Filter to relevant threads<\/strong>\n<ul class=\"wp-block-list\">\n<li>For ASP.NET Core, you often look at <strong>thread pool worker threads<\/strong> handling requests.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Open Call Tree \/ Hotspots for that range<\/strong>\n<ul class=\"wp-block-list\">\n<li>Switch to <strong>Call Tree<\/strong> or <strong>Top Methods<\/strong> filtered by your time selection.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Sort by \u201cSelf Time\u201d or \u201cTotal Time\u201d<\/strong>\n<ul class=\"wp-block-list\">\n<li><em>Self Time<\/em> = method\u2019s own work<\/li>\n\n\n\n<li><em>Total Time<\/em> = method + callees<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Drill down<\/strong>\n<ul class=\"wp-block-list\">\n<li>Find your <strong>controller<\/strong> or <strong>service<\/strong> methods (e.g., <code>OrdersController.GetOrders<\/code>)<\/li>\n\n\n\n<li>Expand down the call tree:\n<ul class=\"wp-block-list\">\n<li>Look for heavy LINQ, EF calls, repeated DB queries, large JSON serialization, or blocking I\/O.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<p>Examples of what you might find:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>OrdersRepository.GetOrdersByCustomer<\/code> calling EF\u2019s <code>ToList()<\/code> in a loop.<\/li>\n\n\n\n<li><code>HttpClient.GetAsync<\/code> or <code>Task.Wait()<\/code> causing sync-over-async.<\/li>\n\n\n\n<li><code>Thread.Sleep<\/code> or expensive logging.<\/li>\n<\/ul>\n\n\n\n<p>From here you can create a story:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>\u201cThe <code>\/api\/orders<\/code> request spends 800 ms in <code>GetOrdersByCustomer<\/code>, mostly on N+1 EF queries; optimizing this to a single query or adding caching should reduce latency.\u201d<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Step 9 \u2013 Repeat: Optimize and Re-profile<\/h3>\n\n\n\n<p>dotTrace is most valuable when you use it iteratively:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Apply code changes:\n<ul class=\"wp-block-list\">\n<li>Optimize queries, add caching, reduce allocations, switch to async, remove redundant work, etc.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Rebuild and rerun the app.<\/li>\n\n\n\n<li>Repeat Steps 1\u20138.<\/li>\n\n\n\n<li>Compare snapshots before &amp; after:\n<ul class=\"wp-block-list\">\n<li>dotTrace can help compare snapshots to see improvements.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">6. Step-by-Step Scenario: UI Freeze in WPF\/WinForms (Quick Outline)<\/h2>\n\n\n\n<p>dotTrace has dedicated guidance for UI freezes. ()<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Start dotTrace (Timeline or sampling mode).<\/li>\n\n\n\n<li>Run your WPF\/WinForms app.<\/li>\n\n\n\n<li>Reproduce UI freeze (click the button that hangs).<\/li>\n\n\n\n<li>In Timeline:\n<ul class=\"wp-block-list\">\n<li>Filter by <strong>UI thread<\/strong>.<\/li>\n\n\n\n<li>Look for time where UI thread is <strong>Running<\/strong> but not pumping messages (or blocked).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Analyze call stack on UI thread during freeze:\n<ul class=\"wp-block-list\">\n<li>Find heavy work: DB call, file I\/O, or heavy CPU loops.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Move that work off UI thread:\n<ul class=\"wp-block-list\">\n<li>Use <code>async\/await<\/code>, background worker, <code>Task.Run<\/code>, etc.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Re-profile to confirm UI remains responsive.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">7. dotTrace Command Line &amp; Self-Profiling (Advanced)<\/h2>\n\n\n\n<p>For automation and production-like environments, you may not want to open GUI.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Command line profiler<\/h3>\n\n\n\n<p>JetBrains provides <strong>dotTrace command line tools<\/strong>: ()<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>dotTrace start<\/code> \u2013 run or attach to a process.<\/li>\n\n\n\n<li>Control profiling via <strong>stdin\/file<\/strong> messages like:\n<ul class=\"wp-block-list\">\n<li><code>##dotTrace[\"get-snapshot\"]<\/code><\/li>\n\n\n\n<li><code>##dotTrace[\"disconnect\"]<\/code><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Output is snapshot files which you open later in the GUI.<\/li>\n<\/ul>\n\n\n\n<p>This is perfect for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>CI pipelines (run performance tests + profile).<\/li>\n\n\n\n<li>Remote servers (scripted profiling during a specific test window).<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">JetBrains Profiler API \/ Self-Profiling API<\/h3>\n\n\n\n<p>You can also trigger profiling from inside your code with the <strong>JetBrains Profiler API<\/strong> \/ <strong>Self-Profiling API<\/strong>: ()<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Add <code>JetBrains.Profiler.Api<\/code> NuGet package.<\/li>\n\n\n\n<li>From your code, call methods that:\n<ul class=\"wp-block-list\">\n<li>Attach profiler,<\/li>\n\n\n\n<li>Start collecting data,<\/li>\n\n\n\n<li>Save snapshot.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Allows collecting snapshots from environments where full profiler isn\u2019t installed.<\/li>\n<\/ul>\n\n\n\n<p>Great for:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Capturing performance snapshots on customer environments.<\/li>\n\n\n\n<li>Rare production bugs that only show up in their environment.<\/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. What to Take Away from dotTrace for Your Apps<\/h2>\n\n\n\n<p>When you finish a dotTrace session, you should come out with <strong>concrete, actionable insights<\/strong>, not just screenshots.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Key \u201ctakeaways\u201d per session<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Top 5 slowest operations<\/strong>\n<ul class=\"wp-block-list\">\n<li>Methods or call chains with highest <strong>Total Time<\/strong>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Root causes<\/strong>\n<ul class=\"wp-block-list\">\n<li>\u201cCPU bound in algorithm X\u201d<\/li>\n\n\n\n<li>\u201cBlocked on DB query Y\u201d<\/li>\n\n\n\n<li>\u201cStuck on lock in Z\u201d<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Code paths to change<\/strong>\n<ul class=\"wp-block-list\">\n<li>Exact namespaces\/classes\/methods for developers to optimize.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Before\/After metrics<\/strong>\n<ul class=\"wp-block-list\">\n<li>Latency of key operation before (e.g. 2.5s) vs after optimization (e.g. 200 ms).<\/li>\n\n\n\n<li>CPU usage before vs after.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Things you typically log into your JIRA\/issue:<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>DotTrace <strong>snapshot file name\/path<\/strong>.<\/li>\n\n\n\n<li>Screenshot of call tree\/hotspots with highlighted methods.<\/li>\n\n\n\n<li>Short text summary:\n<ul class=\"wp-block-list\">\n<li>\u201cDuring <code>\/api\/orders<\/code> call, 83% of time is spent in <code>OrderService.GetOrderLines<\/code> due to N+1 EF query pattern.\u201d<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Suggested fixes:\n<ul class=\"wp-block-list\">\n<li>\u201cReplace per-line query with <code>Include<\/code> or custom join; consider caching static configuration data.\u201d<\/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\">9. Why dotTrace is So Useful Compared to Other Options<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Deep integration<\/strong> with Rider \/ ReSharper \/ Visual Studio. ()<\/li>\n\n\n\n<li><strong>Multiple profiling modes<\/strong> (Sampling, Tracing, Line-by-line, Timeline).<\/li>\n\n\n\n<li>Supports <strong>modern .NET, Unity, Mono, Unreal<\/strong> etc., and keeps getting updated with new presets and OS support. ()<\/li>\n\n\n\n<li>Great <strong>Timeline UI<\/strong>:\n<ul class=\"wp-block-list\">\n<li>See CPU, async, GC, I\/O, thread states all in one place.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Strong <strong>filtering and navigation<\/strong>:\n<ul class=\"wp-block-list\">\n<li>By thread, namespace, method, time range, etc.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Command line<\/strong> + <strong>API<\/strong> options for automation.<\/li>\n\n\n\n<li>Good official docs and videos: quick start, timeline tutorials, FAQ, etc. ()<\/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. Best Practices &amp; Tips (for your training material)<\/h2>\n\n\n\n<p>You can turn this into a checklist slide.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Always profile Release builds<\/strong>, not Debug.<\/li>\n\n\n\n<li><strong>Warm up<\/strong> the app:\n<ul class=\"wp-block-list\">\n<li>Run it once before capturing snapshot to avoid JIT noise.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Profile one scenario at a time<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Take separate snapshots for different use cases (login, search, checkout).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Keep snapshots small and focused<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Start profiling <strong>just before<\/strong> reproducing issue; stop right after.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Prefer Timeline for servers<\/strong>, Sampling\/Timeline for desktop.<\/li>\n\n\n\n<li><strong>Don\u2019t trust intuition alone<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Use dotTrace data to confirm where time is really spent.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Repeat after changes<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Always verify performance improvements with a new snapshot.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Document findings<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Save snapshots and summary to your performance wiki \/ JIRA.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Combine with other tools<\/strong>:\n<ul class=\"wp-block-list\">\n<li>dotTrace for <em>code-level<\/em> performance,<\/li>\n\n\n\n<li>dotMemory for memory leaks\/allocations,<\/li>\n\n\n\n<li>dotnet-counters \/ PerfMon for runtime metrics,<\/li>\n\n\n\n<li>APM tools for production telemetry.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n","protected":false},"excerpt":{"rendered":"<p>1. What is dotTrace? Definition What it actually does Profiling modes (high level) 2. Why and When to Use dotTrace Why use dotTrace? Use dotTrace when you need answers to&#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-54193","post","type-post","status-publish","format-standard","hentry","category-best-tools"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54193","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=54193"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54193\/revisions"}],"predecessor-version":[{"id":54194,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/54193\/revisions\/54194"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=54193"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=54193"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=54193"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}