Dan Schnau

Experimenting with performances gains from Blazor WASM AOT Compilation

It would appear that AOT compilation gets substantial performance improvements in client-side application performance.

I put together a tech demo running Blazor client side WASM. The code for the main component is at the bottom of this post.

The gist is this: draw an image, using the SixLabors ImageSharp library, 20 times. Each image is slightly wider than the previous, and post the time taken.

In my experiments, it takes about 1/3rd as much time to complete with Ahead-of-time compilation.

Here's the test without AOT compilation:

And the same test, compiled with AOT:

Obviously, this is an anecdotal test, but it would certainly appear to me that AOT compilation can make for some very fast client-side image processing applications.

Code below:

@page "/"
@using SixLabors.ImageSharp
@using SixLabors.ImageSharp.Drawing
@using SixLabors.ImageSharp.Drawing.Processing
@using SixLabors.ImageSharp.Formats.Jpeg
@using SixLabors.ImageSharp.Formats.Png
@using SixLabors.ImageSharp.PixelFormats
@using SixLabors.ImageSharp.Processing
@using System.Diagnostics

<PageTitle>Home</PageTitle>

<h1>Blazor WASM AOT performance testing</h1>

<button @onclick="_ => StartWork()" disabled="@started">Start</button>

<p>milliseconds to @TOTAL_ITERATIONS draws: @TimeTaken</p>

<img src="@ImgString" />

@code {
    const int TOTAL_ITERATIONS = 20;
    private string? ImgString { get; set; }
    private long TimeTaken { get; set; }
    private int TimesCompleted { get; set; }
    private bool started { get; set; } = false;

    private Stopwatch Timer { get; set; } = new Stopwatch();

    private async Task StartWork()
    {
        started = true;
        TimesCompleted = 1;
        Timer.Start();

        while(TimesCompleted < TOTAL_ITERATIONS)
        {
            await DrawStar();
        }

        Timer.Stop();

        TimeTaken = Timer.ElapsedMilliseconds;
    }

    private async Task DrawStar()
    {
        using (Image<Rgba32> image = new(TimesCompleted * 10, 200))
        {
            Star star = new(x: 100.0f, y: 100.0f, prongs: 5, innerRadii: 20.0f, outerRadii: 30.0f);
            image.Mutate(x => x.Fill(Color.Red, star));
            ImgString = image.ToBase64String(JpegFormat.Instance);
        }
        TimesCompleted++;
        StateHasChanged();
        await Task.Delay(100);
        Console.WriteLine(this.ImgString);
    }
}