mirror of
https://github.com/kuhyx/todo-app.git
synced 2026-11-10 19:07:02 +01:00
Renames this repo's markdown onto README.md / CLAUDE*.md / DOCS*.md / TODO*.md so a future session can tell a live task from a finished record without reading the file to find out. TODO files carry the literal "REMOVE ME AFTER FINISH" and are deleted when the work lands. Enforced by the md-naming pre-commit hook and CI workflow, both delegating to the shared gate in kuhyx/utils so this repo's idea of a valid name cannot drift from every other repo's. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A47aX5DJwmA3QFn3pkEWi7
74 lines
3.7 KiB
Markdown
74 lines
3.7 KiB
Markdown
# Linux desktop performance: measured findings
|
|
|
|
Investigation date: 2026-07-20. Machine: Arch, X11 + i3, NVIDIA proprietary
|
|
610.43.03, RTX 3090. DP-0 = 3840x2160 @144 Hz (primary), HDMI-0 = 2560x1440
|
|
@144 Hz. Flutter 3.44.6 stable.
|
|
|
|
## Conclusion
|
|
|
|
**The previous session was right: Flutter's Linux desktop embedder cannot drive
|
|
this machine's 4K display, and switching technology for the desktop app is
|
|
justified.**
|
|
|
|
Two independent defects, neither fixable in application code:
|
|
|
|
1. **Hard 60 FPS cap.** Flutter's Linux embedder schedules frames at a fixed
|
|
60 FPS regardless of the monitor (upstream
|
|
[#183703](https://github.com/flutter/flutter/issues/183703), P2, no PR).
|
|
2. **~20 FPS at 4K.** Far worse, and the actual cause of the reported lag. At
|
|
3840x2160 the app achieves 18.6 fps while each frame costs only ~3 ms of a
|
|
16.7 ms budget. The stock `flutter create` counter app behaves identically,
|
|
so this is the toolkit, not todo.
|
|
|
|
Application code is not implicated anywhere: build (Dart) time is 0.1-0.4 ms in
|
|
every configuration and at every window size measured.
|
|
|
|
An earlier revision of this document concluded that a rewrite was **not**
|
|
warranted. That conclusion was based only on defect 1 and is superseded by the
|
|
4K measurements below.
|
|
|
|
## Evidence
|
|
|
|
Measured with a temporary in-app instrument (`lib/frame_stats.dart`, armed by
|
|
`TODO_FRAME_STATS=1`) reporting frame-to-frame cadence alongside build/raster
|
|
times, driven by a perpetual animation so frames are produced continuously.
|
|
|
|
| Configuration | Cadence p50 | Achieved | build p50 | raster p50 |
|
|
|---|---|---|---|---|
|
|
| Release, Skia GL (default) | 16.67 ms | **60.0 fps** | 0.30 ms | 1.50 ms |
|
|
| Release, Impeller | 16.67 ms | **60.0 fps** | 0.19 ms | 1.33 ms |
|
|
| Release, Impeller + Vulkan | 16.67 ms | **60.0 fps** | 0.26 ms | 1.33 ms |
|
|
| Driver vsync off (`__GL_SYNC_TO_VBLANK=0`) | 16.67 ms | **60.0 fps** | 0.28 ms | 1.40 ms |
|
|
| picom compositor + Skia GL | 16.67 ms | **60.0 fps** | 0.27 ms | 1.62 ms |
|
|
| picom compositor + Impeller | 16.67 ms | **60.0 fps** | 0.30 ms | 1.44 ms |
|
|
| **Stock `flutter create` app** (no todo code) | 16.67 ms | **60.0 fps** | 0.12 ms | 1.35 ms |
|
|
| **Same Flutter code as a web build, in Chrome** | **7.00 ms** | **142.9 fps** | — | — |
|
|
|
|
> **Retracted:** an earlier revision of this table had a "real typing +
|
|
> scrolling" row. It was invalid. It used `xdotool type --window`, which sends
|
|
> synthetic `XSendEvent` keystrokes that GTK/Flutter ignore; the keystrokes
|
|
> actually landed in a different application. That run measured an idle app.
|
|
> Interaction is measured properly in the next section instead.
|
|
|
|
Confounds on the web row, stated for honesty: it ran on HDMI-0 (1440p@144) with
|
|
a game occupying the 4K GPU, which is why its p95 was 13.90 ms. The desktop
|
|
60.0 fps lock, by contrast, is clean, jitter-free and monitor-independent, so
|
|
the comparison's conclusion holds — but the web number should be re-confirmed on
|
|
the 4K monitor with the GPU idle.
|
|
|
|
Key readings:
|
|
|
|
- Cadence p50 **equals** p95 at exactly 16.67 ms in every desktop run — a hard
|
|
lock with zero jitter, not contention.
|
|
- Total per-frame work is ~1.8 ms against a 6.94 ms 144 Hz budget. The renderer
|
|
has **74% headroom at 144 Hz** and 89% at 60 Hz.
|
|
- Under real typing and scrolling, **one** frame exceeded the 144 Hz budget in
|
|
14 seconds and **zero** exceeded 60 Hz. There is no dropped-frame jank.
|
|
- The stock counter app behaves identically, so this is not `todo`'s code.
|
|
- Neither renderer choice, nor driver vsync, nor a compositor moves the number.
|
|
|
|
---
|
|
|
|
Part 2 — the interaction-lag half of this investigation, and the decision that came out of it — is in
|
|
[desktop-performance-interaction-lag.md](desktop-performance-interaction-lag.md).
|