SlintPlot benchmarks
Frame times of SlintPlot's charts from 100 to 1,000,000 points, with Slint's software renderer and with Skia on the GPU. For the short version, see how much a chart can show.
How it's measured
The numbers come from the stress test app, slintplot-stress. --bench renders each configuration with Slint's software renderer, without a window;
--bench-gpu renders the same configurations with Skia, on the GPU.
- Machine: Apple M4 (10 cores, 16 GB), macOS 27, a release build of SlintPlot 0.5.0 with Slint 1.18.1 (its Skia renderer through skia-bindings 0.153.3).
- Versions matter. Most of a frame is spent in Slint's renderer, so another Slint version, or another Skia, can give different numbers, faster or slower. We measure again for each SlintPlot release; when you compare your own numbers with these, check which Slint version your build uses (
cargo tree -i slint). - Software renderer: on one CPU core, into a 1280×800 pixel buffer.
- Skia: Slint's Skia renderer with Metal on the M4's GPU, in a 1280×800 window at scale factor 1. Each frame is drawn with
Window::take_snapshot, which returns once the GPU has drawn it and the pixels are read back, so the GPU's work is included. Reading back costs a fixed amount per frame: the least a frame takes, a gauge, is 1.3 ms. - Data: three datasets (three groups for the sunburst), random walks.
- Frame: the chart's layout plus drawing every pixel, measured once per configuration. Showing it on a screen isn't included. Hover is the next frame after the mouse moves over the chart. With Skia, redraw is the median of up to 15 more frames of the same data.
- Runs: each number is the median of three runs. Most numbers differed between runs by ±3% or less; frames under 5 ms, and a few others, by up to ±15%.
At 60 frames per second, a frame has 16.7 ms. Frames below that can be animated and streamed smoothly; slower ones are fine for charts that change now and then.
Software renderer
Lines, bars and points
Frame time per number of points in each dataset. Decimation draws a line with more points than pixels as one span per pixel column.
| Points | Line | Line, decimated | Time series | Time series, decimated | Bars | Scatter |
|---|---|---|---|---|---|---|
| 100 | 4.4 ms | 4.6 ms | 3.2 ms | 3.1 ms | 3.2 ms | 2.7 ms |
| 1,000 | 6.8 ms | 6.8 ms | 7.6 ms | 5.8 ms | 5.0 ms | 4.3 ms |
| 10,000 | 59 ms | 5.5 ms | 67 ms | 5.6 ms | 26 ms | 23 ms |
| 100,000 | 1.2 s | 24 ms | 1.3 s | 29 ms | 231 ms | not run |
| 1,000,000 | 16.9 s | 238 ms | 15.3 s | 281 ms | not run | not run |
With point markers and smooth lines, a line takes 6.3 ms at 100 points, 14 ms at 1,000 and 129 ms at 10,000: each marker is an element. Bars and markers are one element each, so the benchmark doesn't run them past 100,000 bars or 10,000 markers.
Charts with one shape per item
Waterfall, dumbbell, funnel and sunburst charts draw every step, row, stage or item, with no decimation:
| Items | Waterfall | Dumbbell | Funnel | Sunburst |
|---|---|---|---|---|
| 100 | 1.7 ms | 1.5 ms | 1.0 ms | 3.4 ms |
| 1,000 | 9.0 ms | 9.1 ms | 3.8 ms | 21 ms |
| 10,000 | 83 ms | 93 ms | 33 ms | 266 ms |
A gauge frame takes 2.3 ms.
Segmented rings and tile grids
Frame time per number of cells in the matrix, on a scale and by category. These charts draw their cells as one path per color, not a shape per cell:
| Cells | Segmented rings, on a scale | Segmented rings, by category | Tile grid, on a scale | Tile grid, by category |
|---|---|---|---|---|
| 100 | 2.4 ms | 2.4 ms | 2.9 ms | 2.9 ms |
| 1,000 | 6.2 ms | 5.1 ms | 7.7 ms | 7.4 ms |
| 10,000 | 45 ms | 30 ms | 54 ms | 53 ms |
| 100,000 | over the limit | over the limit | 238 ms | 235 ms |
A segmented ring chart shows at most 50 rings of 720 segments (36,000 cells), and a tile grid at most 200 rows of 1,000 tiles (200,000 cells); the rest of a larger matrix isn't drawn.
Skia (GPU)
Frame time per number of points in each dataset, with new data, and redrawing the same data (as when hovering), with Slint's Skia renderer on the M4's GPU:
| Points | Line | Line, decimated | Time series | Time series, decimated | Bars | Scatter |
|---|---|---|---|---|---|---|
| 100 | 2.4 ms | 2.2 ms | 2.3 ms | 1.8 ms | 3.0 ms | 2.5 ms |
| 1,000 | 5.8 ms | 5.4 ms | 6.7 ms | 4.8 ms | 8.2 ms | 11 ms |
| 10,000 | 34 ms | 5.8 ms | 44 ms | 5.8 ms | 62 ms | 102 ms |
| 100,000 | 352 ms | 25 ms | 430 ms | 29 ms | 641 ms | not run |
| 1,000,000 | 3.3 s | 241 ms | 3.4 s | 288 ms | not run | not run |
| Redraw, 1,000,000 | 2.2 s | 3.1 ms | 2.2 s | 3.0 ms |
With point markers and smooth lines, a line takes 4.2 ms at 100 points, 18 ms at 1,000 and 177 ms at 10,000.
| Items | Waterfall | Dumbbell | Funnel | Sunburst |
|---|---|---|---|---|
| 100 | 2.5 ms | 3.6 ms | 1.8 ms | 4.6 ms |
| 1,000 | 11 ms | 24 ms | 6.5 ms | 24 ms |
| 10,000 | 97 ms | 224 ms | 53 ms | 364 ms |
| Cells | Segmented rings, on a scale | Segmented rings, by category | Tile grid, on a scale | Tile grid, by category |
|---|---|---|---|---|
| 100 | 1.8 ms | 1.8 ms | 2.0 ms | 1.9 ms |
| 1,000 | 6.6 ms | 5.0 ms | 5.6 ms | 5.6 ms |
| 10,000 | 44 ms | 29 ms | 37 ms | 36 ms |
| 100,000 | over the limit | over the limit | 112 ms | 110 ms |
- Long paths are faster with Skia. A line or time series without decimation takes 3.3 s at a million points instead of 17 s, and 34 ms at 10,000 instead of 59 ms.
- Many separate shapes are slower. Each bar, marker or item is a separate draw on the GPU: 10,000 scatter markers take 102 ms instead of 23 ms, 10,000 bars 62 ms instead of 26 ms.
- Decimated lines cost the same in both renderers, since reading and decimating the data takes most of the time; redrawing them without new data takes 3 ms with Skia.
- Redraws are cheaper. Drawing the same data again takes a third to three quarters of a frame with new data, because Skia keeps the shapes it has built.
- One machine. These are from Apple's Metal on an M4. Other GPUs, and Skia with OpenGL or Vulkan on Linux and Windows, will differ.
Streaming limits
How much data can a chart show while it streams, and still update at 60 or 30 frames per second? slintplot-stress --bench-stream
measures it: each update appends one value to each of three datasets, drops the oldest, and renders a full frame. It grows the window
(the values kept per dataset) in 1-2-5 steps from 1,000 to 10,000,000, and times each size: the 95th percentile of up to 100 updates, the median of three runs.
Same machine and renderer as above: Apple M4, macOS 27, Slint's software renderer on one core, 1280×800.
Two views: everything, the whole window on screen, and the latest 1,000, zoomed in to the newest values, as a live view usually is, with the rest kept for scrolling back.
| Chart | Everything shown | Latest 1,000 shown | ||
|---|---|---|---|---|
| 60 fps | 30 fps | 60 fps | 30 fps | |
| Line, decimated | 50,000 | 100,000 | 10,000,000+ | 10,000,000+ |
| Time series, decimated | 20,000 | 100,000 | 10,000,000+ | 10,000,000+ |
| Line, not decimated | 2,000 | 5,000 | 10,000,000+ | 10,000,000+ |
| Time series, not decimated | 2,000 | 5,000 | 10,000,000+ | 10,000,000+ |
| Bars | 2,000 | 5,000 | 10,000,000+ | 10,000,000+ |
| Scatter | 5,000 | 10,000 | 20,000 | 50,000 |
The largest window, in values per dataset, that updates within 16.7 ms (60 fps) or 33.3 ms (30 fps). 10,000,000+ means the largest size tried still made it.
- Zoomed in, the data size doesn't matter. A view of the latest 1,000 values updates in about 6 ms with 1,000 values kept per dataset or with 10,000,000: the chart finds the visible values with a binary search and reads only those.
- Showing everything, decimation sets the limit. A decimated line updates at 60 fps with 50,000 values per dataset, and takes 130–150 ms with 500,000. A decimated time series makes 60 fps with 20,000 in two runs of three and 50,000 in one: at 50,000 it takes 16.4–16.8 ms, right at the 16.7 ms limit. Below about 2,500 values (twice the plot width in pixels) lines aren't decimated, so up to there all line charts cost the same.
- Scatter charts read every point, since their points can be in any order, so even zoomed in they slow down from about 20,000 points per dataset.
- One value per update. At higher data rates, the samples that arrive between frames are added in one batch per frame (see Streaming). The benchmark doesn't measure those larger batches; the stress app shows their effect live, at up to 100,000 samples a second.
What the numbers mean
- Up to about 1,000 points per dataset, every chart fits in a 60 fps frame, except the sunburst (21 ms).
- Lines of any size stay usable with decimation, which is on by default: 5 ms at 10,000 points, 24 ms at 100,000 and about 240 ms at 1,000,000 for a full redraw. Hovering stays at about 3 ms at every size, and zooming in to 0.1% of a million points brings a frame to 46 ms. Without decimation, a million-point line takes 17 s to draw.
- Bars, scatter markers and the one-shape-per-item charts grow with the count. For animation and streaming, keep them to about 1,000 bars, markers or items; at 10,000 a frame takes 23–266 ms.
- Up to 10,000 points, drawing takes most of the time. Computing the chart takes 1–8 ms (19 ms for a line with point markers) of frames of 6–266 ms. With decimated million-point lines it's the other way round: reading and decimating the data takes 188 ms of the 238 ms frame.
What isn't measured
- FemtoVG, and Skia on other systems. Skia is measured on macOS only, with Metal. FemtoVG, Slint's default GPU renderer, isn't benchmarked: its snapshots can't be timed the same way. The streaming limits are measured with the software renderer only.
- The browser. The web gallery runs SlintPlot as WebAssembly; it isn't benchmarked, and is likely slower.
- Other machines. Everything above is from one fast computer. Older or low-power hardware is slower; embedded devices are untested.
- Memory use and start-up time.
Run it yourself
To measure your own machine, run the benchmark, or open the app to try the charts with live numbers:
cargo install slintplot-stress
slintplot-stress --bench # the tables above, for your machine
slintplot-stress --bench-stream # only the streaming limits, with your machine's specs
slintplot-stress # the interactive stress test
To repeat the numbers above from the source, at the version they were measured with:
git clone https://github.com/trondegil/slintplot
cd slintplot
git checkout v0.5.0
cargo run --release -p slintplot-stress -- --bench
A full run takes about 8 minutes and prints the machine it ran on. Close other apps first and keep the computer on mains power; we run it three times and take the median of each number.
The interactive app shows live frame times with any renderer; see choosing a renderer.
The Skia numbers, with the app built with its skia feature (or installed with cargo install slintplot-stress --features skia, then
SLINT_BACKEND=winit-skia SLINT_SCALE_FACTOR=1 slintplot-stress --bench-gpu). A window opens and stays empty while it runs: the frames are drawn off-screen. Add a folder after --bench-gpu to save every frame as a PNG.
SLINT_BACKEND=winit-skia SLINT_SCALE_FACTOR=1 \
cargo run --release -p slintplot-stress --features skia -- --bench-gpu
SlintPlot · slintplot.dev · license@slintplot.dev