runtime: Bad performance with Blazor WebAssembly even when using AOT compilation
Description
For a certain project I have to load CSV files in Blazor WebAssembly and use the DataFrame from the Microsoft.Data.Analysis package. For this purpose I used DataFrame.LoadCsv. The performance was not good even after publishing the project with AOT compilation.
Configuration
.NET 6 Microsoft Edge 101.0.1210.53 (Official build) (64-bit) Windows 10 21H2 (x64)
Data
From this website I downloaded the dataset Building consents issued: March 2022 – CSV (ZIP file) and from that ZIP file I used Building consents by institutional control (Monthly).csv. For comparison, besides using Blazor WebAssembly with AOT compilation with Microsoft’s DataFrame (using DataFrame.LoadCsv), I also tried loading the CSV file with the CsvHelper library in Blazor WebAssembly and then manually add the data to the DataFrame, but it was for some datasets slightly faster and for others slightly slower than DataFrame.LoadCsv. For comparison, I also tried to use DataFrame.LoadCsv directly in a C# console project on Windows (without Blazor WebAssembly) and in JavaScript using Danfo.js. Here are the results:
Benchmark method | Load time |
---|---|
Blazor WebAssembly + DataFrame with AOT (.NET 6) | 00:00:41.1740000 |
Blazor WebAssembly + CSV Helper with AOT (.NET 6) | 00:00:45.2790000 |
C# + DataFrame directly on Windows (without Blazor, .NET 6) | 00:00:00.6477062 |
JavaScript + Danfo.js | 00:00:01.423 |
Blazor WebAssembly + DataFrame without AOT (Release build, .NET 6) | 00:02:54.8770000 |
Blazor WebAssembly + CSV Helper without AOT (Release build, .NET 6) | 00:03:33.7900000 |
I already saw in another GitHub issue that the performance of Blazor WebAssembly with AOT can be affected by things like reflection, where Blazor must fall back to the interpreter. However, I did not expect Blazor WebAssembly to be - even with AOT - almost 65 times slower than a C# console application on Windows and almost 30 times slower than JavaScript (with Danfo.js).
Analysis
For my example with Blazor WebAssembly and Microsoft’s DataFrame I started a new Blazor WebAssembly project and added a button that called the following function:
async Task LoadData()
{
_paragraphText = "Loading data to the dataframe...";
var fileStream = await Http.GetStreamAsync(new Uri("datasets/Building consents by institutional control (Monthly).csv", UriKind.Relative));
var startTime = DateTime.Now;
DataFrame data = DataFrame.LoadCsv(fileStream, ',');
var loadTimeSpan = DateTime.Now - startTime;
_paragraphText = "Loaded successfully. Elapsed time for loading: " + loadTimeSpan;
}
This code blocks the UI thread, but it’s enough to demonstrate the issue. I can also provide you with the code snippets for the other test cases if you wish, but this is the most important one for me.
I then used the following build settings to be able to do performance profiling in the browser:
<RunAOTCompilation>True</RunAOTCompilation>
<WasmEmitSymbolMap>true</WasmEmitSymbolMap>
<WasmNativeStrip>false</WasmNativeStrip>
When looking at the Performance Profiler from Microsoft Edge, you can see that there are a lot of transitions from JavaScript to WASM and back:
If this helps, you can open this file in Microsoft Edge’s performance profiler to see my results: Blazor WebAssembly AOT .NET 6 performance profiling with DataFrame.LoadCsv.txt
Thanks for creating Blazor and let me know if I can help with anything! 😃
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 21 (10 by maintainers)
We plan continue to work on performance for both the interpreter and aot scenarios (as well as exploring other options). You might find that the interpreter is also faster in .NET7, although not to the same degree as AOT.
There have been a couple bugs in the illinker that caused DateTime issues that might be causing your problem but I’m not sure @radical can you see if you can figure out what is failing in the build here?