Benchmarks

BUI's published numbers with their full context: start time and battery cost for every API, frame times, Rust against gpui, and JavaScript startup and animation.

  • Ryzen 7 5800U
  • Windows 11

BUI is fast where it matters to people: it opens quickly, it sits at zero CPU while you’re not touching it, and it stays smooth when thousands of things move. Here are the numbers, with everything you need to judge them.

Start time and battery

What was measured: the same small settings window (a label, a text field, a checkbox, a slider and a button), written each of the five ways, from bench/apps. Each ran on BUI’s CPU renderer (the default) and on its GPU renderer (BUI_GPU=1).

The last rows are one gpui-syntax source file, settings.rs, compiled unchanged against blenderui, Zed’s gpui and gpui-fast. gpui has no form widgets, so there the controls are styled divs.

How: the median of 10 launches, from process start until the first frame is on screen, with Python 3.14 and Node 22.

Start time, every way in

The same small settings window written five ways; median of 10 launches

Lower is better

  • CPU renderer
  • GPU renderer
  • RustHTML + CSS
    • CPU renderer: 38 ms
    • GPU renderer: 42 ms
  • JavaScriptReact, Node.js
    • CPU renderer: 94 ms
    • GPU renderer: 99 ms
  • Blender componentsPython
    • CPU renderer: 112 ms
    • GPU renderer: 116 ms
  • tkinter syntaxPython
    • CPU renderer: 139 ms
    • GPU renderer: 159 ms
  • Qt syntaxPython
    • CPU renderer: 156 ms
    • GPU renderer: 161 ms
Open bench
Start time and battery: the same small settings window, median of 10 launches, process start to first frame
AppRendererStart timeCPU used to startMemory (idle)Idle CPU per minute
Rust (HTML + CSS)CPU38 ms27 ms13 MB0 ms
GPU42 ms61 ms31 MB1.8 ms
JavaScript (React, Node.js)CPU94 ms100 ms48 MB68 ms
GPU99 ms131 ms60 MB71 ms
Blender components (Python)CPU112 ms86 ms23 MB0 ms
GPU116 ms125 ms32 MB1.7 ms
tkinter syntax (Python)CPU139 ms112 ms25 MB0.2 ms
GPU159 ms157 ms43 MB2.4 ms
Qt syntax (Python)CPU156 ms123 ms27 MB0 ms
GPU161 ms160 ms36 MB1.2 ms
Same gpui code: blenderuiCPU40 ms27 ms15 MB0 ms
blenderuiGPU43 ms60 ms31 MB2.1 ms
gpuiGPU231 ms226 ms29 MB743 ms
gpui-fastGPU226 ms217 ms31 MB2.5 ms

Python 3.14 and Node 22. The last rows are one gpui-syntax source file (bindings/rust/bench/common/settings.rs) compiled unchanged against blenderui, gpui and gpui-fast; gpui has no form widgets, so there the controls are styled divs. Battery cost is the CPU time an app causes; memory doesn't count GPU memory.

Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power

Start time and battery: the same small settings window, median of 10 launches, process start to first frame
AppRendererStart timeCPU used to startMemory (idle)Idle CPU per minute
Rust (HTML + CSS)CPU38 ms27 ms13 MB0 ms
GPU42 ms61 ms31 MB1.8 ms
JavaScript (React, Node.js)CPU94 ms100 ms48 MB68 ms
GPU99 ms131 ms60 MB71 ms
Blender components (Python)CPU112 ms86 ms23 MB0 ms
GPU116 ms125 ms32 MB1.7 ms
tkinter syntax (Python)CPU139 ms112 ms25 MB0.2 ms
GPU159 ms157 ms43 MB2.4 ms
Qt syntax (Python)CPU156 ms123 ms27 MB0 ms
GPU161 ms160 ms36 MB1.2 ms
Same gpui code: blenderuiCPU40 ms27 ms15 MB0 ms
blenderuiGPU43 ms60 ms31 MB2.1 ms
gpuiGPU231 ms226 ms29 MB743 ms
gpui-fastGPU226 ms217 ms31 MB2.5 ms

Python 3.14 and Node 22. The last rows are one gpui-syntax source file (bindings/rust/bench/common/settings.rs) compiled unchanged against blenderui, gpui and gpui-fast; gpui has no form widgets, so there the controls are styled divs. Battery cost is the CPU time an app causes; memory doesn't count GPU memory.

What it means:

  • On the same code, blenderui shows its first frame about 5× sooner than gpui and gpui-fast, spends about 8× less CPU getting there, and on the CPU renderer uses half the memory.
  • Idle, gpui keeps about 1.2% of a core busy. blenderui uses none.
  • The GPU renderer starts a little slower and uses more memory (the GPU device). It pays off on large, animated scenes, below.

Start time, same gpui code

One gpui-syntax file compiled against each library; median of 10 launches

Lower is better

5.7×faster start than gpui-fast

  • BUI
  • Others
  • blenderuiCPU renderer40 ms
  • blenderuiGPU renderer43 ms
  • gpui-fastGPU226 ms5.7× more
  • gpuiZed's, GPU231 ms5.8× more
Open bench
Start time, the same gpui-syntax file (bindings/rust/bench/common/settings.rs) compiled against each library: median of 10 launches, process start to first frame
Same gpui codeRendererStart timeCPU used to startMemory (idle)Idle CPU per minute
blenderuiCPU40 ms27 ms15 MB0 ms
blenderuiGPU43 ms60 ms31 MB2.1 ms
gpuiGPU231 ms226 ms29 MB743 ms
gpui-fastGPU226 ms217 ms31 MB2.5 ms

gpui has no form widgets, so there the controls are styled divs. Memory doesn't count GPU memory.

Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power

Idle CPU, same gpui code

CPU time per minute while the window sits idle

Lower is better

0 msidle CPU on the CPU renderer: it sleeps

  • BUI
  • Others
  • blenderuiCPU renderer0 ms
  • blenderuiGPU renderer2.1 ms
  • gpui-fastGPU2.5 ms1.2× more
  • gpuiZed's, GPU743 ms354× more
Open bench
Start time, the same gpui-syntax file (bindings/rust/bench/common/settings.rs) compiled against each library: median of 10 launches, process start to first frame
Same gpui codeRendererStart timeCPU used to startMemory (idle)Idle CPU per minute
blenderuiCPU40 ms27 ms15 MB0 ms
blenderuiGPU43 ms60 ms31 MB2.1 ms
gpuiGPU231 ms226 ms29 MB743 ms
gpui-fastGPU226 ms217 ms31 MB2.5 ms

gpui has no form widgets, so there the controls are styled divs. Memory doesn't count GPU memory.

Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power

How battery cost is measured: laptops can’t report energy per app, so the benchmark uses CPU time as a proxy. It counts the CPU an app spends starting up, and the CPU it uses over 20 seconds while the window sits idle: that’s what drains a battery while an app is open. BUI redraws only when something changes and otherwise sleeps, so idle use is near zero on either renderer.

Fine print: Node’s event loop accounts for the JavaScript idle figure. Python’s times include starting the interpreter. Memory doesn’t count GPU memory.

Frame times

What was measured: the full Blender components demo (520×900), from Python and C.

Frame cost

Python and C, the full component demo (520×900)

Lower is better

0.05 msfor a hover or scrub frame

  • Complete frameeverything redrawn~0.7 ms
  • Input to screennative window~0.06 ms
  • Hover or scrubdamage only~0.05 ms
Open bench
Python and C, the full component demo (520×900)
FrameTime
Complete frame (everything redrawn)~0.7 ms
Hover or number-scrub frame (damage only)~0.05 ms
Native window: input event → on screen~0.06 ms

Dear ImGui's demo window with every section open (27k triangles, 1280×800) is a full software redraw of about 5–8 ms.

Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power

Rust against gpui and gpui-fast

What was measured: a 1000×800 window filled with N rounded, numbered cells, built with the same element tree in every framework. In this table, every cell changes every frame (the worst case), with 3,000 cells. All apps ran in the same session.

Frames per second

Rust, 3000 animated cells, same session

Higher is better

3×the frame rate of gpui

  • BUI
  • Others
  • blenderuiGPU renderer59.9 fps
  • blenderuiCPU renderer57.6 fps
  • gpui-fast31.5 fps1.9× fewer
  • gpui19.9 fps3× fewer
Open bench
Rust, 3000 animated cells, all apps in the same session
blenderui (GPU)blenderui (CPU)gpui-fastgpui
FPS59.957.631.519.9
CPU per frame11.6 ms22.0 ms31.9 ms + GPU50.5 ms + GPU
RAM40 MB30 MB65 MB77 MB
First frame~5 ms~5 ms~200 ms~220 ms
Idle CPU0 %0–0.9 %0–0.4 %0.9–1.4 %

gpui-fast's heavy-scene frame rate varies between sessions on this laptop (30–60 fps), so compare within one session.

Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power

CPU per frame

Rust, 3000 animated cells; gpui's numbers don't include its GPU time

Lower is better

2.8×less CPU per frame than gpui-fast

  • BUI
  • Others
  • blenderuiGPU renderer11.6 ms
  • blenderuiCPU renderer22.0 ms
  • gpui-fast31.9 ms + GPU2.8× more
  • gpui50.5 ms + GPU4.4× more
Open bench
Rust, 3000 animated cells, all apps in the same session
blenderui (GPU)blenderui (CPU)gpui-fastgpui
FPS59.957.631.519.9
CPU per frame11.6 ms22.0 ms31.9 ms + GPU50.5 ms + GPU
RAM40 MB30 MB65 MB77 MB
First frame~5 ms~5 ms~200 ms~220 ms
Idle CPU0 %0–0.9 %0–0.4 %0.9–1.4 %

gpui-fast's heavy-scene frame rate varies between sessions on this laptop (30–60 fps), so compare within one session.

Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power

Rust, 3000 animated cells, all apps in the same session
blenderui (GPU)blenderui (CPU)gpui-fastgpui
FPS59.957.631.519.9
CPU per frame11.6 ms22.0 ms31.9 ms + GPU50.5 ms + GPU
RAM40 MB30 MB65 MB77 MB
First frame~5 ms~5 ms~200 ms~220 ms
Idle CPU0 %0–0.9 %0–0.4 %0.9–1.4 %

gpui-fast's heavy-scene frame rate varies between sessions on this laptop (30–60 fps), so compare within one session.

More results, at 100 and 1,000 cells:

Uncapped frame rate

Frames per second with vsync off, as the scene grows

Higher is better

  • blenderui GPU
  • blenderui CPU
05001,0001,5002,0001001,0003,000animated cells · fps1,4913099464920276
Open bench
Rust, full results: 100, 1000 and 3000 animated cells
blenderui (GPU)blenderui (CPU)gpui-fastgpui
FPS, 1000 animated cells606049.236.4
CPU per frame, 1000 / 100 cells4.7 / 1.2 ms10.2 / 4.6 ms20.5 / 2.7 ms + GPU27.7 / 4.7 ms + GPU
Uncapped FPS, 100 / 1000 / 3000 cells1491 / 309 / 94649 / 202 / 76--
RAM, 1000 / 100 cells35 / 28 MB24 / 21 MB45 / 47 MB47 / 40 MB
GPU memory19–22 MBnone19–24 MB16–21 MB

The GPU renderer is off by default: Application::new().gpu(true), tk.Tk(gpu=True), bui.set_gpu(True) or BUI_GPU=1. Its shaders evaluate the software raster's formulas: 10 of 172,800 pixels differ by more than 3/255.

Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power

Rust, full results: 100, 1000 and 3000 animated cells
blenderui (GPU)blenderui (CPU)gpui-fastgpui
FPS, 1000 animated cells606049.236.4
CPU per frame, 1000 / 100 cells4.7 / 1.2 ms10.2 / 4.6 ms20.5 / 2.7 ms + GPU27.7 / 4.7 ms + GPU
Uncapped FPS, 100 / 1000 / 3000 cells1491 / 309 / 94649 / 202 / 76--
RAM, 1000 / 100 cells35 / 28 MB24 / 21 MB45 / 47 MB47 / 40 MB
GPU memory19–22 MBnone19–24 MB16–21 MB

The GPU renderer is off by default: Application::new().gpu(true), tk.Tk(gpu=True), bui.set_gpu(True) or BUI_GPU=1. Its shaders evaluate the software raster's formulas: 10 of 172,800 pixels differ by more than 3/255.

What it means:

  • The GPU renderer beats gpui-fast on every measurement. It uses 2.2× less CPU per frame at 100 cells, 4.4× less at 1,000 and 2.8× less at 3,000, where it also runs at nearly twice the frame rate. It uses less RAM and the same GPU memory.
  • The GPU renderer halves blenderui’s own CPU cost (22.0 to 11.6 ms at 3,000 cells). What stays on the CPU is the Rust side: cascade, layout and the paint list.
  • The CPU raster stays the lightest on memory and remains the default.

How: each app measures its own CPU cycles across all threads (Windows’ QueryProcessCycleTime), its frames and its memory, over a 10-second window after a 3-second warm-up. The runner adds GPU utilisation and GPU memory from Windows’ performance counters, because GPU work isn’t process CPU time. “+ GPU” means gpui’s numbers exclude its GPU work, so read them with the GPU columns in the full results.

Fine print: one laptop, one 60 Hz display (which caps every app), an integrated GPU.

JavaScript and React

Startup

What was measured: a small React app (a counter) that quits as soon as its first frame is on screen. Each figure is the median of 12 launches after a warm-up launch (node bench/startup.js).

JavaScript: first frame

A small React app, median of 12 launches

Lower is better

4.9 MBsingle executable with QuickJS

  • QuickJS executablebui build68 ms
  • Bun executablebui build --bun79 ms
  • Bunbun app.js80 ms
  • Node.jsnode app.js108 ms
Open bench
JavaScript startup: a small React app that quits after its first frame, median of 12 launches after a warm-up
First frameLaunch to exitRAM at first frameWhat you ship
QuickJS executable (bui build)68 ms104 ms19 MB4.9 MB
Bun executable (bui build --bun)79 ms147 ms35 MB114 MB
Bun (bun app.js)80 ms152 ms35 MBBun + your app
Node.js (node app.js)108 ms187 ms45 MBNode + your app
Rust (for reference: the benchmark app)5 ms~92 ms3.5 MB

First frame is measured from the runtime's start. Launch to exit is wall time measured from outside, including process creation and teardown.

Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power

JavaScript startup: a small React app that quits after its first frame, median of 12 launches after a warm-up
First frameLaunch to exitRAM at first frameWhat you ship
QuickJS executable (bui build)68 ms104 ms19 MB4.9 MB
Bun executable (bui build --bun)79 ms147 ms35 MB114 MB
Bun (bun app.js)80 ms152 ms35 MBBun + your app
Node.js (node app.js)108 ms187 ms45 MBNode + your app
Rust (for reference: the benchmark app)5 ms~92 ms3.5 MB

First frame is measured from the runtime's start. Launch to exit is wall time measured from outside, including process creation and teardown.

Animation

What was measured: the same scene as the Rust table, in one mode: one cell changes per frame, like a hover or a ticking value. GPU renderer, medians of 3 runs, React’s production build. CPU is the whole process, counted with the cycle counter as for Rust.

  • Plain JS uses @blender-ui/native.
  • React with signals passes the changing values as signals, so the grid renders once.
  • React with state re-renders the grid every frame.

JavaScript: CPU per frame, 3,000 cells

One cell changes per frame; GPU renderer

Lower is better

  • Plain JS
  • React + signals
  • React + state
  • QuickJS
    • Plain JS: 16.3 ms
    • React + signals: 14.9 ms
    • React + state: 51 ms
  • Bun 1.4
    • Plain JS: 13.1 ms
    • React + signals: 13.3 ms
    • React + state: 20.8 ms
  • Node 22
    • Plain JS: 14.4 ms
    • React + signals: 14 ms
    • React + state: 18.9 ms
Open bench
JavaScript animation, 3,000 cells: one cell changes per frame, GPU renderer, medians of 3 runs
3,000 cellsFPSCPU per frameRAM
Rust59.612.0 ms43 MB
QuickJS: plain JS / React with signals / React with state59.1 / 58.7 / 19.716.3 / 14.9 / 51.0 ms56 / 61 / 67 MB
Bun 1.4: plain JS / React with signals / React with state58.8 / 58.4 / 55.813.1 / 13.3 / 20.8 ms80 / 85 / 118 MB
Node 22: plain JS / React with signals / React with state55.8 / 56.7 / 54.814.4 / 14.0 / 18.9 ms88 / 93 / 121 MB

Plain JS uses @blender-ui/native; React with signals renders the grid once; React with state re-renders it every frame. React's production build throughout.

Source: README.md#performance · Ryzen 7 5800U laptop, Windows 11, on AC power

JavaScript animation, 3,000 cells: one cell changes per frame, GPU renderer, medians of 3 runs
3,000 cellsFPSCPU per frameRAM
Rust59.612.0 ms43 MB
QuickJS: plain JS / React with signals / React with state59.1 / 58.7 / 19.716.3 / 14.9 / 51.0 ms56 / 61 / 67 MB
Bun 1.4: plain JS / React with signals / React with state58.8 / 58.4 / 55.813.1 / 13.3 / 20.8 ms80 / 85 / 118 MB
Node 22: plain JS / React with signals / React with state55.8 / 56.7 / 54.814.4 / 14.0 / 18.9 ms88 / 93 / 121 MB

Plain JS uses @blender-ui/native; React with signals renders the grid once; React with state re-renders it every frame. React's production build throughout.

JavaScript animation, 1,000 cells
1,000 cellsFPSCPU per frameRAM
Rust604.8 ms32 MB
QuickJS: plain JS / React with signals / React with state60 / 60 / 56.86.0 / 5.6 / 17.8 ms38 / 40 / 43 MB
Bun: plain JS / React with signals / React with state60 / 60 / 605.2 / 5.2 / 7.5 ms58 / 63 / 81 MB
Node: plain JS / React with signals / React with state60 / 60 / 605.6 / 5.6 / 6.9 ms68 / 71 / 97 MB

What it means:

  • JavaScript costs little over Rust: 0.4–2.4 ms per frame, for sending changes to BUI’s UI thread.
  • Signals make React as cheap as the plain API: the component doesn’t re-render.
  • QuickJS starts fastest and uses the least memory, from a 5 MB file. It has no JIT, so re-rendering a 3,000-element list every frame drops it to 20 FPS. Keep big lists on signals, or build with --bun.

Next steps

Edit this page on GitHub

Last updated