Performance
bibui has two routes, and you choose one per app. Silk + Skia is a GLFW window drawn by SkiaSharp on the GPU. Wayland + managed is a raw Wayland window, drawn on the CPU by bibui's own rasterizer. This page gives the results of measuring them. Every number comes from one machine. Compare the routes with each other, not with your own hardware.
The machine. Ryzen AI 9 365 with a Radeon 880M, Hyprland, .NET 10. Each timing ran on a core with nothing else on it. The headline figures are for the Wayland + managed route.
How small
The same small dashboard app, built on each route and published with Native AOT:
- The showcase publishes to about 5.2 MB. It is an observatory console that uses most of bibui: charts, Markdown, dialogs, theme files and a seeded theme.
- Your own code adds little. Most of the binary is bibui and the managed rasterizer, so it grows slowly with the app.
System.Text.Json, for example, adds about half a megabyte. - The Wayland + managed route takes no third-party NuGet packages.
Bibui.Platform.WaylandandBibui.Raster.Managed.Backenddepend on nothing outside bibui.
How fast it starts
The showcase was measured as a Native AOT binary on the Wayland + managed route. It reaches its first rendered 1440 × 900 frame about 29 ms after it is spawned.
How much memory
Most nodes come from pools, so building a frame allocates almost nothing. A pooled box is the n-th box from a pool, and the pool rewinds when the frame ends. A retained box is the same instance from frame to frame.
Frame times
A 600-button grid, built, laid out and rasterised headless. These rows exclude presenting.
In a window
- Presenting. A Wayland frame goes into a shared-memory buffer, so presenting costs 0.01 to 0.03 ms. There is no GL upload or readback. On the GPU path, the CPU side of a 600-button frame is about 5.5 ms p50. That covers recording the frame and flushing it.
- Pacing. Wayland frame callbacks give an even 16.67 ms interval. The GLFW path's p99 interval is 17.5 ms.
- Idle.
BeginFramesleeps until input arrives or something asks for a frame. When every animation has arrived, the loop goes idle.
Full redraws: where the GPU wins
A CPU-only route still holds 60 Hz because of damage tracking. A typical frame changes only a hover colour or a caret. Only the rectangles that changed are rasterised. The output is byte-identical to a full repaint.
Configurations and systems
Every route on every machine we have measured so far. This table grows as more machines are measured. A blank cell has not been measured.
| System | Route | AOT size | First frame | RSS | Grid p50 1800×1400 |
|---|---|---|---|---|---|
| Ryzen AI 9 365 Radeon 880M · Hyprland | Wayland + managed | 5.8 MB | 9.9 ms | 33.1 MB | 4.61 ms |
| Ryzen AI 9 365 Radeon 880M · Hyprland | Silk + Skia | 15.1 MB | 17.1 ms | 46.8 MB | 6.37 ms |
| Intel laptop, integrated GPU | both routes | — | — | — | — |
| Desktop, discrete GPU | both routes | — | — | — | — |
| Low-power x64 (N100 class) | Wayland + managed | — | — | — | — |
| Arm64 board | Wayland + managed | Once Linux arm64 is supported | |||
Measuring your own app
BIBUI_PROFILE=1 prints, for every frame, the time EndBuild spent building, laying out and recording. Drawing and presenting happen in your own loop, so time those yourself:
while (WaylandWindow.BeginFrame(window, runtime))
{
long t0 = Stopwatch.GetTimestamp();
runtime.BeginBuild(window.Events);
BuildUi(runtime);
runtime.EndBuild(); // build + layout + record
long t1 = Stopwatch.GetTimestamp();
WaylandWindow.BeginDraw(window);
managed.Draw(runtime.DrawList); // raster
long t2 = Stopwatch.GetTimestamp();
WaylandWindow.EndDraw(window); // present: swap or commit
long t3 = Stopwatch.GetTimestamp();
Log(Stopwatch.GetElapsedTime(t0, t1), Stopwatch.GetElapsedTime(t1, t2), Stopwatch.GetElapsedTime(t2, t3));
WaylandWindow.EndFrame(window, runtime);
}- Run on a quiet machine and record the load average with the numbers. On a busy machine the medians inflate and p99 becomes mostly scheduler noise.
BIBUI_ALWAYS_RENDER=1draws a frame on every refresh. Use it for steady-state timing of a scene that would otherwise go idle.- The numbers above come from the maintainers' benchmark harness, which is not in the public repository.