From 4b31efd93b08377f8a4cd69bf4d43310b671658d Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Thu, 17 Apr 2025 08:17:03 -0400 Subject: [PATCH 01/28] [Pre4] Blazor WASM performance profiling --- .../blazor/components/event-handling.md | 2 +- aspnetcore/blazor/components/index.md | 2 +- aspnetcore/blazor/components/lifecycle.md | 2 +- aspnetcore/blazor/components/rendering.md | 4 +- .../blazor/components/templated-components.md | 2 +- .../blazor/globalization-localization.md | 2 +- .../host-and-deploy/configure-linker.md | 2 +- .../host-and-deploy/configure-trimmer.md | 2 +- .../javascript-interoperability/index.md | 1 + .../blazor/performance/app-download-size.md | 108 ++++++++ aspnetcore/blazor/performance/index.md | 26 ++ .../javascript-interoperability.md | 117 ++++++++ aspnetcore/blazor/performance/profiling.md | 213 +++++++++++++++ .../rendering.md} | 258 ++---------------- .../webassembly-lazy-load-assemblies.md | 2 +- aspnetcore/diagnostics/bl0001.md | 2 +- aspnetcore/diagnostics/bl0004.md | 2 +- aspnetcore/performance/diagnostic-tools.md | 2 + aspnetcore/performance/memory.md | 2 +- aspnetcore/performance/overview.md | 4 +- .../aspnetcore-10/includes/blazor.md | 4 + aspnetcore/toc.yml | 12 +- 22 files changed, 515 insertions(+), 256 deletions(-) create mode 100644 aspnetcore/blazor/performance/app-download-size.md create mode 100644 aspnetcore/blazor/performance/index.md create mode 100644 aspnetcore/blazor/performance/javascript-interoperability.md create mode 100644 aspnetcore/blazor/performance/profiling.md rename aspnetcore/blazor/{performance.md => performance/rendering.md} (73%) diff --git a/aspnetcore/blazor/components/event-handling.md b/aspnetcore/blazor/components/event-handling.md index 20aef0c16755..21ac9d89b737 100644 --- a/aspnetcore/blazor/components/event-handling.md +++ b/aspnetcore/blazor/components/event-handling.md @@ -577,7 +577,7 @@ It's often convenient to close over additional values using C# method parameters :::moniker-end -Creating a large number of event delegates in a loop may cause poor rendering performance. For more information, see . +Creating a large number of event delegates in a loop may cause poor rendering performance. For more information, see . Avoid using a loop variable directly in a lambda expression, such as `i` in the preceding `for` loop example. Otherwise, the same variable is used by all lambda expressions, which results in use of the same value in all lambdas. Capture the variable's value in a local variable. In the preceding example: diff --git a/aspnetcore/blazor/components/index.md b/aspnetcore/blazor/components/index.md index 79319ee4c515..8f595a0b7d71 100644 --- a/aspnetcore/blazor/components/index.md +++ b/aspnetcore/blazor/components/index.md @@ -1392,7 +1392,7 @@ You can factor out child components purely as a way of reusing rendering logic. } ``` -For more information, see [Reuse rendering logic](xref:blazor/performance#define-reusable-renderfragments-in-code). +For more information, see [Reuse rendering logic](xref:blazor/performance/rendering#define-reusable-renderfragments-in-code). ## Loop variables with component parameters and child content diff --git a/aspnetcore/blazor/components/lifecycle.md b/aspnetcore/blazor/components/lifecycle.md index 0f5ca364830a..d4bbd33233a4 100644 --- a/aspnetcore/blazor/components/lifecycle.md +++ b/aspnetcore/blazor/components/lifecycle.md @@ -326,7 +326,7 @@ If a disposable component doesn't use a . -For an example of implementing `SetParametersAsync` manually to improve performance in some scenarios, see . +For an example of implementing `SetParametersAsync` manually to improve performance in some scenarios, see . ## After component render (`OnAfterRender{Async}`) diff --git a/aspnetcore/blazor/components/rendering.md b/aspnetcore/blazor/components/rendering.md index 4cc6ae8e2e0e..b4f61e590b51 100644 --- a/aspnetcore/blazor/components/rendering.md +++ b/aspnetcore/blazor/components/rendering.md @@ -39,7 +39,7 @@ Components inherited from s In most cases, conventions result in the correct subset of component rerenders after an event occurs. Developers aren't usually required to provide manual logic to tell the framework which components to rerender and when to rerender them. The overall effect of the framework's conventions is that the component receiving an event rerenders itself, which recursively triggers rerendering of descendant components whose parameter values may have changed. -For more information on the performance implications of the framework's conventions and how to optimize an app's component hierarchy for rendering, see . +For more information on the performance implications of the framework's conventions and how to optimize an app's component hierarchy for rendering, see . ::: moniker range=">= aspnetcore-8.0" @@ -147,7 +147,7 @@ Even if is ::: moniker-end -For more information on performance best practices pertaining to , see . +For more information on performance best practices pertaining to , see . ## `StateHasChanged` diff --git a/aspnetcore/blazor/components/templated-components.md b/aspnetcore/blazor/components/templated-components.md index 54fb84b682cd..d9e2392dc873 100644 --- a/aspnetcore/blazor/components/templated-components.md +++ b/aspnetcore/blazor/components/templated-components.md @@ -329,6 +329,6 @@ Without using the `@key` directive attribute in the `TableTemplate` component, t ## Additional resources -* +* * * [Blazor samples GitHub repository (`dotnet/blazor-samples`)](https://github.com/dotnet/blazor-samples) ([how to download](xref:blazor/fundamentals/index#sample-apps)) diff --git a/aspnetcore/blazor/globalization-localization.md b/aspnetcore/blazor/globalization-localization.md index e864b4898f8a..e99d5ce6f599 100644 --- a/aspnetcore/blazor/globalization-localization.md +++ b/aspnetcore/blazor/globalization-localization.md @@ -143,7 +143,7 @@ Adopting [invariant globalization](#invariant-globalization) only results in usi ``` > [!NOTE] -> [``](xref:blazor/performance#disable-unused-features) overrides an earlier `` setting. We recommend removing the `` setting. +> [``](xref:blazor/performance/app-download-size#disable-unused-features) overrides an earlier `` setting. We recommend removing the `` setting. :::moniker-end diff --git a/aspnetcore/blazor/host-and-deploy/configure-linker.md b/aspnetcore/blazor/host-and-deploy/configure-linker.md index f0834255a584..73119e7eddd5 100644 --- a/aspnetcore/blazor/host-and-deploy/configure-linker.md +++ b/aspnetcore/blazor/host-and-deploy/configure-linker.md @@ -119,4 +119,4 @@ For more information, see [I18N: Pnetlib Internationalization Framework Library ## Additional resources -* + diff --git a/aspnetcore/blazor/host-and-deploy/configure-trimmer.md b/aspnetcore/blazor/host-and-deploy/configure-trimmer.md index 443c72323e85..2e6370621705 100644 --- a/aspnetcore/blazor/host-and-deploy/configure-trimmer.md +++ b/aspnetcore/blazor/host-and-deploy/configure-trimmer.md @@ -178,4 +178,4 @@ Because custom types are never trimmed by Blazor when an app is published, the c ## Additional resources * [Trim self-contained deployments and executables](/dotnet/core/deploying/trimming/trim-self-contained) -* +* diff --git a/aspnetcore/blazor/javascript-interoperability/index.md b/aspnetcore/blazor/javascript-interoperability/index.md index 3b0721618cc6..fe5b2b86ef1c 100644 --- a/aspnetcore/blazor/javascript-interoperability/index.md +++ b/aspnetcore/blazor/javascript-interoperability/index.md @@ -18,6 +18,7 @@ Further JS interop guidance is provided in the following articles: * * +* :::moniker range=">= aspnetcore-7.0" diff --git a/aspnetcore/blazor/performance/app-download-size.md b/aspnetcore/blazor/performance/app-download-size.md new file mode 100644 index 000000000000..1a4ecd48c9d7 --- /dev/null +++ b/aspnetcore/blazor/performance/app-download-size.md @@ -0,0 +1,108 @@ +--- +title: ASP.NET Core Blazor app download size performance best practices +author: guardrex +description: Tips for reducing app download size in ASP.NET Core Blazor apps and avoiding common performance problems. +monikerRange: '>= aspnetcore-3.1' +ms.author: riande +ms.custom: mvc +ms.date: 04/16/2025 +uid: blazor/performance/app-download-size +--- +# ASP.NET Core Blazor app download size performance best practices + +[!INCLUDE[](~/includes/not-latest-version.md)] + +:::moniker range=">= aspnetcore-6.0" + +## Runtime relinking + +For information on how runtime relinking minimizes an app's download size, see . + +:::moniker-end + +## Use `System.Text.Json` + +Blazor's JS interop implementation relies on , which is a high-performance JSON serialization library with low memory allocation. Using shouldn't result in additional app payload size over adding one or more alternate JSON libraries. + +For migration guidance, see [How to migrate from `Newtonsoft.Json` to `System.Text.Json`](/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to). + +## Intermediate Language (IL) trimming + +*This section only applies to client-side Blazor scenarios.* + +:::moniker range=">= aspnetcore-5.0" + +Trimming unused assemblies from a Blazor WebAssembly app reduces the app's size by removing unused code in the app's binaries. For more information, see . + +:::moniker-end + +:::moniker range="< aspnetcore-5.0" + +[Linking a Blazor WebAssembly app](xref:blazor/host-and-deploy/configure-linker) reduces the app's size by trimming unused code in the app's binaries. The Intermediate Language (IL) Linker is only enabled when building in `Release` configuration. To benefit from this, publish the app for deployment using the [`dotnet publish`](/dotnet/core/tools/dotnet-publish) command with the [-c|--configuration](/dotnet/core/tools/dotnet-publish#options) option set to `Release`: + +```dotnetcli +dotnet publish -c Release +``` + +:::moniker-end + +## Lazy load assemblies + +*This section only applies to client-side Blazor scenarios.* + +Load assemblies at runtime when the assemblies are required by a route. For more information, see . + +## Compression + +*This section only applies to Blazor WebAssembly apps.* + +When a Blazor WebAssembly app is published, the output is statically compressed during publish to reduce the app's size and remove the overhead for runtime compression. Blazor relies on the server to perform content negotiation and serve statically-compressed files. + +After an app is deployed, verify that the app serves compressed files. Inspect the **Network** tab in a browser's [developer tools](https://developer.mozilla.org/docs/Glossary/Developer_Tools) and verify that the files are served with `Content-Encoding: br` (Brotli compression) or `Content-Encoding: gz` (Gzip compression). If the host isn't serving compressed files, follow the instructions in . + +## Disable unused features + +*This section only applies to client-side Blazor scenarios.* + +Blazor WebAssembly's runtime includes the following .NET features that can be disabled for a smaller payload size. + +Blazor WebAssembly carries globalization resources required to display values, such as dates and currency, in the user's culture. If the app doesn't require localization, you may [configure the app to support the invariant culture](xref:blazor/globalization-localization#invariant-globalization), which is based on the `en-US` culture. + +:::moniker range=">= aspnetcore-8.0" + +Adopting [invariant globalization](xref:blazor/globalization-localization#invariant-globalization) only results in using non-localized timezone names. To trim timezone code and data from the app, apply the `` MSBuild property with a value of `true` in the app's project file: + +```xml + +true + +``` + +> [!NOTE] +> [``](xref:blazor/performance/app-download-size#disable-unused-features) overrides an earlier `` setting. We recommend removing the `` setting. + +:::moniker-end + +:::moniker range="< aspnetcore-8.0" + +A data file is included to make timezone information correct. If the app doesn't require this feature, consider disabling it by setting the `` MSBuild property to `false` in the app's project file: + +```xml + +false + +``` + +:::moniker-end + +:::moniker range="< aspnetcore-5.0" + +Collation information is included to make APIs such as work correctly. If you're certain that the app doesn't require the collation data, consider disabling it by setting the `BlazorWebAssemblyPreserveCollationData` MSBuild property in the app's project file to `false`: + +```xml + +false + +``` + +:::moniker-end diff --git a/aspnetcore/blazor/performance/index.md b/aspnetcore/blazor/performance/index.md new file mode 100644 index 000000000000..1ecf596b0dc8 --- /dev/null +++ b/aspnetcore/blazor/performance/index.md @@ -0,0 +1,26 @@ +--- +title: ASP.NET Core Blazor performance best practices +author: guardrex +description: Tips for increasing the performance of ASP.NET Core Blazor apps and avoiding common performance problems. +monikerRange: '>= aspnetcore-3.1' +ms.author: riande +ms.custom: mvc +ms.date: 04/16/2025 +uid: blazor/performance/index +--- +# ASP.NET Core Blazor performance best practices + +[!INCLUDE[](~/includes/not-latest-version.md)] + +Blazor is optimized for high performance in most realistic application UI scenarios. However, the best performance depends on developers adopting the correct patterns and features. + +> [!NOTE] +> The code examples in this node of articles adopt [nullable reference types (NRTs) and .NET compiler null-state static analysis](xref:migration/50-to-60#nullable-reference-types-nrts-and-net-compiler-null-state-static-analysis), which are supported in ASP.NET Core in .NET 6 or later. + +:::moniker range=">= aspnetcore-6.0" + +## Ahead-of-time (AOT) compilation + +Ahead-of-time (AOT) compilation compiles a Blazor app's .NET code directly into native WebAssembly for direct execution by the browser. AOT-compiled apps result in larger apps that take longer to download, but AOT-compiled apps usually provide better runtime performance, especially for apps that execute CPU-intensive tasks. For more information, see . + +:::moniker-end diff --git a/aspnetcore/blazor/performance/javascript-interoperability.md b/aspnetcore/blazor/performance/javascript-interoperability.md new file mode 100644 index 000000000000..93f439633f78 --- /dev/null +++ b/aspnetcore/blazor/performance/javascript-interoperability.md @@ -0,0 +1,117 @@ +--- +title: ASP.NET Core Blazor JavaScript interoperability (JS interop) performance best practices +author: guardrex +description: Tips for improving JS interop performance in ASP.NET Core Blazor apps and avoiding common performance problems. +monikerRange: '>= aspnetcore-3.1' +ms.author: riande +ms.custom: mvc +ms.date: 04/16/2025 +uid: blazor/performance/js-interop +--- +# ASP.NET Core Blazor JavaScript interoperability (JS interop) performance best practices + +[!INCLUDE[](~/includes/not-latest-version.md)] + +Calls between .NET and JavaScript require additional overhead because: + +* Calls are asynchronous. +* Parameters and return values are JSON-serialized to provide an easy-to-understand conversion mechanism between .NET and JavaScript types. + +Additionally for server-side Blazor apps, these calls are passed across the network. + +## Avoid excessively fine-grained calls + +Since each call involves some overhead, it can be valuable to reduce the number of calls. Consider the following code, which stores a collection of items in the browser's [`localStorage`](https://developer.mozilla.org/docs/Web/API/Window/localStorage): + +```csharp +private async Task StoreAllInLocalStorage(IEnumerable items) +{ + foreach (var item in items) + { + await JS.InvokeVoidAsync("localStorage.setItem", item.Id, + JsonSerializer.Serialize(item)); + } +} +``` + +The preceding example makes a separate JS interop call for each item. Instead, the following approach reduces the JS interop to a single call: + +```csharp +private async Task StoreAllInLocalStorage(IEnumerable items) +{ + await JS.InvokeVoidAsync("storeAllInLocalStorage", items); +} +``` + +The corresponding JavaScript function stores the whole collection of items on the client: + +```javascript +function storeAllInLocalStorage(items) { + items.forEach(item => { + localStorage.setItem(item.id, JSON.stringify(item)); + }); +} +``` + +For Blazor WebAssembly apps, rolling individual JS interop calls into a single call usually only improves performance significantly if the component makes a large number of JS interop calls. + +## Consider the use of synchronous calls + +:::moniker range=">= aspnetcore-5.0" + +### Call JavaScript from .NET + +[!INCLUDE[](~/blazor/includes/js-interop/synchronous-js-interop-call-js.md)] + +### Call .NET from JavaScript + +[!INCLUDE[](~/blazor/includes/js-interop/synchronous-js-interop-call-dotnet.md)] + +:::moniker-end + +:::moniker range="< aspnetcore-5.0" + +[!INCLUDE[](~/blazor/includes/js-interop/synchronous-js-interop-call-js.md)] + +:::moniker-end + +:::moniker range=">= aspnetcore-5.0 < aspnetcore-7.0" + +## Consider the use of unmarshalled calls + +*This section only applies to Blazor WebAssembly apps.* + +When running on Blazor WebAssembly, it's possible to make unmarshalled calls from .NET to JavaScript. These are synchronous calls that don't perform JSON serialization of arguments or return values. All aspects of memory management and translations between .NET and JavaScript representations are left up to the developer. + +> [!WARNING] +> While using has the least overhead of the JS interop approaches, the JavaScript APIs required to interact with these APIs are currently undocumented and subject to breaking changes in future releases. + +```javascript +function jsInteropCall() { + return BINDING.js_to_mono_obj("Hello world"); +} +``` + +```razor +@inject IJSRuntime JS + +@code { + protected override void OnInitialized() + { + var unmarshalledJs = (IJSUnmarshalledRuntime)JS; + var value = unmarshalledJs.InvokeUnmarshalled("jsInteropCall"); + } +} +``` + +:::moniker-end + +:::moniker range=">= aspnetcore-7.0" + +## Use JavaScript `[JSImport]`/`[JSExport]` interop + +JavaScript `[JSImport]`/`[JSExport]` interop for Blazor WebAssembly apps offers improved performance and stability over the JS interop API in framework releases prior to ASP.NET Core in .NET 7. + +For more information, see . + +:::moniker-end diff --git a/aspnetcore/blazor/performance/profiling.md b/aspnetcore/blazor/performance/profiling.md new file mode 100644 index 000000000000..207ffddcb5f7 --- /dev/null +++ b/aspnetcore/blazor/performance/profiling.md @@ -0,0 +1,213 @@ +--- +title: ASP.NET Core Blazor WebAssembly performance profiling and diagnostic counters +author: guardrex +description: Learn about performance profiling and diagnostic counters in ASP.NET Core Blazor WebAssembly apps. +monikerRange: '>= aspnetcore-10.0' +ms.author: riande +ms.custom: mvc +ms.date: 04/16/2025 +uid: blazor/performance/profiling +--- +# ASP.NET Core Blazor WebAssembly performance profiling and diagnostic counters + +[!INCLUDE[](~/includes/not-latest-version.md)] + +This article describes performance profiling tools and diagnostic counters for Blazor WebAssembly apps. + +## Prerequisite + +Install the [.NET WebAssembly build tools](xref:blazor/webassembly-build-tools-and-aot#net-webassembly-build-tools): + +```dotnetcli +dotnet workload install wasm-tools +``` + +## Browser developer tools + +App code can be manually profiled using the performance profiler in a browser's developer tools console. + +Built-in performance counters are available to track: + +* [Ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation) +* Code interpolation +* [JIT (Just-In-Time) interpolation](https://developer.mozilla.org/docs/Glossary/Just_In_Time_Compilation) +* Call specification (":::no-loc text="callspec":::", sequence and timing of function calls) and instrumentation + +Enable integration with the browser's developer tools profiler using the `` property in the app's project file (`.csproj`). The following additional properties that the native code produced by AOT has symbols, which are visible in the browser devtools profiler: + +```xml + + browser; + true + true + false + true + true + +``` + +Add Blazor start configuration in `wwwroot/index.html`, using the [fingerprinted location of the Blazor WebAssembly script](xref:blazor/fundamentals/static-files#fingerprint-client-side-static-assets-in-standalone-blazor-webassembly-apps). In the following example, the `sampleIntervalMs` option is set to 10 seconds, which is the default setting if `sampleIntervalMs` isn't specified: + +```html + + +``` + +## Call specification (`callspec`) + +If you want to filter profiled methods, you can use callspec + +For more information, see [Trace MonoVM profiler events during startup](https://github.com/dotnet/runtime/blob/main/docs/design/mono/diagnostics-tracing.md#trace-monovm-profiler-events-during-startup). + +Add `callspec` to the `browser` WebAssembly profiler in the `` element. In the following example, the `{APP NAMESPACE}` placeholder is the app's namespace: + +```xml +browser:callspec=N:{APP NAMESPACE}; +``` + +Configure `callSpec` in `browserProfilerOptions`. Replace the `{APP NAMESPACE}` placeholder in the following example with the app's namespace: + +```html + + +``` + +## Log profiling for memory troubleshooting + +Enable integration with the log profiler using the `` and `` properties in the app's project file (`.csproj`): + +```xml + + log; + true + +``` + +In order to trigger a heap shot, add the following, where the `{APP NAMESPACE}` placeholder is the app's namespace: + +```csharp +namespace {APP NAMESPACE}; + +class Profiling +{ + [JSExport] + [MethodImpl(MethodImplOptions.NoInlining)] + public static void TakeHeapshot() { } +} +``` + +Invoke `{APP NAMESPACE}.Profiling.TakeHeapshot()` from your code in order to create a memory heap shot and flush the contents of the profile to the file system. Download the resulting `.mpld` file to analyze the data. + +## EventPipe profiler + +[EventPipe](/dotnet/core/diagnostics/eventpipe) is a runtime component used to collect tracing data, similar to [ETW](/windows/win32/etw/event-tracing-portal) and [perf_events](https://wikipedia.org/wiki/Perf_%28Linux%29). + +* Manual testing + * Browser developer tools: Download, open in Visual Studio, and find expected calls. + * [`dotnet-trace`](/dotnet/core/diagnostics/dotnet-trace): Open the `.nettrace` output file in Visual Studio and find the expected method calls. +* Web-based testing + * Use the JavaScript API to obtain a [promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) of NetTrace (`.nettrace`) bytes. + * Upload the file via HTTP. + * Parse and validate that the trace contains the expected method calls. + +Built-in performance counters are available to track: + +* [Ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation) +* Code interpolation +* JIT (Just-In-Time) interpolation + +## GC (Garbage Collector) dumps + +* Manual testing + * Browser developer tools: Download, open in Visual Studio, and find the expected classes. + * [`dotnet-gcdump` (`collect`/convert` options)](/dotnet/core/diagnostics/dotnet-gcdump): To view the captured GC dump files, see [View the GC dump captured from dotnet-gcdump](/dotnet/core/diagnostics/dotnet-gcdump#view-the-gc-dump-captured-from-dotnet-gcdump). +* Web-based testing + * Use the JavaScript API to obtain a [promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) of NetTrace (`.nettrace`) bytes. + * Upload the file via HTTP. + * Parse and validate that the trace contains the expected classes. + +## Counters trace + +* Manual testing + * Browser developer tools: Download, open in Visual Studio, and find the expected counters/values. + * [`dotnet-counters collect`](/dotnet/core/diagnostics/dotnet-counters): Open the `.csv`/`.json` output file in Visual Studio and find the expected counters/values. +* Web-based testing + * Use the JavaScript API to obtain a [promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) of NetTrace (`.nettrace`) bytes. + * Upload the file via HTTP. + * Parse and validate that the trace contains the expected counters/values. + +## .NET Core Diagnostics Client Library example + +Parse and validate NetTrace (`.nettrace`) messages using the .NET Core Diagnostics Client Library: + +* [`dotnet/diagnostics` GitHub repository](https://github.com/dotnet/diagnostics) +* [`Microsoft.Diagnostics.NETCore.Client` NuGet package](https://www.nuget.org/packages/Microsoft.Diagnostics.NETCore.Client) + +For more information, see the [.NET Core diagnostics documentation](/dotnet/core/diagnostics/) and the [`IpcMessage` API (reference source)](https://github.com/dotnet/diagnostics/blob/main/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/IpcMessage.cs). + +[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] + +The following example: + +* Collects a GC (Garbage Collector) dump of the live .NET process. +* Collects performance counters for 60 seconds. +* Collects CPU counters for 60 seconds. + +In the project file (`.csproj`), the following properties enable integration with the browser's profiler: + +* ``: Enables integration with the profiler in the browser's developer tools. +* ``: Enables diagnostic server. +* ``: Enables performance instrumentation for the sampling CPU profiler. +* ``: Enables metrics. For more information, see the [`System.Diagnostics.Metrics` namespace](/dotnet/api/system.diagnostics.metrics). +* ``: Enables system events. For more information, see [Diagnostics and instrumentation: Observability and telemetry](/dotnet/core/deploying/native-aot/diagnostics#observability-and-telemetry). + +```xml + + browser; + true + true + true + true + +``` + +The [`Timing-Allow-Origin` HTTP header](https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/Timing-Allow-Origin) allows for more precise time measurements. + +Browser developer tools console calls in the following example that trigger profiling: + +* `collectGcDump`: Collect a GC (Garbage Collector) dump. +* `collectPerfCounters(durationSeconds)`: Collect performance counters. +* `collectCpuSamples(durationSeconds)`: Collect performance counters. + +```javascript +globalThis.getDotnetRuntime(0).collectGcDump(); +globalThis.getDotnetRuntime(0).collectPerfCounters({durationSeconds: 60}); +globalThis.getDotnetRuntime(0).collectCpuSamples({durationSeconds: 60}); +``` + +## Additional resources + +* [What diagnostic tools are available in .NET Core?](/dotnet/core/diagnostics/) +* [.NET diagnostic tools](/dotnet/core/diagnostics/tools-overview) diff --git a/aspnetcore/blazor/performance.md b/aspnetcore/blazor/performance/rendering.md similarity index 73% rename from aspnetcore/blazor/performance.md rename to aspnetcore/blazor/performance/rendering.md index 908ee0f3b7df..08c61537029d 100644 --- a/aspnetcore/blazor/performance.md +++ b/aspnetcore/blazor/performance/rendering.md @@ -1,27 +1,20 @@ --- -title: ASP.NET Core Blazor performance best practices +title: ASP.NET Core Blazor rendering performance best practices author: guardrex -description: Tips for increasing performance in ASP.NET Core Blazor apps and avoiding common performance problems. +description: Tips for improving the rendering performance of ASP.NET Core Blazor apps and avoiding common performance problems. monikerRange: '>= aspnetcore-3.1' ms.author: riande ms.custom: mvc -ms.date: 11/12/2024 -uid: blazor/performance +ms.date: 04/16/2025 +uid: blazor/performance/rendering --- -# ASP.NET Core Blazor performance best practices +# ASP.NET Core Blazor rendering performance best practices [!INCLUDE[](~/includes/not-latest-version.md)] -Blazor is optimized for high performance in most realistic application UI scenarios. However, the best performance depends on developers adopting the correct patterns and features. - -> [!NOTE] -> The code examples in this article adopt [nullable reference types (NRTs) and .NET compiler null-state static analysis](xref:migration/50-to-60#nullable-reference-types-nrts-and-net-compiler-null-state-static-analysis), which are supported in ASP.NET Core in .NET 6 or later. - -## Optimize rendering speed - Optimize rendering speed to minimize rendering workload and improve UI responsiveness, which can yield a *ten-fold or higher improvement* in UI rendering speed. -### Avoid unnecessary rendering of component subtrees +## Avoid unnecessary rendering of component subtrees You might be able to remove the majority of a parent component's rendering cost by skipping the rerendering of child component subtrees when an event occurs. You should only be concerned about skipping the rerendering subtrees that are particularly expensive to render and are causing UI lag. @@ -77,7 +70,7 @@ For more information, see the following resources: :::moniker range=">= aspnetcore-5.0" -### Virtualization +## Virtualization When rendering large amounts of UI within a loop, for example, a list or grid with thousands of entries, the sheer quantity of rendering operations can lead to a lag in UI rendering. Given that the user can only see a small number of elements at once without scrolling, it's often wasteful to spend time rendering elements that aren't currently visible. @@ -87,7 +80,7 @@ For more information, see . :::moniker-end -### Create lightweight, optimized components +## Create lightweight, optimized components Most Razor components don't require aggressive optimization efforts because most components don't repeat in the UI and don't rerender at high frequency. For example, routable components with an `@page` directive and components used to render high-level pieces of the UI, such as dialogs or forms, most likely appear only one at a time and only rerender in response to a user gesture. These components don't usually create high rendering workload, so you can freely use any combination of framework features without much concern about rendering performance. @@ -99,7 +92,7 @@ However, there are common scenarios where components are repeated at scale and o If modelling each element, cell, or data point as a separate component instance, there are often so many of them that their rendering performance becomes critical. This section provides advice on making such components lightweight so that the UI remains fast and responsive. -#### Avoid thousands of component instances +## Avoid thousands of component instances Each component is a separate island that can render independently of its parents and children. By choosing how to split the UI into a hierarchy of components, you are taking control over the granularity of UI rendering. This can result in either good or poor performance. @@ -111,9 +104,7 @@ It's possible to make components more lightweight so that you can have more of t For more information on memory management, see . -##### Inline child components into their parents - -Consider the following portion of a parent component that renders child components in a loop: +**Inline child components into their parents:** Consider the following portion of a parent component that renders child components in a loop: ```razor
@@ -152,9 +143,7 @@ The preceding example performs well if thousands of messages aren't shown at onc
``` -##### Define reusable `RenderFragments` in code - -You might be factoring out child components purely as a way of reusing rendering logic. If that's the case, you can create reusable rendering logic without implementing additional components. In any component's `@code` block, define a . Render the fragment from any location as many times as needed: +**Define reusable `RenderFragments` in code:** You might be factoring out child components purely as a way of reusing rendering logic. If that's the case, you can create reusable rendering logic without implementing additional components. In any component's `@code` block, define a . Render the fragment from any location as many times as needed: ```razor @RenderWelcomeInfo @@ -206,7 +195,7 @@ protected RenderFragment DisplayTitle => ; ``` -#### Don't receive too many parameters +## Don't receive too many parameters If a component repeats extremely often, for example, hundreds or thousands of times, the overhead of passing and receiving each parameter builds up. @@ -241,7 +230,7 @@ For more information on generic type parameters (`@typeparam`), see the followin * * -#### Ensure cascading parameters are fixed +## Ensure cascading parameters are fixed The [`CascadingValue` component](xref:blazor/components/cascading-values-and-parameters#cascadingvalue-component) has an optional `IsFixed` parameter: @@ -260,7 +249,7 @@ Where a component passes `this` as a cascaded value, `IsFixed` can also be set t For more information, see . -#### Avoid attribute splatting with `CaptureUnmatchedValues` +## Avoid attribute splatting with `CaptureUnmatchedValues` Components can elect to receive "unmatched" parameter values using the flag: @@ -282,7 +271,7 @@ Use . -#### Implement `SetParametersAsync` manually +## Implement `SetParametersAsync` manually A significant source of per-component rendering overhead is writing incoming parameter values to `[Parameter]` properties. The renderer uses [reflection](/dotnet/csharp/advanced-topics/reflection-and-attributes/) to write the parameter values, which can lead to poor performance at scale. @@ -340,7 +329,7 @@ In the preceding code, returning the base class and supplying custom logic is complicated and laborious, so we don't generally recommend adopting this approach. In extreme cases, it can improve rendering performance by 20-25%, but you should only consider this approach in the extreme scenarios listed earlier in this section. -### Don't trigger events too rapidly +## Don't trigger events too rapidly Some browser events fire extremely frequently. For example, `onmousemove` and `onscroll` can fire tens or hundreds of times per second. In most cases, you don't need to perform UI updates this frequently. If events are triggered too rapidly, you may harm UI responsiveness or consume excessive CPU time. @@ -397,7 +386,7 @@ The corresponding JavaScript code registers the DOM event listener for mouse mov ``` -### Avoid rerendering after handling events without state changes +## Avoid rerendering after handling events without state changes Components inherit from , which automatically invokes after the component's event handlers are invoked. In some cases, it might be unnecessary or undesirable to trigger a rerender after an event handler is invoked. For example, an event handler might not modify component state. In these scenarios, the app can leverage the interface to control the behavior of Blazor's event handling. @@ -542,7 +531,7 @@ In the following example: In addition to implementing the interface, leveraging the other best practices described in this article can also help reduce unwanted renders after events are handled. For example, overriding in child components of the target component can be used to control rerendering. -### Avoid recreating delegates for many repeated elements or components +## Avoid recreating delegates for many repeated elements or components Blazor's recreation of [lambda expression delegates](xref:blazor/components/event-handling#lambda-expressions) for elements or components in a loop can lead to poor performance. @@ -638,214 +627,3 @@ If a large number of buttons are rendered using the preceding approach, renderin } } ``` - -## Optimize JavaScript interop speed - -Calls between .NET and JavaScript require additional overhead because: - -* Calls are asynchronous. -* Parameters and return values are JSON-serialized to provide an easy-to-understand conversion mechanism between .NET and JavaScript types. - -Additionally for server-side Blazor apps, these calls are passed across the network. - -### Avoid excessively fine-grained calls - -Since each call involves some overhead, it can be valuable to reduce the number of calls. Consider the following code, which stores a collection of items in the browser's [`localStorage`](https://developer.mozilla.org/docs/Web/API/Window/localStorage): - -```csharp -private async Task StoreAllInLocalStorage(IEnumerable items) -{ - foreach (var item in items) - { - await JS.InvokeVoidAsync("localStorage.setItem", item.Id, - JsonSerializer.Serialize(item)); - } -} -``` - -The preceding example makes a separate JS interop call for each item. Instead, the following approach reduces the JS interop to a single call: - -```csharp -private async Task StoreAllInLocalStorage(IEnumerable items) -{ - await JS.InvokeVoidAsync("storeAllInLocalStorage", items); -} -``` - -The corresponding JavaScript function stores the whole collection of items on the client: - -```javascript -function storeAllInLocalStorage(items) { - items.forEach(item => { - localStorage.setItem(item.id, JSON.stringify(item)); - }); -} -``` - -For Blazor WebAssembly apps, rolling individual JS interop calls into a single call usually only improves performance significantly if the component makes a large number of JS interop calls. - -### Consider the use of synchronous calls - -:::moniker range=">= aspnetcore-5.0" - -#### Call JavaScript from .NET - -[!INCLUDE[](~/blazor/includes/js-interop/synchronous-js-interop-call-js.md)] - -#### Call .NET from JavaScript - -[!INCLUDE[](~/blazor/includes/js-interop/synchronous-js-interop-call-dotnet.md)] - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" - -[!INCLUDE[](~/blazor/includes/js-interop/synchronous-js-interop-call-js.md)] - -:::moniker-end - -:::moniker range=">= aspnetcore-5.0 < aspnetcore-7.0" - -### Consider the use of unmarshalled calls - -*This section only applies to Blazor WebAssembly apps.* - -When running on Blazor WebAssembly, it's possible to make unmarshalled calls from .NET to JavaScript. These are synchronous calls that don't perform JSON serialization of arguments or return values. All aspects of memory management and translations between .NET and JavaScript representations are left up to the developer. - -> [!WARNING] -> While using has the least overhead of the JS interop approaches, the JavaScript APIs required to interact with these APIs are currently undocumented and subject to breaking changes in future releases. - -```javascript -function jsInteropCall() { - return BINDING.js_to_mono_obj("Hello world"); -} -``` - -```razor -@inject IJSRuntime JS - -@code { - protected override void OnInitialized() - { - var unmarshalledJs = (IJSUnmarshalledRuntime)JS; - var value = unmarshalledJs.InvokeUnmarshalled("jsInteropCall"); - } -} -``` - -:::moniker-end - -:::moniker range=">= aspnetcore-7.0" - -### Use JavaScript `[JSImport]`/`[JSExport]` interop - -JavaScript `[JSImport]`/`[JSExport]` interop for Blazor WebAssembly apps offers improved performance and stability over the JS interop API in framework releases prior to ASP.NET Core in .NET 7. - -For more information, see . - -:::moniker-end - -:::moniker range=">= aspnetcore-6.0" - -## Ahead-of-time (AOT) compilation - -Ahead-of-time (AOT) compilation compiles a Blazor app's .NET code directly into native WebAssembly for direct execution by the browser. AOT-compiled apps result in larger apps that take longer to download, but AOT-compiled apps usually provide better runtime performance, especially for apps that execute CPU-intensive tasks. For more information, see . - -:::moniker-end - -## Minimize app download size - -:::moniker range=">= aspnetcore-6.0" - -### Runtime relinking - -For information on how runtime relinking minimizes an app's download size, see . - -:::moniker-end - -### Use `System.Text.Json` - -Blazor's JS interop implementation relies on , which is a high-performance JSON serialization library with low memory allocation. Using shouldn't result in additional app payload size over adding one or more alternate JSON libraries. - -For migration guidance, see [How to migrate from `Newtonsoft.Json` to `System.Text.Json`](/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to). - -### Intermediate Language (IL) trimming - -*This section only applies to client-side Blazor scenarios.* - -:::moniker range=">= aspnetcore-5.0" - -Trimming unused assemblies from a Blazor WebAssembly app reduces the app's size by removing unused code in the app's binaries. For more information, see . - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" - -[Linking a Blazor WebAssembly app](xref:blazor/host-and-deploy/configure-linker) reduces the app's size by trimming unused code in the app's binaries. The Intermediate Language (IL) Linker is only enabled when building in `Release` configuration. To benefit from this, publish the app for deployment using the [`dotnet publish`](/dotnet/core/tools/dotnet-publish) command with the [-c|--configuration](/dotnet/core/tools/dotnet-publish#options) option set to `Release`: - -```dotnetcli -dotnet publish -c Release -``` - -:::moniker-end - -### Lazy load assemblies - -*This section only applies to client-side Blazor scenarios.* - -Load assemblies at runtime when the assemblies are required by a route. For more information, see . - -### Compression - -*This section only applies to Blazor WebAssembly apps.* - -When a Blazor WebAssembly app is published, the output is statically compressed during publish to reduce the app's size and remove the overhead for runtime compression. Blazor relies on the server to perform content negotiation and serve statically-compressed files. - -After an app is deployed, verify that the app serves compressed files. Inspect the **Network** tab in a browser's [developer tools](https://developer.mozilla.org/docs/Glossary/Developer_Tools) and verify that the files are served with `Content-Encoding: br` (Brotli compression) or `Content-Encoding: gz` (Gzip compression). If the host isn't serving compressed files, follow the instructions in . - -### Disable unused features - -*This section only applies to client-side Blazor scenarios.* - -Blazor WebAssembly's runtime includes the following .NET features that can be disabled for a smaller payload size: - -* Blazor WebAssembly carries globalization resources required to display values, such as dates and currency, in the user's culture. If the app doesn't require localization, you may [configure the app to support the invariant culture](xref:blazor/globalization-localization#invariant-globalization), which is based on the `en-US` culture. - -:::moniker range=">= aspnetcore-8.0" - -* Adopting [invariant globalization](xref:blazor/globalization-localization#invariant-globalization) only results in using non-localized timezone names. To trim timezone code and data from the app, apply the `` MSBuild property with a value of `true` in the app's project file: - - ```xml - - true - - ``` - - > [!NOTE] - > [``](xref:blazor/performance#disable-unused-features) overrides an earlier `` setting. We recommend removing the `` setting. - -:::moniker-end - -:::moniker range="< aspnetcore-8.0" - -* A data file is included to make timezone information correct. If the app doesn't require this feature, consider disabling it by setting the `` MSBuild property to `false` in the app's project file: - - ```xml - - false - - ``` - -:::moniker-end - -:::moniker range="< aspnetcore-5.0" - -* Collation information is included to make APIs such as work correctly. If you're certain that the app doesn't require the collation data, consider disabling it by setting the `BlazorWebAssemblyPreserveCollationData` MSBuild property in the app's project file to `false`: - - ```xml - - false - - ``` - -:::moniker-end diff --git a/aspnetcore/blazor/webassembly-lazy-load-assemblies.md b/aspnetcore/blazor/webassembly-lazy-load-assemblies.md index 2317df26779b..e1f857aac198 100644 --- a/aspnetcore/blazor/webassembly-lazy-load-assemblies.md +++ b/aspnetcore/blazor/webassembly-lazy-load-assemblies.md @@ -822,4 +822,4 @@ When the `Robot` component from the RCL is requested at `/robot`, the `GrantImah ## Additional resources * [Handle asynchronous navigation events with `OnNavigateAsync`](xref:blazor/fundamentals/routing#handle-asynchronous-navigation-events-with-onnavigateasync) -* +* diff --git a/aspnetcore/diagnostics/bl0001.md b/aspnetcore/diagnostics/bl0001.md index f9be1941fa5a..f10992c5bbd2 100644 --- a/aspnetcore/diagnostics/bl0001.md +++ b/aspnetcore/diagnostics/bl0001.md @@ -50,7 +50,7 @@ Component parameters are required to have publicly accessible setters to allow t } ``` -* If making the property non-public is not possible, consider [implementing `SetParametersAsync` manually](xref:blazor/performance#implement-setparametersasync-manually). +* If making the property non-public is not possible, consider [implementing `SetParametersAsync` manually](xref:blazor/performance/rendering#implement-setparametersasync-manually). ## When to suppress warnings diff --git a/aspnetcore/diagnostics/bl0004.md b/aspnetcore/diagnostics/bl0004.md index 0796d47fd011..6629468966eb 100644 --- a/aspnetcore/diagnostics/bl0004.md +++ b/aspnetcore/diagnostics/bl0004.md @@ -41,7 +41,7 @@ Component parameters are required to be public and must have a public setter. } ``` -* If making the property non-public is not possible, consider [implementing `SetParametersAsync` manually](xref:blazor/performance#implement-setparametersasync-manually). +* If making the property non-public is not possible, consider [implementing `SetParametersAsync` manually](xref:blazor/performance/rendering#implement-setparametersasync-manually). ## When to suppress warnings diff --git a/aspnetcore/performance/diagnostic-tools.md b/aspnetcore/performance/diagnostic-tools.md index 77bf092c6abc..2a73661e62a7 100644 --- a/aspnetcore/performance/diagnostic-tools.md +++ b/aspnetcore/performance/diagnostic-tools.md @@ -13,6 +13,8 @@ By [Mike Rousos](https://github.com/mjrousos) This article lists tools for diagnosing performance issues in ASP.NET Core. +For information on Blazor WebAssembly performance diagnostic tools and counters, see . + ## Visual Studio Diagnostic Tools The [profiling and diagnostic tools](/visualstudio/profiling) built into Visual Studio are a good place to start investigating performance issues. These tools are powerful and convenient to use from the Visual Studio development environment. The tooling allows analysis of CPU usage, memory usage, and performance events in ASP.NET Core apps. Being built-in makes profiling easy at development time. diff --git a/aspnetcore/performance/memory.md b/aspnetcore/performance/memory.md index 4b9290ed604f..f95d2a836faf 100644 --- a/aspnetcore/performance/memory.md +++ b/aspnetcore/performance/memory.md @@ -7,7 +7,6 @@ ms.custom: mvc ms.date: 4/05/2019 uid: performance/memory --- - # Memory management and garbage collection (GC) in ASP.NET Core By [Sébastien Ros](https://github.com/sebastienros) and [Rick Anderson](https://twitter.com/RickAndMSFT) @@ -427,6 +426,7 @@ The main difference is allocated bytes, and as a consequence much fewer generati ## Additional resources +* * [Garbage Collection](/dotnet/standard/garbage-collection/) * [Understanding different GC modes with Concurrency Visualizer](https://blogs.msdn.microsoft.com/seteplia/2017/01/05/understanding-different-gc-modes-with-concurrency-visualizer/) * [Large Object Heap Uncovered](https://devblogs.microsoft.com/dotnet/large-object-heap-uncovered-from-an-old-msdn-article/) diff --git a/aspnetcore/performance/overview.md b/aspnetcore/performance/overview.md index 4578a97bd206..14428678afb9 100644 --- a/aspnetcore/performance/overview.md +++ b/aspnetcore/performance/overview.md @@ -13,7 +13,7 @@ The following articles provide information about how to optimize the performance :::moniker range=">= aspnetcore-8.0" -* +* * * * @@ -30,7 +30,7 @@ The following articles provide information about how to optimize the performance :::moniker range="< aspnetcore-8.0" -* +* * * * diff --git a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md index ccf25f2e19d5..616371bb9344 100644 --- a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md +++ b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md @@ -346,4 +346,8 @@ For more information, see the following sections of the *Call JavaScript functio * [Create an instance of a JS object using a constructor function](xref:blazor/js-interop/call-javascript-from-dotnet#create-an-instance-of-a-js-object-using-a-constructor-function) * [Read or modify the value of a JS object property](xref:blazor/js-interop/call-javascript-from-dotnet#read-or-modify-the-value-of-a-js-object-property) +### Blazor WebAssembly performance profiling and diagnostic counters + +New performance profiling and diagnostic counters are available for Blazor WebAssembly apps. For more information, see . + --> diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 89bfd084bb96..e0ff370c29ca 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -651,7 +651,17 @@ items: - name: WebAssembly native dependencies uid: blazor/webassembly-native-dependencies - name: Performance - uid: blazor/performance + items: + - name: Overview + uid: blazor/performance/index + - name: Rendering speed + uid: blazor/performance/rendering + - name: App download size + uid: blazor/performance/app-download-size + - name: JavaScript interop + uid: blazor/performance/js-interop + - name: WebAssembly profiling + uid: blazor/performance/profiling - name: Test components uid: blazor/test - name: Progressive Web Applications From f21854e140bb1c70495079c8d35eeb9d040ecce1 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Thu, 17 Apr 2025 08:40:46 -0400 Subject: [PATCH 02/28] Updates --- .openpublishing.redirection.json | 5 +++++ aspnetcore/blazor/performance/profiling.md | 4 ++-- aspnetcore/blazor/performance/rendering.md | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index bb2d0991f928..f0840f77f820 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1397,6 +1397,11 @@ "source_path": "aspnetcore/blazor/host-and-deploy/webassembly/integrity-check-failures.md", "redirect_url": "/aspnet/core/blazor/host-and-deploy/webassembly/bundle-caching-and-integrity-check-failures", "redirect_document_id": false + }, + { + "source_path": "aspnetcore/blazor/performance.md", + "redirect_url": "/aspnet/core/blazor/performance/", + "redirect_document_id": false } ] } diff --git a/aspnetcore/blazor/performance/profiling.md b/aspnetcore/blazor/performance/profiling.md index 207ffddcb5f7..bd777bb5b8ae 100644 --- a/aspnetcore/blazor/performance/profiling.md +++ b/aspnetcore/blazor/performance/profiling.md @@ -10,13 +10,13 @@ uid: blazor/performance/profiling --- # ASP.NET Core Blazor WebAssembly performance profiling and diagnostic counters -[!INCLUDE[](~/includes/not-latest-version.md)] +[!INCLUDE[](~/includes/not-latest-version-without-not-supported-content.md)] This article describes performance profiling tools and diagnostic counters for Blazor WebAssembly apps. ## Prerequisite -Install the [.NET WebAssembly build tools](xref:blazor/webassembly-build-tools-and-aot#net-webassembly-build-tools): +Install the [.NET WebAssembly build tools](xref:blazor/tooling/webassembly#net-webassembly-build-tools): ```dotnetcli dotnet workload install wasm-tools diff --git a/aspnetcore/blazor/performance/rendering.md b/aspnetcore/blazor/performance/rendering.md index 08c61537029d..7c5b18cdb028 100644 --- a/aspnetcore/blazor/performance/rendering.md +++ b/aspnetcore/blazor/performance/rendering.md @@ -219,7 +219,7 @@ To reduce parameter load, bundle multiple parameters in a custom class. For exam However, keep in mind that bundling primitive parameters into a class isn't always an advantage. While it can reduce parameter count, it also impacts how change detection and rendering behave. Passing non-primitive parameters always triggers a re-render, because Blazor can't know whether arbitrary objects have internally mutable state, whereas passing primitive parameters only triggers a re-render if their values have actually changed. -Also, consider that it might be an improvement not to have a table cell component, as shown in the preceding example, and instead [inline its logic into the parent component](#inline-child-components-into-their-parents). +Also, consider that it might be an improvement not to have a table cell component, as shown in the preceding example, and instead [inline its logic into the parent component](#avoid-thousands-of-component-instances). > [!NOTE] > When multiple approaches are available for improving performance, benchmarking the approaches is usually required to determine which approach yields the best results. From 895c85afe6221d64bcbd589110fe263f8b4d5630 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Thu, 17 Apr 2025 08:52:26 -0400 Subject: [PATCH 03/28] Updates --- aspnetcore/blazor/performance/profiling.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/aspnetcore/blazor/performance/profiling.md b/aspnetcore/blazor/performance/profiling.md index bd777bb5b8ae..3ffb05ca3402 100644 --- a/aspnetcore/blazor/performance/profiling.md +++ b/aspnetcore/blazor/performance/profiling.md @@ -10,7 +10,11 @@ uid: blazor/performance/profiling --- # ASP.NET Core Blazor WebAssembly performance profiling and diagnostic counters -[!INCLUDE[](~/includes/not-latest-version-without-not-supported-content.md)] + This article describes performance profiling tools and diagnostic counters for Blazor WebAssembly apps. From 3a30f36c102f8c7dff991777c2638549fafc03ad Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Thu, 17 Apr 2025 09:22:08 -0400 Subject: [PATCH 04/28] Updates --- aspnetcore/blazor/performance/profiling.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aspnetcore/blazor/performance/profiling.md b/aspnetcore/blazor/performance/profiling.md index 3ffb05ca3402..f6e1b59f5f2f 100644 --- a/aspnetcore/blazor/performance/profiling.md +++ b/aspnetcore/blazor/performance/profiling.md @@ -129,7 +129,7 @@ Invoke `{APP NAMESPACE}.Profiling.TakeHeapshot()` from your code in order to cre [EventPipe](/dotnet/core/diagnostics/eventpipe) is a runtime component used to collect tracing data, similar to [ETW](/windows/win32/etw/event-tracing-portal) and [perf_events](https://wikipedia.org/wiki/Perf_%28Linux%29). * Manual testing - * Browser developer tools: Download, open in Visual Studio, and find expected calls. + * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find expected calls. * [`dotnet-trace`](/dotnet/core/diagnostics/dotnet-trace): Open the `.nettrace` output file in Visual Studio and find the expected method calls. * Web-based testing * Use the JavaScript API to obtain a [promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) of NetTrace (`.nettrace`) bytes. @@ -145,7 +145,7 @@ Built-in performance counters are available to track: ## GC (Garbage Collector) dumps * Manual testing - * Browser developer tools: Download, open in Visual Studio, and find the expected classes. + * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find expected calls. * [`dotnet-gcdump` (`collect`/convert` options)](/dotnet/core/diagnostics/dotnet-gcdump): To view the captured GC dump files, see [View the GC dump captured from dotnet-gcdump](/dotnet/core/diagnostics/dotnet-gcdump#view-the-gc-dump-captured-from-dotnet-gcdump). * Web-based testing * Use the JavaScript API to obtain a [promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) of NetTrace (`.nettrace`) bytes. @@ -155,7 +155,7 @@ Built-in performance counters are available to track: ## Counters trace * Manual testing - * Browser developer tools: Download, open in Visual Studio, and find the expected counters/values. + * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find expected calls. * [`dotnet-counters collect`](/dotnet/core/diagnostics/dotnet-counters): Open the `.csv`/`.json` output file in Visual Studio and find the expected counters/values. * Web-based testing * Use the JavaScript API to obtain a [promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) of NetTrace (`.nettrace`) bytes. From fc1421a2234c7542f1038bbfa755e3fe8f13cb13 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 18 Apr 2025 08:27:43 -0400 Subject: [PATCH 05/28] Updates --- aspnetcore/blazor/performance/profiling.md | 23 +++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/aspnetcore/blazor/performance/profiling.md b/aspnetcore/blazor/performance/profiling.md index f6e1b59f5f2f..bf8d5cf31c5b 100644 --- a/aspnetcore/blazor/performance/profiling.md +++ b/aspnetcore/blazor/performance/profiling.md @@ -37,7 +37,14 @@ Built-in performance counters are available to track: * [JIT (Just-In-Time) interpolation](https://developer.mozilla.org/docs/Glossary/Just_In_Time_Compilation) * Call specification (":::no-loc text="callspec":::", sequence and timing of function calls) and instrumentation -Enable integration with the browser's developer tools profiler using the `` property in the app's project file (`.csproj`). The following additional properties that the native code produced by AOT has symbols, which are visible in the browser devtools profiler: +Enable integration with the browser's developer tools profiler using the `` property in the app's project file (`.csproj`). Include the following additional properties: + +* ``: The "`browser`" profiler enables integration with the profiler in the browser's developer tools. +* ``: Run AOT compilation. Default: `false` +* ``: Run AOT compilation after build. By default, it is run only for publish. Default: `false` +* ``: Set to `false` to prevent stripping the native executable. Default: `true` +* ``: Build with native debug symbols. Default: `true` +* ``: Build the native executable. Default: `false` ```xml @@ -68,11 +75,9 @@ Add Blazor start configuration in `wwwroot/index.html`, using the [fingerprinted ``` -## Call specification (`callspec`) - -If you want to filter profiled methods, you can use callspec +## Call specification (:::no-loc text="callspec":::) -For more information, see [Trace MonoVM profiler events during startup](https://github.com/dotnet/runtime/blob/main/docs/design/mono/diagnostics-tracing.md#trace-monovm-profiler-events-during-startup). +If you want to filter profiled methods, you can use call specification (:::no-loc text="callspec":::). For more information, see [Trace MonoVM profiler events during startup](https://github.com/dotnet/runtime/blob/main/docs/design/mono/diagnostics-tracing.md#trace-monovm-profiler-events-during-startup). Add `callspec` to the `browser` WebAssembly profiler in the `` element. In the following example, the `{APP NAMESPACE}` placeholder is the app's namespace: @@ -109,12 +114,12 @@ Enable integration with the log profiler using the `` and ` ``` -In order to trigger a heap shot, add the following, where the `{APP NAMESPACE}` placeholder is the app's namespace: +To trigger a heap shot, add the following, where the `{APP NAMESPACE}` placeholder is the app's namespace: ```csharp namespace {APP NAMESPACE}; -class Profiling +public class Profiling { [JSExport] [MethodImpl(MethodImplOptions.NoInlining)] @@ -122,7 +127,7 @@ class Profiling } ``` -Invoke `{APP NAMESPACE}.Profiling.TakeHeapshot()` from your code in order to create a memory heap shot and flush the contents of the profile to the file system. Download the resulting `.mpld` file to analyze the data. +Invoke `TakeHeapshot` to create a memory heap shot and flush the contents of the profile to the file system. Download the resulting `.mpld` file to analyze the data. ## EventPipe profiler @@ -181,7 +186,7 @@ The following example: In the project file (`.csproj`), the following properties enable integration with the browser's profiler: -* ``: Enables integration with the profiler in the browser's developer tools. +* ``: The "`browser`" profiler enables integration with the profiler in the browser's developer tools. * ``: Enables diagnostic server. * ``: Enables performance instrumentation for the sampling CPU profiler. * ``: Enables metrics. For more information, see the [`System.Diagnostics.Metrics` namespace](/dotnet/api/system.diagnostics.metrics). From 5fc2d598c482758cfc487caa82f559cd7ddc56fd Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 18 Apr 2025 08:43:01 -0400 Subject: [PATCH 06/28] Updates --- aspnetcore/blazor/performance/profiling.md | 34 ++++++++++++---------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/aspnetcore/blazor/performance/profiling.md b/aspnetcore/blazor/performance/profiling.md index bf8d5cf31c5b..512d8f788ce7 100644 --- a/aspnetcore/blazor/performance/profiling.md +++ b/aspnetcore/blazor/performance/profiling.md @@ -37,14 +37,16 @@ Built-in performance counters are available to track: * [JIT (Just-In-Time) interpolation](https://developer.mozilla.org/docs/Glossary/Just_In_Time_Compilation) * Call specification (":::no-loc text="callspec":::", sequence and timing of function calls) and instrumentation -Enable integration with the browser's developer tools profiler using the `` property in the app's project file (`.csproj`). Include the following additional properties: +Enable integration with the browser's developer tools profiler using the `` property in the app's project file (`.csproj`). Include the additional properties in the following table. -* ``: The "`browser`" profiler enables integration with the profiler in the browser's developer tools. -* ``: Run AOT compilation. Default: `false` -* ``: Run AOT compilation after build. By default, it is run only for publish. Default: `false` -* ``: Set to `false` to prevent stripping the native executable. Default: `true` -* ``: Build with native debug symbols. Default: `true` -* ``: Build the native executable. Default: `false` +Property | Default | Set value to… | Description +--- | :---: | :---: | --- +`` | No value | `browser` | Mono profilers to use. Potential values are "`browser`" and "`log`". To use both, separate the values with a semicolon. The `browser` profiler enables integration with the browser's developer tools profiler. +``| `false` | `true` | Controls AOT compilation. +`` | `false` | `true` | Controls AOT compilation after build. By default, it's run only for publish. +`` | `true` | `false` | Controls stripping the native executable. +`` | `true` | `true` | Controls building with native debug symbols. +`` | `false` | `true` | Controls building the native executable. ```xml @@ -109,7 +111,7 @@ Enable integration with the log profiler using the `` and ` - log; + log true ``` @@ -184,17 +186,19 @@ The following example: * Collects performance counters for 60 seconds. * Collects CPU counters for 60 seconds. -In the project file (`.csproj`), the following properties enable integration with the browser's profiler: +In the project file (`.csproj`), the properties in the following table enable integration with the browser's profiler. -* ``: The "`browser`" profiler enables integration with the profiler in the browser's developer tools. -* ``: Enables diagnostic server. -* ``: Enables performance instrumentation for the sampling CPU profiler. -* ``: Enables metrics. For more information, see the [`System.Diagnostics.Metrics` namespace](/dotnet/api/system.diagnostics.metrics). -* ``: Enables system events. For more information, see [Diagnostics and instrumentation: Observability and telemetry](/dotnet/core/deploying/native-aot/diagnostics#observability-and-telemetry). +Property | Default | Set value to… | Description +--- | :---: | :---: | --- +`` | No value | `browser` | Mono profilers to use. Potential values are "`browser`" and "`log`". To use both, separate the values with a semicolon. The `browser` profiler enables integration with the browser's developer tools profiler. +`` | `false` | `true` | Controls diagnostic server tracing. +`` | `false` | `true` | Controls CPU sampling instrumentation for diagnostic server. +`` | `false` | `true` | Controls `System.Diagnostics.Metrics` support. For more information, see the [`System.Diagnostics.Metrics` namespace](/dotnet/api/system.diagnostics.metrics). +`` | `false`| `true` | Controls `EventPipe` support. For more information, see [Diagnostics and instrumentation: Observability and telemetry](/dotnet/core/deploying/native-aot/diagnostics#observability-and-telemetry). ```xml - browser; + browser true true true From e7f5715cbee9815e6bdf31c68dba606cebae1f16 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 18 Apr 2025 08:52:38 -0400 Subject: [PATCH 07/28] Updates --- aspnetcore/blazor/performance/profiling.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/aspnetcore/blazor/performance/profiling.md b/aspnetcore/blazor/performance/profiling.md index 512d8f788ce7..a6d4b8ff12a1 100644 --- a/aspnetcore/blazor/performance/profiling.md +++ b/aspnetcore/blazor/performance/profiling.md @@ -136,7 +136,7 @@ Invoke `TakeHeapshot` to create a memory heap shot and flush the contents of the [EventPipe](/dotnet/core/diagnostics/eventpipe) is a runtime component used to collect tracing data, similar to [ETW](/windows/win32/etw/event-tracing-portal) and [perf_events](https://wikipedia.org/wiki/Perf_%28Linux%29). * Manual testing - * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find expected calls. + * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected method calls. * [`dotnet-trace`](/dotnet/core/diagnostics/dotnet-trace): Open the `.nettrace` output file in Visual Studio and find the expected method calls. * Web-based testing * Use the JavaScript API to obtain a [promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) of NetTrace (`.nettrace`) bytes. @@ -147,12 +147,12 @@ Built-in performance counters are available to track: * [Ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation) * Code interpolation -* JIT (Just-In-Time) interpolation +* [JIT (Just-In-Time) interpolation](https://developer.mozilla.org/docs/Glossary/Just_In_Time_Compilation) ## GC (Garbage Collector) dumps * Manual testing - * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find expected calls. + * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected classes. * [`dotnet-gcdump` (`collect`/convert` options)](/dotnet/core/diagnostics/dotnet-gcdump): To view the captured GC dump files, see [View the GC dump captured from dotnet-gcdump](/dotnet/core/diagnostics/dotnet-gcdump#view-the-gc-dump-captured-from-dotnet-gcdump). * Web-based testing * Use the JavaScript API to obtain a [promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) of NetTrace (`.nettrace`) bytes. @@ -162,12 +162,12 @@ Built-in performance counters are available to track: ## Counters trace * Manual testing - * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find expected calls. - * [`dotnet-counters collect`](/dotnet/core/diagnostics/dotnet-counters): Open the `.csv`/`.json` output file in Visual Studio and find the expected counters/values. + * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected counters. + * [`dotnet-counters collect`](/dotnet/core/diagnostics/dotnet-counters): Open the `.csv`/`.json` output file in Visual Studio and find the expected counters. * Web-based testing * Use the JavaScript API to obtain a [promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) of NetTrace (`.nettrace`) bytes. * Upload the file via HTTP. - * Parse and validate that the trace contains the expected counters/values. + * Parse and validate that the trace contains the expected counters. ## .NET Core Diagnostics Client Library example @@ -211,8 +211,8 @@ The [`Timing-Allow-Origin` HTTP header](https://developer.mozilla.org/docs/Web/H Browser developer tools console calls in the following example that trigger profiling: * `collectGcDump`: Collect a GC (Garbage Collector) dump. -* `collectPerfCounters(durationSeconds)`: Collect performance counters. -* `collectCpuSamples(durationSeconds)`: Collect performance counters. +* `collectPerfCounters(durationSeconds)`: Collect general performance counters. +* `collectCpuSamples(durationSeconds)`: Collect CPU performance counters. ```javascript globalThis.getDotnetRuntime(0).collectGcDump(); From f7a0f32af97154b7c434ce808692f7ce9c9ca414 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Tue, 29 Apr 2025 11:58:35 -0400 Subject: [PATCH 08/28] Updates --- .../blazor/performance/app-download-size.md | 20 ++- ...filing.md => developer-tools-profiling.md} | 77 ++++-------- .../performance/event-pipe-profiling.md | 119 ++++++++++++++++++ aspnetcore/toc.yml | 6 +- 4 files changed, 159 insertions(+), 63 deletions(-) rename aspnetcore/blazor/performance/{profiling.md => developer-tools-profiling.md} (68%) create mode 100644 aspnetcore/blazor/performance/event-pipe-profiling.md diff --git a/aspnetcore/blazor/performance/app-download-size.md b/aspnetcore/blazor/performance/app-download-size.md index 1a4ecd48c9d7..e5cad963f1ec 100644 --- a/aspnetcore/blazor/performance/app-download-size.md +++ b/aspnetcore/blazor/performance/app-download-size.md @@ -66,15 +66,21 @@ After an app is deployed, verify that the app serves compressed files. Inspect t Blazor WebAssembly's runtime includes the following .NET features that can be disabled for a smaller payload size. -Blazor WebAssembly carries globalization resources required to display values, such as dates and currency, in the user's culture. If the app doesn't require localization, you may [configure the app to support the invariant culture](xref:blazor/globalization-localization#invariant-globalization), which is based on the `en-US` culture. +Blazor WebAssembly carries globalization resources required to display values, such as dates and currency, in the user's culture. If the app doesn't require localization, you may configure the app to [support the invariant culture](xref:blazor/globalization-localization#invariant-globalization), which is based on the `en-US` culture. Apply the `` MSBuild property with a value of `true` in the app's project file (`.csproj`): + +```xml + + true + +``` :::moniker range=">= aspnetcore-8.0" -Adopting [invariant globalization](xref:blazor/globalization-localization#invariant-globalization) only results in using non-localized timezone names. To trim timezone code and data from the app, apply the `` MSBuild property with a value of `true` in the app's project file: +Adopting [invariant globalization](xref:blazor/globalization-localization#invariant-globalization) only results in using non-localized timezone names. To trim timezone code and data from the app, apply the `` MSBuild property with a value of `true` in the app's project file (`.csproj`): ```xml -true + true ``` @@ -89,7 +95,7 @@ A data file is included to make timezone information correct. If the app doesn't ```xml -false + false ``` @@ -101,8 +107,12 @@ Collation information is included to make APIs such as -false + false ``` :::moniker-end + +## Additional resources + +[Configuring and hosting .NET WebAssembly applications](https://github.com/dotnet/runtime/blob/main/src/mono/wasm/features.md) diff --git a/aspnetcore/blazor/performance/profiling.md b/aspnetcore/blazor/performance/developer-tools-profiling.md similarity index 68% rename from aspnetcore/blazor/performance/profiling.md rename to aspnetcore/blazor/performance/developer-tools-profiling.md index a6d4b8ff12a1..a20a3345167b 100644 --- a/aspnetcore/blazor/performance/profiling.md +++ b/aspnetcore/blazor/performance/developer-tools-profiling.md @@ -1,14 +1,14 @@ --- -title: ASP.NET Core Blazor WebAssembly performance profiling and diagnostic counters +title: ASP.NET Core Blazor WebAssembly developer tools performance profiling and diagnostic counters author: guardrex -description: Learn about performance profiling and diagnostic counters in ASP.NET Core Blazor WebAssembly apps. +description: Learn about developer tools performance profiling and diagnostic counters in ASP.NET Core Blazor WebAssembly apps. monikerRange: '>= aspnetcore-10.0' ms.author: riande ms.custom: mvc -ms.date: 04/16/2025 -uid: blazor/performance/profiling +ms.date: 04/29/2025 +uid: blazor/performance/developer-tools-profiling --- -# ASP.NET Core Blazor WebAssembly performance profiling and diagnostic counters +# ASP.NET Core Blazor WebAssembly developer tools performance profiling and diagnostic counters -This article describes performance profiling tools and diagnostic counters for Blazor WebAssembly apps. +This article describes developer tools performance profiling tools and diagnostic counters for Blazor WebAssembly apps. ## Prerequisite @@ -34,10 +34,9 @@ Built-in performance counters are available to track: * [Ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation) * Code interpolation -* [JIT (Just-In-Time) interpolation](https://developer.mozilla.org/docs/Glossary/Just_In_Time_Compilation) * Call specification (":::no-loc text="callspec":::", sequence and timing of function calls) and instrumentation -Enable integration with the browser's developer tools profiler using the `` property in the app's project file (`.csproj`). Include the additional properties in the following table. +The MSBuild properties in the following table enable profiler integration. Property | Default | Set value to… | Description --- | :---: | :---: | --- @@ -48,8 +47,12 @@ Property | Default | Set value to… | Description `` | `true` | `true` | Controls building with native debug symbols. `` | `false` | `true` | Controls building the native executable. +Enabling profilers has negative size and performance impact, so don't publish an app for production with profilers enabled. In the following example, a condition is set on a property group section that only enables profiling when the app is built with `/p:ProfilingEnabled=true` (.NET CLI) or `true` in a Visual Studio publish profile. + +In the app's project file (`.csproj`): + ```xml - + browser; true true @@ -59,7 +62,15 @@ Property | Default | Set value to… | Description ``` -Add Blazor start configuration in `wwwroot/index.html`, using the [fingerprinted location of the Blazor WebAssembly script](xref:blazor/fundamentals/static-files#fingerprint-client-side-static-assets-in-standalone-blazor-webassembly-apps). In the following example, the `sampleIntervalMs` option is set to 10 seconds, which is the default setting if `sampleIntervalMs` isn't specified: +Setting WebAssembly profilers with `browser;` doesn't require AOT (``/`` set to `false` or removed from the preceding properity group). + +The browser developer tools profiler can be used with AOT (``/`` set to `true`) and without WebAssembly profilers (`browser;` removed from the preceding property group). + +To see AOT method names in the developer tools console, install [DWARF chrome extension](https://chromewebstore.google.com/detail/cc++-devtools-support-dwa/pdcpmagijalfljmkmjngeonclgbbannb). + +## Set the sample interval + +To set the sample interval, add the following Blazor start configuration in `wwwroot/index.html` and add `autostart="false"` to the Blazor ` ``` -## Log profiling for memory troubleshooting - -Enable integration with the log profiler using the `` and `` properties in the app's project file (`.csproj`): - -```xml - - log - true - -``` - -To trigger a heap shot, add the following, where the `{APP NAMESPACE}` placeholder is the app's namespace: - -```csharp -namespace {APP NAMESPACE}; - -public class Profiling -{ - [JSExport] - [MethodImpl(MethodImplOptions.NoInlining)] - public static void TakeHeapshot() { } -} -``` - -Invoke `TakeHeapshot` to create a memory heap shot and flush the contents of the profile to the file system. Download the resulting `.mpld` file to analyze the data. - -## EventPipe profiler - -[EventPipe](/dotnet/core/diagnostics/eventpipe) is a runtime component used to collect tracing data, similar to [ETW](/windows/win32/etw/event-tracing-portal) and [perf_events](https://wikipedia.org/wiki/Perf_%28Linux%29). - -* Manual testing - * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected method calls. - * [`dotnet-trace`](/dotnet/core/diagnostics/dotnet-trace): Open the `.nettrace` output file in Visual Studio and find the expected method calls. -* Web-based testing - * Use the JavaScript API to obtain a [promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) of NetTrace (`.nettrace`) bytes. - * Upload the file via HTTP. - * Parse and validate that the trace contains the expected method calls. - -Built-in performance counters are available to track: - -* [Ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation) -* Code interpolation -* [JIT (Just-In-Time) interpolation](https://developer.mozilla.org/docs/Glossary/Just_In_Time_Compilation) - ## GC (Garbage Collector) dumps * Manual testing * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected classes. * [`dotnet-gcdump` (`collect`/convert` options)](/dotnet/core/diagnostics/dotnet-gcdump): To view the captured GC dump files, see [View the GC dump captured from dotnet-gcdump](/dotnet/core/diagnostics/dotnet-gcdump#view-the-gc-dump-captured-from-dotnet-gcdump). * Web-based testing - * Use the JavaScript API to obtain a [promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) of NetTrace (`.nettrace`) bytes. * Upload the file via HTTP. * Parse and validate that the trace contains the expected classes. @@ -165,7 +131,6 @@ Built-in performance counters are available to track: * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected counters. * [`dotnet-counters collect`](/dotnet/core/diagnostics/dotnet-counters): Open the `.csv`/`.json` output file in Visual Studio and find the expected counters. * Web-based testing - * Use the JavaScript API to obtain a [promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise) of NetTrace (`.nettrace`) bytes. * Upload the file via HTTP. * Parse and validate that the trace contains the expected counters. diff --git a/aspnetcore/blazor/performance/event-pipe-profiling.md b/aspnetcore/blazor/performance/event-pipe-profiling.md new file mode 100644 index 000000000000..90506951a1f0 --- /dev/null +++ b/aspnetcore/blazor/performance/event-pipe-profiling.md @@ -0,0 +1,119 @@ +--- +title: ASP.NET Core Blazor WebAssembly Event Pipe performance profiling and diagnostic counters +author: guardrex +description: Learn about Event Pipe performance profiling and diagnostic counters in ASP.NET Core Blazor WebAssembly apps. +monikerRange: '>= aspnetcore-10.0' +ms.author: riande +ms.custom: mvc +ms.date: 04/29/2025 +uid: blazor/performance/event-pipe-profiling +--- +# ASP.NET Core Blazor WebAssembly Event Pipe performance profiling and diagnostic counters + + + +This article describes Event Pipe performance profiling tools and diagnostic counters for Blazor WebAssembly apps. + +## Prerequisite + +Install the [.NET WebAssembly build tools](xref:blazor/tooling/webassembly#net-webassembly-build-tools): + +```dotnetcli +dotnet workload install wasm-tools +``` + +## EventPipe profiler + +[EventPipe](/dotnet/core/diagnostics/eventpipe) is a runtime component used to collect tracing data, similar to [ETW](/windows/win32/etw/event-tracing-portal) and [perf_events](https://wikipedia.org/wiki/Perf_%28Linux%29). + +* Manual testing + * Browser developer tools: Download the `.nettrace` output file, open the file in Visual Studio, and find the expected method calls. + * [`dotnet-trace`](/dotnet/core/diagnostics/dotnet-trace): Open the `.nettrace` output file in Visual Studio and find the expected method calls. +* Web-based testing + * Upload the file via HTTP. + * Parse and validate that the trace contains the expected method calls. + +Built-in performance counters are available to track: + +* [Ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation) +* Code interpolation + +## GC (Garbage Collector) dumps + +* Manual testing + * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected classes. + * [`dotnet-gcdump` (`collect`/convert` options)](/dotnet/core/diagnostics/dotnet-gcdump): To view the captured GC dump files, see [View the GC dump captured from dotnet-gcdump](/dotnet/core/diagnostics/dotnet-gcdump#view-the-gc-dump-captured-from-dotnet-gcdump). +* Web-based testing + * Upload the file via HTTP. + * Parse and validate that the trace contains the expected classes. + +## Counters trace + +* Manual testing + * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected counters. + * [`dotnet-counters collect`](/dotnet/core/diagnostics/dotnet-counters): Open the `.csv`/`.json` output file in Visual Studio and find the expected counters. +* Web-based testing + * Upload the file via HTTP. + * Parse and validate that the trace contains the expected counters. + +## .NET Core Diagnostics Client Library example + +Parse and validate NetTrace (`.nettrace`) messages using the .NET Core Diagnostics Client Library: + +* [`dotnet/diagnostics` GitHub repository](https://github.com/dotnet/diagnostics) +* [`Microsoft.Diagnostics.NETCore.Client` NuGet package](https://www.nuget.org/packages/Microsoft.Diagnostics.NETCore.Client) + +For more information, see the [.NET Core diagnostics documentation](/dotnet/core/diagnostics/) and the [`IpcMessage` API (reference source)](https://github.com/dotnet/diagnostics/blob/main/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/IpcMessage.cs). + +[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] + +The following example: + +* Collects a GC (Garbage Collector) dump of the live .NET process. +* Collects performance counters for 60 seconds. +* Collects CPU counters for 60 seconds. + +The MSBuild properties in the following table enable profiler integration. + +Property | Default | Set value to… | Description +--- | :---: | :---: | --- +`` | `false` | `true` | Controls diagnostic server tracing. +`` | `false` | `true` | Controls CPU sampling instrumentation for diagnostic server. Not necessary for memory dump or counters. **Makes the app execute slower. Only set this to `true` for performance profiling. +`` | `false` | `true` | Controls `System.Diagnostics.Metrics` support. For more information, see the [`System.Diagnostics.Metrics` namespace](/dotnet/api/system.diagnostics.metrics). +`` | `false`| `true` | Controls `EventPipe` support. For more information, see [Diagnostics and instrumentation: Observability and telemetry](/dotnet/core/deploying/native-aot/diagnostics#observability-and-telemetry). + +Enabling profilers has negative size and performance impact, so don't publish an app for production with profilers enabled. In the following example, a condition is set on a property group section that only enables profiling when the app is built with `/p:ProfilingEnabled=true` (.NET CLI) or `true` in a Visual Studio publish profile. + +In the app's project file (`.csproj`): + +```xml + + true + true + true + true + +``` + +The [`Timing-Allow-Origin` HTTP header](https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/Timing-Allow-Origin) allows for more precise time measurements. + +Browser developer tools console calls in the following example that trigger profiling: + +* `collectGcDump`: Collect a GC (Garbage Collector) dump. +* `collectPerfCounters(durationSeconds)`: Collect general performance counters. +* `collectCpuSamples(durationSeconds)`: Collect CPU performance counters. + +```javascript +globalThis.getDotnetRuntime(0).collectGcDump(); +globalThis.getDotnetRuntime(0).collectPerfCounters({durationSeconds: 60}); +globalThis.getDotnetRuntime(0).collectCpuSamples({durationSeconds: 60}); +``` + +## Additional resources + +* [What diagnostic tools are available in .NET Core?](/dotnet/core/diagnostics/) +* [.NET diagnostic tools](/dotnet/core/diagnostics/tools-overview) diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index e0ff370c29ca..6043e11c1969 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -660,8 +660,10 @@ items: uid: blazor/performance/app-download-size - name: JavaScript interop uid: blazor/performance/js-interop - - name: WebAssembly profiling - uid: blazor/performance/profiling + - name: WebAssembly developer tools profiling + uid: blazor/performance/developer-tools-profiling + - name: WebAssembly Event Pipe profiling + uid: blazor/performance/event-pipe-profiling - name: Test components uid: blazor/test - name: Progressive Web Applications From 9875831cb48556d4a2e4279fe60198f9415ce623 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Tue, 29 Apr 2025 12:01:41 -0400 Subject: [PATCH 09/28] Updates --- aspnetcore/release-notes/aspnetcore-10/includes/blazor.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md index 616371bb9344..effe4afd74dd 100644 --- a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md +++ b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md @@ -348,6 +348,9 @@ For more information, see the following sections of the *Call JavaScript functio ### Blazor WebAssembly performance profiling and diagnostic counters -New performance profiling and diagnostic counters are available for Blazor WebAssembly apps. For more information, see . +New performance profiling and diagnostic counters are available for Blazor WebAssembly apps. For more information, see the following articles: + +* +* --> From 4d15ead5ac83846e11d40fb0d770ce3eb21c7d72 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Tue, 29 Apr 2025 12:04:44 -0400 Subject: [PATCH 10/28] Updates --- aspnetcore/performance/diagnostic-tools.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/performance/diagnostic-tools.md b/aspnetcore/performance/diagnostic-tools.md index 2a73661e62a7..ebf18a394860 100644 --- a/aspnetcore/performance/diagnostic-tools.md +++ b/aspnetcore/performance/diagnostic-tools.md @@ -13,7 +13,7 @@ By [Mike Rousos](https://github.com/mjrousos) This article lists tools for diagnosing performance issues in ASP.NET Core. -For information on Blazor WebAssembly performance diagnostic tools and counters, see . +For information on Blazor WebAssembly performance diagnostic tools and counters, see and . ## Visual Studio Diagnostic Tools From fcb5be4d631bbeb5327c15ad99f90bf0ea3a46d6 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 30 Apr 2025 11:02:22 -0400 Subject: [PATCH 11/28] Updates --- .../blazor/performance/app-download-size.md | 2 +- ...d => browser-developer-tools-profiling.md} | 28 +++++++++------- .../performance/event-pipe-profiling.md | 32 +++++++++++-------- aspnetcore/performance/diagnostic-tools.md | 2 +- .../aspnetcore-10/includes/blazor.md | 4 +-- aspnetcore/toc.yml | 8 ++--- 6 files changed, 43 insertions(+), 33 deletions(-) rename aspnetcore/blazor/performance/{developer-tools-profiling.md => browser-developer-tools-profiling.md} (87%) diff --git a/aspnetcore/blazor/performance/app-download-size.md b/aspnetcore/blazor/performance/app-download-size.md index e5cad963f1ec..e210b6127811 100644 --- a/aspnetcore/blazor/performance/app-download-size.md +++ b/aspnetcore/blazor/performance/app-download-size.md @@ -5,7 +5,7 @@ description: Tips for reducing app download size in ASP.NET Core Blazor apps and monikerRange: '>= aspnetcore-3.1' ms.author: riande ms.custom: mvc -ms.date: 04/16/2025 +ms.date: 04/30/2025 uid: blazor/performance/app-download-size --- # ASP.NET Core Blazor app download size performance best practices diff --git a/aspnetcore/blazor/performance/developer-tools-profiling.md b/aspnetcore/blazor/performance/browser-developer-tools-profiling.md similarity index 87% rename from aspnetcore/blazor/performance/developer-tools-profiling.md rename to aspnetcore/blazor/performance/browser-developer-tools-profiling.md index a20a3345167b..9f42d1f50896 100644 --- a/aspnetcore/blazor/performance/developer-tools-profiling.md +++ b/aspnetcore/blazor/performance/browser-developer-tools-profiling.md @@ -1,14 +1,14 @@ --- -title: ASP.NET Core Blazor WebAssembly developer tools performance profiling and diagnostic counters +title: ASP.NET Core Blazor WebAssembly browser developer tools diagnostic profiling author: guardrex -description: Learn about developer tools performance profiling and diagnostic counters in ASP.NET Core Blazor WebAssembly apps. +description: Learn about browser developer tools diagnostic profiling for ASP.NET Core Blazor WebAssembly apps. monikerRange: '>= aspnetcore-10.0' ms.author: riande ms.custom: mvc -ms.date: 04/29/2025 -uid: blazor/performance/developer-tools-profiling +ms.date: 04/30/2025 +uid: blazor/performance/browser-developer-tools --- -# ASP.NET Core Blazor WebAssembly developer tools performance profiling and diagnostic counters +# ASP.NET Core Blazor WebAssembly browser developer tools diagnostic profiling -This article describes developer tools performance profiling tools and diagnostic counters for Blazor WebAssembly apps. +This article describes browser developer tools diagnostic profiling tools for Blazor WebAssembly apps. ## Prerequisite @@ -28,9 +28,9 @@ dotnet workload install wasm-tools ## Browser developer tools -App code can be manually profiled using the performance profiler in a browser's developer tools console. +App code can be manually profiled using the diagnostic profiler in a browser's developer tools console. -Built-in performance counters are available to track: +Built-in diagnostic counters are available to track: * [Ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation) * Code interpolation @@ -47,21 +47,25 @@ Property | Default | Set value to… | Description `` | `true` | `true` | Controls building with native debug symbols. `` | `false` | `true` | Controls building the native executable. -Enabling profilers has negative size and performance impact, so don't publish an app for production with profilers enabled. In the following example, a condition is set on a property group section that only enables profiling when the app is built with `/p:ProfilingEnabled=true` (.NET CLI) or `true` in a Visual Studio publish profile. +Enabling profilers has negative size and performance impact, so don't publish an app for production with profilers enabled. In the following example, a condition is set on a property group section that only enables profiling when the app is built with `/p:BlazorSampleProfilingEnabled=true` (.NET CLI) or `true` in a Visual Studio publish profile, where "`BlazorSampleProfilingEnabled`" is a custom symbol name that you choose and doesn't conflict with other symbol names. In the app's project file (`.csproj`): ```xml - + browser; - true - true false true true ``` +Alternatively, enable features when the app is built with the .NET CLI. The following options passed to the `dotnet build` command mirror the preceding MS Build property configuration: + +```dotnetcli +/p:WasmProfilers=browser /p:WasmNativeStrip=false /p:WasmNativeDebugSymbols=true /p:WasmBuildNative=true +``` + Setting WebAssembly profilers with `browser;` doesn't require AOT (``/`` set to `false` or removed from the preceding properity group). The browser developer tools profiler can be used with AOT (``/`` set to `true`) and without WebAssembly profilers (`browser;` removed from the preceding property group). diff --git a/aspnetcore/blazor/performance/event-pipe-profiling.md b/aspnetcore/blazor/performance/event-pipe-profiling.md index 90506951a1f0..9666e6b9563d 100644 --- a/aspnetcore/blazor/performance/event-pipe-profiling.md +++ b/aspnetcore/blazor/performance/event-pipe-profiling.md @@ -1,14 +1,14 @@ --- -title: ASP.NET Core Blazor WebAssembly Event Pipe performance profiling and diagnostic counters +title: ASP.NET Core Blazor WebAssembly Event Pipe diagnostic profiling author: guardrex -description: Learn about Event Pipe performance profiling and diagnostic counters in ASP.NET Core Blazor WebAssembly apps. +description: Learn about Event Pipe diagnostic profiling, counters, and how to get a Garbage Collector heap dump in ASP.NET Core Blazor WebAssembly apps. monikerRange: '>= aspnetcore-10.0' ms.author: riande ms.custom: mvc -ms.date: 04/29/2025 -uid: blazor/performance/event-pipe-profiling +ms.date: 04/30/2025 +uid: blazor/performance/event-pipe --- -# ASP.NET Core Blazor WebAssembly Event Pipe performance profiling and diagnostic counters +# ASP.NET Core Blazor WebAssembly Event Pipe diagnostic profiling -This article describes Event Pipe performance profiling tools and diagnostic counters for Blazor WebAssembly apps. +This article describes Event Pipe diagnostic profiling tools, counters, and how to get a Garbage Collector heap dump in Blazor WebAssembly apps. ## Prerequisite @@ -37,7 +37,7 @@ dotnet workload install wasm-tools * Upload the file via HTTP. * Parse and validate that the trace contains the expected method calls. -Built-in performance counters are available to track: +Built-in diagnostic counters are available to track: * [Ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation) * Code interpolation @@ -74,7 +74,7 @@ For more information, see the [.NET Core diagnostics documentation](/dotnet/core The following example: * Collects a GC (Garbage Collector) dump of the live .NET process. -* Collects performance counters for 60 seconds. +* Collects diagnostic counters for 60 seconds. * Collects CPU counters for 60 seconds. The MSBuild properties in the following table enable profiler integration. @@ -82,16 +82,16 @@ The MSBuild properties in the following table enable profiler integration. Property | Default | Set value to… | Description --- | :---: | :---: | --- `` | `false` | `true` | Controls diagnostic server tracing. -`` | `false` | `true` | Controls CPU sampling instrumentation for diagnostic server. Not necessary for memory dump or counters. **Makes the app execute slower. Only set this to `true` for performance profiling. +`` | `false` | `true` | Controls CPU sampling instrumentation for diagnostic server. Not necessary for memory dump or counters. **Makes the app execute slower. Only set this to `true` for performance profiling.** `` | `false` | `true` | Controls `System.Diagnostics.Metrics` support. For more information, see the [`System.Diagnostics.Metrics` namespace](/dotnet/api/system.diagnostics.metrics). `` | `false`| `true` | Controls `EventPipe` support. For more information, see [Diagnostics and instrumentation: Observability and telemetry](/dotnet/core/deploying/native-aot/diagnostics#observability-and-telemetry). -Enabling profilers has negative size and performance impact, so don't publish an app for production with profilers enabled. In the following example, a condition is set on a property group section that only enables profiling when the app is built with `/p:ProfilingEnabled=true` (.NET CLI) or `true` in a Visual Studio publish profile. +Enabling profilers has negative size and performance impact, so don't publish an app for production with profilers enabled. In the following example, a condition is set on a property group section that only enables profiling when the app is built with `/p:BlazorSampleProfilingEnabled=true` (.NET CLI) or `true` in a Visual Studio publish profile, where "`BlazorSampleProfilingEnabled`" is a custom symbol name that you choose and doesn't conflict with other symbol names. In the app's project file (`.csproj`): ```xml - + true true true @@ -99,13 +99,19 @@ In the app's project file (`.csproj`): ``` +Alternatively, enable features when the app is built with the .NET CLI. The following options passed to the `dotnet build` command mirror the preceding MS Build property configuration: + +```dotnetcli +/p:WasmPerfTracing=true /p:WasmPerfInstrumentation=true /p:MetricsSupport=true /p:EventSourceSupport=true +``` + The [`Timing-Allow-Origin` HTTP header](https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/Timing-Allow-Origin) allows for more precise time measurements. Browser developer tools console calls in the following example that trigger profiling: * `collectGcDump`: Collect a GC (Garbage Collector) dump. -* `collectPerfCounters(durationSeconds)`: Collect general performance counters. -* `collectCpuSamples(durationSeconds)`: Collect CPU performance counters. +* `collectPerfCounters(durationSeconds)`: Collect general diagnostic counters. +* `collectCpuSamples(durationSeconds)`: Collect CPU diagnostic counters. ```javascript globalThis.getDotnetRuntime(0).collectGcDump(); diff --git a/aspnetcore/performance/diagnostic-tools.md b/aspnetcore/performance/diagnostic-tools.md index ebf18a394860..e7c7fb979ecc 100644 --- a/aspnetcore/performance/diagnostic-tools.md +++ b/aspnetcore/performance/diagnostic-tools.md @@ -13,7 +13,7 @@ By [Mike Rousos](https://github.com/mjrousos) This article lists tools for diagnosing performance issues in ASP.NET Core. -For information on Blazor WebAssembly performance diagnostic tools and counters, see and . +For information on Blazor WebAssembly performance diagnostic tools and counters, see and . ## Visual Studio Diagnostic Tools diff --git a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md index effe4afd74dd..9471598d8b6b 100644 --- a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md +++ b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md @@ -350,7 +350,7 @@ For more information, see the following sections of the *Call JavaScript functio New performance profiling and diagnostic counters are available for Blazor WebAssembly apps. For more information, see the following articles: -* -* +* +* --> diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index 6043e11c1969..f11a75d91896 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -660,10 +660,10 @@ items: uid: blazor/performance/app-download-size - name: JavaScript interop uid: blazor/performance/js-interop - - name: WebAssembly developer tools profiling - uid: blazor/performance/developer-tools-profiling - - name: WebAssembly Event Pipe profiling - uid: blazor/performance/event-pipe-profiling + - name: WebAssembly browser developer tools diagnostics + uid: blazor/performance/browser-developer-tools + - name: WebAssembly Event Pipe diagnostics + uid: blazor/performance/event-pipe - name: Test components uid: blazor/test - name: Progressive Web Applications From de64081562c9d62fa99b9371ec563864cd85a112 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 30 Apr 2025 11:03:53 -0400 Subject: [PATCH 12/28] Updates --- .../blazor/performance/browser-developer-tools-profiling.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aspnetcore/blazor/performance/browser-developer-tools-profiling.md b/aspnetcore/blazor/performance/browser-developer-tools-profiling.md index 9f42d1f50896..650e8ddbe114 100644 --- a/aspnetcore/blazor/performance/browser-developer-tools-profiling.md +++ b/aspnetcore/blazor/performance/browser-developer-tools-profiling.md @@ -1,7 +1,7 @@ --- title: ASP.NET Core Blazor WebAssembly browser developer tools diagnostic profiling author: guardrex -description: Learn about browser developer tools diagnostic profiling for ASP.NET Core Blazor WebAssembly apps. +description: Learn about browser developer tools diagnostic profiling in ASP.NET Core Blazor WebAssembly apps. monikerRange: '>= aspnetcore-10.0' ms.author: riande ms.custom: mvc @@ -16,7 +16,7 @@ uid: blazor/performance/browser-developer-tools --> -This article describes browser developer tools diagnostic profiling tools for Blazor WebAssembly apps. +This article describes browser developer tools diagnostic profiling tools in Blazor WebAssembly apps. ## Prerequisite From 0fa510aaa0c46c103514f03297c326476dd80564 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 30 Apr 2025 11:16:29 -0400 Subject: [PATCH 13/28] Updates --- ...sembly-browser-developer-tools-diagnostics.md} | 15 +++++++-------- ...g.md => webassembly-event-pipe-diagnostics.md} | 10 +++++----- aspnetcore/performance/diagnostic-tools.md | 2 +- .../aspnetcore-10/includes/blazor.md | 4 ++-- aspnetcore/toc.yml | 4 ++-- 5 files changed, 17 insertions(+), 18 deletions(-) rename aspnetcore/blazor/performance/{browser-developer-tools-profiling.md => webassembly-browser-developer-tools-diagnostics.md} (95%) rename aspnetcore/blazor/performance/{event-pipe-profiling.md => webassembly-event-pipe-diagnostics.md} (92%) diff --git a/aspnetcore/blazor/performance/browser-developer-tools-profiling.md b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md similarity index 95% rename from aspnetcore/blazor/performance/browser-developer-tools-profiling.md rename to aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md index 650e8ddbe114..e8a57b304b0e 100644 --- a/aspnetcore/blazor/performance/browser-developer-tools-profiling.md +++ b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md @@ -1,14 +1,14 @@ --- -title: ASP.NET Core Blazor WebAssembly browser developer tools diagnostic profiling +title: ASP.NET Core Blazor WebAssembly browser developer tools diagnostics author: guardrex -description: Learn about browser developer tools diagnostic profiling in ASP.NET Core Blazor WebAssembly apps. +description: Learn about browser developer tools diagnostics in ASP.NET Core Blazor WebAssembly apps. monikerRange: '>= aspnetcore-10.0' ms.author: riande ms.custom: mvc ms.date: 04/30/2025 -uid: blazor/performance/browser-developer-tools +uid: blazor/performance/webassembly-browser-developer-tools --- -# ASP.NET Core Blazor WebAssembly browser developer tools diagnostic profiling +# ASP.NET Core Blazor WebAssembly browser developer tools diagnostics -This article describes browser developer tools diagnostic profiling tools in Blazor WebAssembly apps. +This article describes browser developer tools diagnostic tools in Blazor WebAssembly apps. ## Prerequisite @@ -56,17 +56,16 @@ In the app's project file (`.csproj`): browser; false true - true ``` Alternatively, enable features when the app is built with the .NET CLI. The following options passed to the `dotnet build` command mirror the preceding MS Build property configuration: ```dotnetcli -/p:WasmProfilers=browser /p:WasmNativeStrip=false /p:WasmNativeDebugSymbols=true /p:WasmBuildNative=true +/p:WasmProfilers=browser /p:WasmNativeStrip=false /p:WasmNativeDebugSymbols=true ``` -Setting WebAssembly profilers with `browser;` doesn't require AOT (``/`` set to `false` or removed from the preceding properity group). +Setting WebAssembly profilers with `browser;` doesn't require AOT (``/`` set to `false` or removed from the preceding property group). The browser developer tools profiler can be used with AOT (``/`` set to `true`) and without WebAssembly profilers (`browser;` removed from the preceding property group). diff --git a/aspnetcore/blazor/performance/event-pipe-profiling.md b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md similarity index 92% rename from aspnetcore/blazor/performance/event-pipe-profiling.md rename to aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md index 9666e6b9563d..2fe75acef97c 100644 --- a/aspnetcore/blazor/performance/event-pipe-profiling.md +++ b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md @@ -1,14 +1,14 @@ --- -title: ASP.NET Core Blazor WebAssembly Event Pipe diagnostic profiling +title: ASP.NET Core Blazor WebAssembly Event Pipe diagnostics author: guardrex -description: Learn about Event Pipe diagnostic profiling, counters, and how to get a Garbage Collector heap dump in ASP.NET Core Blazor WebAssembly apps. +description: Learn about Event Pipe diagnostics and how to get a Garbage Collector heap dump in ASP.NET Core Blazor WebAssembly apps. monikerRange: '>= aspnetcore-10.0' ms.author: riande ms.custom: mvc ms.date: 04/30/2025 -uid: blazor/performance/event-pipe +uid: blazor/performance/webassembly-event-pipe --- -# ASP.NET Core Blazor WebAssembly Event Pipe diagnostic profiling +# ASP.NET Core Blazor WebAssembly Event Pipe diagnostics -This article describes Event Pipe diagnostic profiling tools, counters, and how to get a Garbage Collector heap dump in Blazor WebAssembly apps. +This article describes Event Pipe diagnostic tools, counters, and how to get a Garbage Collector heap dump in Blazor WebAssembly apps. ## Prerequisite diff --git a/aspnetcore/performance/diagnostic-tools.md b/aspnetcore/performance/diagnostic-tools.md index e7c7fb979ecc..8f317d47ec98 100644 --- a/aspnetcore/performance/diagnostic-tools.md +++ b/aspnetcore/performance/diagnostic-tools.md @@ -13,7 +13,7 @@ By [Mike Rousos](https://github.com/mjrousos) This article lists tools for diagnosing performance issues in ASP.NET Core. -For information on Blazor WebAssembly performance diagnostic tools and counters, see and . +For information on Blazor WebAssembly performance diagnostic tools and counters, see and . ## Visual Studio Diagnostic Tools diff --git a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md index 9471598d8b6b..709bb77b3b3b 100644 --- a/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md +++ b/aspnetcore/release-notes/aspnetcore-10/includes/blazor.md @@ -350,7 +350,7 @@ For more information, see the following sections of the *Call JavaScript functio New performance profiling and diagnostic counters are available for Blazor WebAssembly apps. For more information, see the following articles: -* -* +* +* --> diff --git a/aspnetcore/toc.yml b/aspnetcore/toc.yml index f11a75d91896..d97cf7d16b4d 100644 --- a/aspnetcore/toc.yml +++ b/aspnetcore/toc.yml @@ -661,9 +661,9 @@ items: - name: JavaScript interop uid: blazor/performance/js-interop - name: WebAssembly browser developer tools diagnostics - uid: blazor/performance/browser-developer-tools + uid: blazor/performance/webassembly-browser-developer-tools - name: WebAssembly Event Pipe diagnostics - uid: blazor/performance/event-pipe + uid: blazor/performance/webassembly-event-pipe - name: Test components uid: blazor/test - name: Progressive Web Applications From 235427cb5082456d58fde9b9192419599762e9b7 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 30 Apr 2025 11:31:14 -0400 Subject: [PATCH 14/28] Updates --- .../webassembly-browser-developer-tools-diagnostics.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md index e8a57b304b0e..35b63488a360 100644 --- a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md @@ -73,7 +73,15 @@ To see AOT method names in the developer tools console, install [DWARF chrome ex ## Set the sample interval -To set the sample interval, add the following Blazor start configuration in `wwwroot/index.html` and add `autostart="false"` to the Blazor ` - -``` - ## Call specification (:::no-loc text="callspec":::) If you want to filter profiled methods, you can use call specification (:::no-loc text="callspec":::). For more information, see [Trace MonoVM profiler events during startup](https://github.com/dotnet/runtime/blob/main/docs/design/mono/diagnostics-tracing.md#trace-monovm-profiler-events-during-startup). @@ -127,24 +105,6 @@ Alternatively, configure `callSpec` in `browserProfilerOptions`. Replace the `{A ``` -## GC (Garbage Collector) dumps - -* Manual testing - * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected classes. - * [`dotnet-gcdump` (`collect`/convert` options)](/dotnet/core/diagnostics/dotnet-gcdump): To view the captured GC dump files, see [View the GC dump captured from dotnet-gcdump](/dotnet/core/diagnostics/dotnet-gcdump#view-the-gc-dump-captured-from-dotnet-gcdump). -* Web-based testing - * Upload the file via HTTP. - * Parse and validate that the trace contains the expected classes. - -## Counters trace - -* Manual testing - * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected counters. - * [`dotnet-counters collect`](/dotnet/core/diagnostics/dotnet-counters): Open the `.csv`/`.json` output file in Visual Studio and find the expected counters. -* Web-based testing - * Upload the file via HTTP. - * Parse and validate that the trace contains the expected counters. - ## .NET Core Diagnostics Client Library example Parse and validate NetTrace (`.nettrace`) messages using the .NET Core Diagnostics Client Library: @@ -158,7 +118,6 @@ For more information, see the [.NET Core diagnostics documentation](/dotnet/core The following example: -* Collects a GC (Garbage Collector) dump of the live .NET process. * Collects performance counters for 60 seconds. * Collects CPU counters for 60 seconds. diff --git a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md index 2fe75acef97c..123267cf54b7 100644 --- a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md @@ -40,7 +40,6 @@ dotnet workload install wasm-tools Built-in diagnostic counters are available to track: * [Ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation) -* Code interpolation ## GC (Garbage Collector) dumps From 17c049c47677d19e53841e085faedf1e74abd741 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 30 Apr 2025 12:29:12 -0400 Subject: [PATCH 18/28] Updates --- ...sembly-browser-developer-tools-diagnostics.md | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md index 1857a0600a29..6e4a14fba866 100644 --- a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md @@ -169,33 +169,17 @@ Property | Default | Set value to… | Description `` | No value | `browser` | Mono profilers to use. Potential values are "`browser`" and "`log`". To use both, separate the values with a semicolon. The `browser` profiler enables integration with the browser's developer tools profiler. `` | `false` | `true` | Controls diagnostic server tracing. `` | `false` | `true` | Controls CPU sampling instrumentation for diagnostic server. -`` | `false` | `true` | Controls `System.Diagnostics.Metrics` support. For more information, see the [`System.Diagnostics.Metrics` namespace](/dotnet/api/system.diagnostics.metrics). -`` | `false`| `true` | Controls `EventPipe` support. For more information, see [Diagnostics and instrumentation: Observability and telemetry](/dotnet/core/deploying/native-aot/diagnostics#observability-and-telemetry). ```xml browser true true - true - true ``` The [`Timing-Allow-Origin` HTTP header](https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/Timing-Allow-Origin) allows for more precise time measurements. -Browser developer tools console calls in the following example that trigger profiling: - -* `collectGcDump`: Collect a GC (Garbage Collector) dump. -* `collectPerfCounters(durationSeconds)`: Collect general performance counters. -* `collectCpuSamples(durationSeconds)`: Collect CPU performance counters. - -```javascript -globalThis.getDotnetRuntime(0).collectGcDump(); -globalThis.getDotnetRuntime(0).collectPerfCounters({durationSeconds: 60}); -globalThis.getDotnetRuntime(0).collectCpuSamples({durationSeconds: 60}); -``` - ## Additional resources * [What diagnostic tools are available in .NET Core?](/dotnet/core/diagnostics/) From a40c1a58058e86edfa3c7b44240c88f17b96f12c Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 30 Apr 2025 12:32:03 -0400 Subject: [PATCH 19/28] Updates --- .../blazor/performance/webassembly-event-pipe-diagnostics.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md index 123267cf54b7..dc43b5cc6752 100644 --- a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md @@ -37,9 +37,7 @@ dotnet workload install wasm-tools * Upload the file via HTTP. * Parse and validate that the trace contains the expected method calls. -Built-in diagnostic counters are available to track: - -* [Ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation) +Built-in diagnostic counters are available to track [Ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation). ## GC (Garbage Collector) dumps From 45c2d58fce6666df1d12bb5b2b062d47675e91e6 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 30 Apr 2025 12:50:01 -0400 Subject: [PATCH 20/28] Updates --- ...bly-browser-developer-tools-diagnostics.md | 20 ---------- .../webassembly-event-pipe-diagnostics.md | 40 ++++++++++--------- 2 files changed, 21 insertions(+), 39 deletions(-) diff --git a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md index 5f914cafb443..9fcf827f22d5 100644 --- a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md @@ -87,24 +87,6 @@ Add `callspec` to the `browser` WebAssembly profiler in the `` el browser:callspec=N:{APP NAMESPACE}; ``` -Alternatively, configure `callSpec` in `browserProfilerOptions`. Replace the `{APP NAMESPACE}` placeholder in the following example with the app's namespace: - -```html - - -``` - ## .NET Core Diagnostics Client Library example Parse and validate NetTrace (`.nettrace`) messages using the .NET Core Diagnostics Client Library: @@ -126,13 +108,11 @@ In the project file (`.csproj`), the properties in the following table enable in Property | Default | Set value to… | Description --- | :---: | :---: | --- `` | No value | `browser` | Mono profilers to use. Potential values are "`browser`" and "`log`". To use both, separate the values with a semicolon. The `browser` profiler enables integration with the browser's developer tools profiler. -`` | `false` | `true` | Controls diagnostic server tracing. `` | `false` | `true` | Controls CPU sampling instrumentation for diagnostic server. ```xml browser - true true ``` diff --git a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md index dc43b5cc6752..fddb5c310095 100644 --- a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md @@ -37,25 +37,19 @@ dotnet workload install wasm-tools * Upload the file via HTTP. * Parse and validate that the trace contains the expected method calls. -Built-in diagnostic counters are available to track [Ahead-of-time (AOT) compilation](xref:blazor/tooling/webassembly#ahead-of-time-aot-compilation). - ## GC (Garbage Collector) dumps -* Manual testing - * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected classes. - * [`dotnet-gcdump` (`collect`/convert` options)](/dotnet/core/diagnostics/dotnet-gcdump): To view the captured GC dump files, see [View the GC dump captured from dotnet-gcdump](/dotnet/core/diagnostics/dotnet-gcdump#view-the-gc-dump-captured-from-dotnet-gcdump). -* Web-based testing - * Upload the file via HTTP. - * Parse and validate that the trace contains the expected classes. +* Manual testing: + +* Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected classes. +* [`dotnet-gcdump` (`collect`/convert` options)](/dotnet/core/diagnostics/dotnet-gcdump): To view the captured GC dump files, see [View the GC dump captured from dotnet-gcdump](/dotnet/core/diagnostics/dotnet-gcdump#view-the-gc-dump-captured-from-dotnet-gcdump). ## Counters trace -* Manual testing - * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected counters. - * [`dotnet-counters collect`](/dotnet/core/diagnostics/dotnet-counters): Open the `.csv`/`.json` output file in Visual Studio and find the expected counters. -* Web-based testing - * Upload the file via HTTP. - * Parse and validate that the trace contains the expected counters. +Manual testing: + +* Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected counters. +* [`dotnet-counters collect`](/dotnet/core/diagnostics/dotnet-counters): Open the `.csv`/`.json` output file in Visual Studio and find the expected counters. ## .NET Core Diagnostics Client Library example @@ -107,14 +101,22 @@ The [`Timing-Allow-Origin` HTTP header](https://developer.mozilla.org/docs/Web/H Browser developer tools console calls in the following example that trigger profiling: * `collectGcDump`: Collect a GC (Garbage Collector) dump. + + ```javascript + globalThis.getDotnetRuntime(0).collectGcDump(); + ``` + * `collectPerfCounters(durationSeconds)`: Collect general diagnostic counters. + + ```javascript + globalThis.getDotnetRuntime(0).collectPerfCounters({durationSeconds: 60}); + ``` + * `collectCpuSamples(durationSeconds)`: Collect CPU diagnostic counters. -```javascript -globalThis.getDotnetRuntime(0).collectGcDump(); -globalThis.getDotnetRuntime(0).collectPerfCounters({durationSeconds: 60}); -globalThis.getDotnetRuntime(0).collectCpuSamples({durationSeconds: 60}); -``` + ```javascript + globalThis.getDotnetRuntime(0).collectCpuSamples({durationSeconds: 60}); + ``` ## Additional resources From e6fae230f7aec03f75f77bccdecf04d70bc68c9c Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:08:50 -0400 Subject: [PATCH 21/28] Updates --- .../webassembly-event-pipe-diagnostics.md | 40 ++++++++----------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md index fddb5c310095..3b6d1f069665 100644 --- a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md @@ -62,11 +62,23 @@ For more information, see the [.NET Core diagnostics documentation](/dotnet/core [!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] -The following example: +Collect a GC (Garbage Collector) dump of the live .NET process with `collectGcDump`: -* Collects a GC (Garbage Collector) dump of the live .NET process. -* Collects diagnostic counters for 60 seconds. -* Collects CPU counters for 60 seconds. +```javascript +globalThis.getDotnetRuntime(0).collectGcDump(); +``` + +Collect diagnostic counters for 60 seconds with `collectPerfCounters(durationSeconds)`: + +```javascript +globalThis.getDotnetRuntime(0).collectPerfCounters({durationSeconds: 60}); +``` + +Collect CPU counters for 60 seconds with `collectCpuSamples(durationSeconds)`: + +```javascript +globalThis.getDotnetRuntime(0).collectCpuSamples({durationSeconds: 60}); +``` The MSBuild properties in the following table enable profiler integration. @@ -98,26 +110,6 @@ Alternatively, enable features when the app is built with the .NET CLI. The foll The [`Timing-Allow-Origin` HTTP header](https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/Timing-Allow-Origin) allows for more precise time measurements. -Browser developer tools console calls in the following example that trigger profiling: - -* `collectGcDump`: Collect a GC (Garbage Collector) dump. - - ```javascript - globalThis.getDotnetRuntime(0).collectGcDump(); - ``` - -* `collectPerfCounters(durationSeconds)`: Collect general diagnostic counters. - - ```javascript - globalThis.getDotnetRuntime(0).collectPerfCounters({durationSeconds: 60}); - ``` - -* `collectCpuSamples(durationSeconds)`: Collect CPU diagnostic counters. - - ```javascript - globalThis.getDotnetRuntime(0).collectCpuSamples({durationSeconds: 60}); - ``` - ## Additional resources * [What diagnostic tools are available in .NET Core?](/dotnet/core/diagnostics/) From 7aed823fb2569255d275bf7a59a585021820d6c2 Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Wed, 30 Apr 2025 13:09:40 -0400 Subject: [PATCH 22/28] Apply suggestions from code review --- .../webassembly-browser-developer-tools-diagnostics.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md index 9fcf827f22d5..cdaaedd28605 100644 --- a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md @@ -98,16 +98,11 @@ For more information, see the [.NET Core diagnostics documentation](/dotnet/core [!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] -The following example: - -* Collects performance counters for 60 seconds. -* Collects CPU counters for 60 seconds. - In the project file (`.csproj`), the properties in the following table enable integration with the browser's profiler. Property | Default | Set value to… | Description --- | :---: | :---: | --- -`` | No value | `browser` | Mono profilers to use. Potential values are "`browser`" and "`log`". To use both, separate the values with a semicolon. The `browser` profiler enables integration with the browser's developer tools profiler. +`` | No value | `browser` | Mono profiler. Currently, only "`browser`" is supported. The `browser` profiler enables integration with the browser's developer tools profiler. `` | `false` | `true` | Controls CPU sampling instrumentation for diagnostic server. ```xml From c69cc661e85f8db8637dbf1853faf6dd1df78b4a Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 2 May 2025 06:30:31 -0400 Subject: [PATCH 23/28] Updates --- .../blazor/performance/app-download-size.md | 2 +- ...bly-browser-developer-tools-diagnostics.md | 2 +- .../webassembly-event-pipe-diagnostics.md | 45 ++++++++----------- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/aspnetcore/blazor/performance/app-download-size.md b/aspnetcore/blazor/performance/app-download-size.md index e210b6127811..b8018b18bd01 100644 --- a/aspnetcore/blazor/performance/app-download-size.md +++ b/aspnetcore/blazor/performance/app-download-size.md @@ -5,7 +5,7 @@ description: Tips for reducing app download size in ASP.NET Core Blazor apps and monikerRange: '>= aspnetcore-3.1' ms.author: riande ms.custom: mvc -ms.date: 04/30/2025 +ms.date: 05/02/2025 uid: blazor/performance/app-download-size --- # ASP.NET Core Blazor app download size performance best practices diff --git a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md index cdaaedd28605..baa95e186972 100644 --- a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md @@ -5,7 +5,7 @@ description: Learn about browser developer tools diagnostics in ASP.NET Core Bla monikerRange: '>= aspnetcore-10.0' ms.author: riande ms.custom: mvc -ms.date: 04/30/2025 +ms.date: 05/02/2025 uid: blazor/performance/webassembly-browser-developer-tools --- # ASP.NET Core Blazor WebAssembly browser developer tools diagnostics diff --git a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md index 3b6d1f069665..f9fa9cb86d53 100644 --- a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md @@ -5,7 +5,7 @@ description: Learn about Event Pipe diagnostics and how to get a Garbage Collect monikerRange: '>= aspnetcore-10.0' ms.author: riande ms.custom: mvc -ms.date: 04/30/2025 +ms.date: 05/02/2025 uid: blazor/performance/webassembly-event-pipe --- # ASP.NET Core Blazor WebAssembly Event Pipe diagnostics @@ -30,20 +30,25 @@ dotnet workload install wasm-tools [EventPipe](/dotnet/core/diagnostics/eventpipe) is a runtime component used to collect tracing data, similar to [ETW](/windows/win32/etw/event-tracing-portal) and [perf_events](https://wikipedia.org/wiki/Perf_%28Linux%29). -* Manual testing - * Browser developer tools: Download the `.nettrace` output file, open the file in Visual Studio, and find the expected method calls. - * [`dotnet-trace`](/dotnet/core/diagnostics/dotnet-trace): Open the `.nettrace` output file in Visual Studio and find the expected method calls. -* Web-based testing - * Upload the file via HTTP. - * Parse and validate that the trace contains the expected method calls. +Collect CPU counters for 60 seconds with `collectCpuSamples(durationSeconds)`: + +```javascript +globalThis.getDotnetRuntime(0).collectCpuSamples({durationSeconds: 60}); +``` ## GC (Garbage Collector) dumps -* Manual testing: +Manual testing: * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected classes. * [`dotnet-gcdump` (`collect`/convert` options)](/dotnet/core/diagnostics/dotnet-gcdump): To view the captured GC dump files, see [View the GC dump captured from dotnet-gcdump](/dotnet/core/diagnostics/dotnet-gcdump#view-the-gc-dump-captured-from-dotnet-gcdump). +Collect a GC (Garbage Collector) dump of the live .NET process with `collectGcDump`: + +```javascript +globalThis.getDotnetRuntime(0).collectGcDump(); +``` + ## Counters trace Manual testing: @@ -51,6 +56,12 @@ Manual testing: * Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected counters. * [`dotnet-counters collect`](/dotnet/core/diagnostics/dotnet-counters): Open the `.csv`/`.json` output file in Visual Studio and find the expected counters. +Collect diagnostic counters for 60 seconds with `collectPerfCounters(durationSeconds)`: + +```javascript +globalThis.getDotnetRuntime(0).collectPerfCounters({durationSeconds: 60}); +``` + ## .NET Core Diagnostics Client Library example Parse and validate NetTrace (`.nettrace`) messages using the .NET Core Diagnostics Client Library: @@ -62,24 +73,6 @@ For more information, see the [.NET Core diagnostics documentation](/dotnet/core [!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] -Collect a GC (Garbage Collector) dump of the live .NET process with `collectGcDump`: - -```javascript -globalThis.getDotnetRuntime(0).collectGcDump(); -``` - -Collect diagnostic counters for 60 seconds with `collectPerfCounters(durationSeconds)`: - -```javascript -globalThis.getDotnetRuntime(0).collectPerfCounters({durationSeconds: 60}); -``` - -Collect CPU counters for 60 seconds with `collectCpuSamples(durationSeconds)`: - -```javascript -globalThis.getDotnetRuntime(0).collectCpuSamples({durationSeconds: 60}); -``` - The MSBuild properties in the following table enable profiler integration. Property | Default | Set value to… | Description From f02f26c6cf2411c4ffe80a4dfbf3863d2a91151d Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Fri, 2 May 2025 06:58:13 -0400 Subject: [PATCH 24/28] Updates --- .../webassembly-event-pipe-diagnostics.md | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md index f9fa9cb86d53..bce064fe10e2 100644 --- a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md @@ -26,42 +26,6 @@ Install the [.NET WebAssembly build tools](xref:blazor/tooling/webassembly#net-w dotnet workload install wasm-tools ``` -## EventPipe profiler - -[EventPipe](/dotnet/core/diagnostics/eventpipe) is a runtime component used to collect tracing data, similar to [ETW](/windows/win32/etw/event-tracing-portal) and [perf_events](https://wikipedia.org/wiki/Perf_%28Linux%29). - -Collect CPU counters for 60 seconds with `collectCpuSamples(durationSeconds)`: - -```javascript -globalThis.getDotnetRuntime(0).collectCpuSamples({durationSeconds: 60}); -``` - -## GC (Garbage Collector) dumps - -Manual testing: - -* Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected classes. -* [`dotnet-gcdump` (`collect`/convert` options)](/dotnet/core/diagnostics/dotnet-gcdump): To view the captured GC dump files, see [View the GC dump captured from dotnet-gcdump](/dotnet/core/diagnostics/dotnet-gcdump#view-the-gc-dump-captured-from-dotnet-gcdump). - -Collect a GC (Garbage Collector) dump of the live .NET process with `collectGcDump`: - -```javascript -globalThis.getDotnetRuntime(0).collectGcDump(); -``` - -## Counters trace - -Manual testing: - -* Browser developer tools: Download the `.json` output file, open the file in Visual Studio, and find the expected counters. -* [`dotnet-counters collect`](/dotnet/core/diagnostics/dotnet-counters): Open the `.csv`/`.json` output file in Visual Studio and find the expected counters. - -Collect diagnostic counters for 60 seconds with `collectPerfCounters(durationSeconds)`: - -```javascript -globalThis.getDotnetRuntime(0).collectPerfCounters({durationSeconds: 60}); -``` - ## .NET Core Diagnostics Client Library example Parse and validate NetTrace (`.nettrace`) messages using the .NET Core Diagnostics Client Library: @@ -103,6 +67,42 @@ Alternatively, enable features when the app is built with the .NET CLI. The foll The [`Timing-Allow-Origin` HTTP header](https://developer.mozilla.org/docs/Web/HTTP/Reference/Headers/Timing-Allow-Origin) allows for more precise time measurements. +## EventPipe profiler + +[EventPipe](/dotnet/core/diagnostics/eventpipe) is a runtime component used to collect tracing data, similar to [ETW](/windows/win32/etw/event-tracing-portal) and [perf_events](https://wikipedia.org/wiki/Perf_%28Linux%29). + +Collect CPU counters for 60 seconds with `collectCpuSamples(durationSeconds)`: + +```javascript +globalThis.getDotnetRuntime(0).collectCpuSamples({durationSeconds: 60}); +``` + +To view the trace, see [Use EventPipe to trace your .NET application](/dotnet/core/diagnostics/eventpipe#use-eventpipe-to-trace-your-net-application). + +## GC (Garbage Collector) dumps + +The [`dotnet-gcdump` (`collect`/convert` options)](/dotnet/core/diagnostics/dotnet-gcdump) global tool collects GC (Garbage Collector) dumps of live .NET processes using [EventPipe](/dotnet/core/diagnostics/eventpipe). + +Collect a GC (Garbage Collector) dump of the live .NET process with `collectGcDump`: + +```javascript +globalThis.getDotnetRuntime(0).collectGcDump(); +``` + +To view the captured GC dump, see [View the GC dump captured from dotnet-gcdump](/dotnet/core/diagnostics/dotnet-gcdump#view-the-gc-dump-captured-from-dotnet-gcdump). + +## Counters trace + +[`dotnet-counters collect`](/dotnet/core/diagnostics/dotnet-counters) is a performance monitoring tool for ad-hoc health monitoring and first-level performance investigation. + +Collect diagnostic counters for 60 seconds with `collectPerfCounters(durationSeconds)`: + +```javascript +globalThis.getDotnetRuntime(0).collectPerfCounters({durationSeconds: 60}); +``` + +To view the trace, see [Use EventPipe to trace your .NET application](/dotnet/core/diagnostics/eventpipe#use-eventpipe-to-trace-your-net-application). + ## Additional resources * [What diagnostic tools are available in .NET Core?](/dotnet/core/diagnostics/) From 0b8ab11df9cb9e39e80c6708d2f927f17b112bbf Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Mon, 5 May 2025 10:51:18 -0400 Subject: [PATCH 25/28] Apply suggestions from code review --- ...ebassembly-browser-developer-tools-diagnostics.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md index baa95e186972..21c0873c834e 100644 --- a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md @@ -73,7 +73,7 @@ Configure the sample interval in the app's project file. In the following exampl ```xml - browser:sampleIntervalMs={INTERVAL}; + browser:interval={INTERVAL}; ``` @@ -89,15 +89,6 @@ Add `callspec` to the `browser` WebAssembly profiler in the `` el ## .NET Core Diagnostics Client Library example -Parse and validate NetTrace (`.nettrace`) messages using the .NET Core Diagnostics Client Library: - -* [`dotnet/diagnostics` GitHub repository](https://github.com/dotnet/diagnostics) -* [`Microsoft.Diagnostics.NETCore.Client` NuGet package](https://www.nuget.org/packages/Microsoft.Diagnostics.NETCore.Client) - -For more information, see the [.NET Core diagnostics documentation](/dotnet/core/diagnostics/) and the [`IpcMessage` API (reference source)](https://github.com/dotnet/diagnostics/blob/main/src/Microsoft.Diagnostics.NETCore.Client/DiagnosticsIpc/IpcMessage.cs). - -[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)] - In the project file (`.csproj`), the properties in the following table enable integration with the browser's profiler. Property | Default | Set value to… | Description @@ -108,7 +99,6 @@ Property | Default | Set value to… | Description ```xml browser - true ``` From c1042eee17aa2add8d949741ffde184b78ac1514 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 5 May 2025 11:25:10 -0400 Subject: [PATCH 26/28] Updates --- .../webassembly-event-pipe-diagnostics.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md index bce064fe10e2..5e31220e1ee2 100644 --- a/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-event-pipe-diagnostics.md @@ -42,7 +42,6 @@ The MSBuild properties in the following table enable profiler integration. Property | Default | Set value to… | Description --- | :---: | :---: | --- `` | `false` | `true` | Controls diagnostic server tracing. -`` | `false` | `true` | Controls CPU sampling instrumentation for diagnostic server. Not necessary for memory dump or counters. **Makes the app execute slower. Only set this to `true` for performance profiling.** `` | `false` | `true` | Controls `System.Diagnostics.Metrics` support. For more information, see the [`System.Diagnostics.Metrics` namespace](/dotnet/api/system.diagnostics.metrics). `` | `false`| `true` | Controls `EventPipe` support. For more information, see [Diagnostics and instrumentation: Observability and telemetry](/dotnet/core/deploying/native-aot/diagnostics#observability-and-telemetry). @@ -53,7 +52,6 @@ In the app's project file (`.csproj`): ```xml true - true true true @@ -71,6 +69,16 @@ The [`Timing-Allow-Origin` HTTP header](https://developer.mozilla.org/docs/Web/H [EventPipe](/dotnet/core/diagnostics/eventpipe) is a runtime component used to collect tracing data, similar to [ETW](/windows/win32/etw/event-tracing-portal) and [perf_events](https://wikipedia.org/wiki/Perf_%28Linux%29). +Use the `` property to enable CPU sampling instrumentation for diagnostic server. This setting isn't necessary for memory dump or counters. **Makes the app execute slower. Only set this to `true` for performance profiling.** + +Enabling profilers has negative size and performance impact, so don't publish an app for production with profilers enabled. In the following example, a condition is set on a property group section that only enables profiling when the app is built with `/p:BlazorSampleProfilingEnabled=true` (.NET CLI) or `true` in a Visual Studio publish profile, where "`BlazorSampleProfilingEnabled`" is a custom symbol name that you choose and doesn't conflict with other symbol names. + +```xml + + true + +``` + Collect CPU counters for 60 seconds with `collectCpuSamples(durationSeconds)`: ```javascript From cfe55f7cd9c4afc38fdb575e08c85f545f1d31a5 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 5 May 2025 11:29:13 -0400 Subject: [PATCH 27/28] Updates --- .../webassembly-browser-developer-tools-diagnostics.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md index 21c0873c834e..151f59eaaa7e 100644 --- a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md @@ -91,10 +91,7 @@ Add `callspec` to the `browser` WebAssembly profiler in the `` el In the project file (`.csproj`), the properties in the following table enable integration with the browser's profiler. -Property | Default | Set value to… | Description ---- | :---: | :---: | --- -`` | No value | `browser` | Mono profiler. Currently, only "`browser`" is supported. The `browser` profiler enables integration with the browser's developer tools profiler. -`` | `false` | `true` | Controls CPU sampling instrumentation for diagnostic server. +Use the `` property set to `browser` for the Mono profiler. Currently, only "`browser`" is supported. The `browser` profiler enables integration with the browser's developer tools profiler. ```xml From 7a3322d868bd001719f997b085bef4f1c0cab277 Mon Sep 17 00:00:00 2001 From: guardrex <1622880+guardrex@users.noreply.github.com> Date: Mon, 5 May 2025 11:33:09 -0400 Subject: [PATCH 28/28] Updates --- .../webassembly-browser-developer-tools-diagnostics.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md index 151f59eaaa7e..8f839e396705 100644 --- a/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md +++ b/aspnetcore/blazor/performance/webassembly-browser-developer-tools-diagnostics.md @@ -89,9 +89,7 @@ Add `callspec` to the `browser` WebAssembly profiler in the `` el ## .NET Core Diagnostics Client Library example -In the project file (`.csproj`), the properties in the following table enable integration with the browser's profiler. - -Use the `` property set to `browser` for the Mono profiler. Currently, only "`browser`" is supported. The `browser` profiler enables integration with the browser's developer tools profiler. +In the project file (`.csproj`), use the `` property set to `browser` to enable integration with the Mono profiler. Currently, only "`browser`" is supported. The `browser` profiler enables integration with the browser's developer tools profiler. ```xml