Skip to content

Commit 712ff51

Browse files
committed
perf: record ime first-render benchmark baseline
1 parent 425a7be commit 712ff51

21 files changed

Lines changed: 514 additions & 82 deletions

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ mode, etc.). Tool-specific files like [`CLAUDE.md`](CLAUDE.md) carry
1111
## Read this first
1212

1313
1. [`PROJECT_CONTEXT.md`](PROJECT_CONTEXT.md) — single-page consolidated
14-
project context. Pins the load-bearing invariants, the v1.8.158
14+
project context. Pins the load-bearing invariants, the v1.8.159
1515
stack, the module layout, the roadmap-file routing, and the current
1616
sprint state.
1717
2. [`ARCHITECTURE.md`](ARCHITECTURE.md) — contributor-facing module,
@@ -80,7 +80,7 @@ and Definition-of-Done evidence.
8080

8181
`gradle.properties` `projectVersionCode` + `projectVersionName` bump
8282
in lockstep with the release-notes commit. Tag the release commit at the
83-
same time. Local and remote release tags are current through `v1.8.158`
83+
same time. Local and remote release tags are current through `v1.8.159`
8484
as of 2026-05-18.
8585

8686
### 5. Definition of Done (per [ROADMAP.md](ROADMAP.md) §15)

ARCHITECTURE.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SwiftFloris Architecture
22

3-
Last updated: 2026-05-18, against the v1.8.158 codebase.
3+
Last updated: 2026-05-18, against the v1.8.159 codebase.
44

55
This file is the fast architectural map for contributors. It is intentionally
66
shorter than `ROADMAP.md` and more code-oriented than `PROJECT_CONTEXT.md`.
@@ -30,9 +30,11 @@ The active Gradle modules are declared in `settings.gradle.kts`.
3030
| `:lib:compose` | Shared Compose resource, layout, and UI helpers |
3131
| `:lib:kotlin` | Pure Kotlin utility code |
3232
| `:lib:snygg` | Snygg theme parser and runtime engine |
33+
| `:benchmark` | AndroidX Macrobenchmark module plus adb-driven benchmark harness target |
3334

34-
`benchmark/` and `lib/native/` are present on disk but are not active Gradle
35-
modules in the current settings file.
35+
`:benchmark` is included in settings for Macrobenchmark and adb performance
36+
harnesses. `:lib:native` remains present on disk but inactive until a native
37+
addon/runtime slice intentionally revives it.
3638

3739
## Runtime Entrypoints
3840

IMPROVEMENT_PLAN.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,19 +216,28 @@ Acceptance criteria:
216216

217217
### 7. Performance Instrumentation
218218

219-
Status: Planned
219+
Status: In progress
220220
Priority: P1
221221

222222
Goal: Add lightweight evidence around typing responsiveness and startup quality.
223223

224224
Tasks:
225-
- [ ] Measure keyboard cold start and first render.
225+
- [x] Measure keyboard cold start and first render.
226226
- [ ] Measure first suggestion latency.
227227
- [ ] Measure dictionary load and preload time.
228228
- [ ] Measure candidate row recomposition hotspots.
229229
- [ ] Measure theme switching cost.
230230
- [ ] Measure backup/restore duration on representative archives.
231-
- [ ] Add repeatable profiling notes using adb, simpleperf, Perfetto, or Compose tracing where appropriate.
231+
- [x] Add repeatable profiling notes using adb, simpleperf, Perfetto, or Compose tracing where appropriate.
232+
233+
Progress:
234+
- 2026-05-18 (v1.8.159): `:benchmark` is active again, the benchmark
235+
variant has a local-only input activity, and
236+
`tools/benchmark-ime-first-render.ps1` records repeatable adb first-render
237+
runs. Samsung SM-S938B / Android 16 baseline: `am start -W` median
238+
`TotalTime` 31.0 ms, median `WaitTime` 34.0 ms, and benchmark-only
239+
`swiftfloris.ime.firstRenderMs` median 18.335469 ms over five runs.
240+
Evidence: `docs/benchmark-results/baseline-2026-05-18-ime-first-render.json`.
232241

233242
Acceptance criteria:
234243
- Performance claims are backed by repeatable commands.

PROJECT_CONTEXT.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
**Maintained at root for fast onboarding.**
44
**Last consolidated:** 2026-05-18 (from the autonomous research run at
55
[`.ai/research/2026-05-17/`](.ai/research/2026-05-17/) plus follow-up slices
6-
through v1.8.158).
6+
through v1.8.159).
77

88
This file is the single fastest read for an AI session, new contributor, or
99
maintainer-context refresh. It does **not** replace [ROADMAP.md](ROADMAP.md),
@@ -45,7 +45,7 @@ them requires changing both the relevant code *and* the gate.
4545
If a proposed change conflicts with any of these, the answer is "move that
4646
feature into an addon" — never "loosen the invariant."
4747

48-
## 3. Stack at HEAD (v1.8.158)
48+
## 3. Stack at HEAD (v1.8.159)
4949

5050
```
5151
Kotlin 2.3.21 · Compose BOM 2026.05.00 · Material 3 + material-kolor 4.1.1
@@ -195,7 +195,7 @@ and in [`ROADMAP.md` §0 v5.5 + v5.4](ROADMAP.md). Net deltas to invariants:
195195
at `docs/outreach/2026-05-17-swiftkey-migration/` covering
196196
AlternativeTo, BGR, Android Authority, and r/Swiftkey.
197197

198-
**v1.8.104 – v1.8.158** ships the seventh research-pass privacy,
198+
**v1.8.104 – v1.8.159** ships the seventh research-pass privacy,
199199
voice, clipboard, NLP, visual-regression, Addons trust/asset/catalog layer, and
200200
input-behavior testability plus conservative lint/dependency cleanup layer.
201201
v1.8.104 – v1.8.110 closed the
@@ -436,6 +436,14 @@ v1.8.158 closes the accessibility manual-QA documentation item.
436436
keyboard label, candidate-row announcement, high-font-scale, non-color-state,
437437
and theme/layout checks for changes that touch settings or keyboard surfaces.
438438

439+
v1.8.159 starts Performance Instrumentation Workstream 7. `:benchmark` is
440+
active again on AGP 9, the benchmark variant has a local-only input activity,
441+
and `tools/benchmark-ime-first-render.ps1` records adb-driven cold IME
442+
first-render baselines. The first committed SM-S938B / Android 16 run records
443+
five iterations with `am start -W` medians of `TotalTime` 31.0 ms and
444+
`WaitTime` 34.0 ms, plus benchmark-only `swiftfloris.ime.firstRenderMs`
445+
median 18.335469 ms.
446+
439447
## 4. Module layout
440448

441449
```
@@ -445,7 +453,7 @@ lib/color — color math
445453
lib/compose — Compose helpers
446454
lib/kotlin — pure-Kotlin utilities
447455
lib/snygg — Snygg theme engine
448-
:benchmark — Macrobenchmark (present on disk, NOT in active settings)
456+
:benchmark — Macrobenchmark + adb benchmark harness (active in settings)
449457
:lib:native — placeholder for future native add-ons (commented out)
450458
```
451459

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SwiftFloris
22

3-
![Version](https://img.shields.io/badge/version-v1.8.158-blue) ![License](https://img.shields.io/badge/license-Apache%202.0-green) ![Platform](https://img.shields.io/badge/platform-Android%208.0+-orange) ![Network](https://img.shields.io/badge/network-none-lightgrey) ![SwiftKey migration](https://img.shields.io/badge/SwiftKey%20migration-window%20closes%202026--05--31-red)
3+
![Version](https://img.shields.io/badge/version-v1.8.159-blue) ![License](https://img.shields.io/badge/license-Apache%202.0-green) ![Platform](https://img.shields.io/badge/platform-Android%208.0+-orange) ![Network](https://img.shields.io/badge/network-none-lightgrey) ![SwiftKey migration](https://img.shields.io/badge/SwiftKey%20migration-window%20closes%202026--05--31-red)
44

55
**SwiftFloris** is a privacy-first Android keyboard, forked from FlorisBoard and pushed toward SwiftKey-class multilingual typing without the cloud. It ships under Apache-2.0, holds no `INTERNET` permission, and binds zero accounts.
66

@@ -44,7 +44,7 @@
4444
4545
## Highlights
4646

47-
| Area | What's in v1.8.158 | Privacy posture |
47+
| Area | What's in v1.8.159 | Privacy posture |
4848
|------|-------------------|-----------------|
4949
| **Autocorrect / prediction** | SCOWL 117k English dictionary, SymSpell d1+d2, bigram + trigram next-word, capitalization-aware completions, contraction handling, instant-remember user-dictionary overlay | On-device |
5050
| **Multilingual typing** | Bilingual subtype presets (EN+ES / EN+FR / EN+DE), per-token Latin language identification, top-two straddle guard, sentence-local context scoring | On-device |
@@ -124,7 +124,7 @@ Project-internal docs all live in the repository:
124124
- [`docs/VOICE_COMMANDS.md`](docs/VOICE_COMMANDS.md) — built-in and custom voice-command grammar reference.
125125
- [`docs/addons/dictionary-pack-spec.md`](docs/addons/dictionary-pack-spec.md) — external dictionary-pack APK descriptor and validation contract.
126126
- [`IMPROVEMENT_PLAN.md`](IMPROVEMENT_PLAN.md) — execution-focused quality / UX / a11y / perf / test / delivery plan.
127-
- [`ROADMAP.md`](ROADMAP.md) — current and historical roadmap (v5.55).
127+
- [`ROADMAP.md`](ROADMAP.md) — current and historical roadmap (v5.56).
128128
- `RELEASE_NOTES_v*.md` — per-release notes, one file per version, in the repository root.
129129

130130
## Architecture & Stack
@@ -149,7 +149,7 @@ lib/color — color math
149149
lib/compose — Compose helpers
150150
lib/kotlin — pure-Kotlin utilities
151151
lib/snygg — Snygg theme engine
152-
:benchmark — Macrobenchmark module (present on disk, not yet wired in settings)
152+
:benchmark — Macrobenchmark + adb benchmark harness (active in settings)
153153
:lib:native — placeholder for future native add-ons (commented out)
154154
```
155155

@@ -261,13 +261,13 @@ Six Macrobenchmark trace sections are emitted from production code paths:
261261
- `swiftfloris.dict.load` (`loadSpecificDictionary`)
262262
- `swiftfloris.nlp.symspell.build` (lazy index init)
263263

264-
Real device-number collection is tracked in [`docs/BENCHMARKS.md`](docs/BENCHMARKS.md). The repository deliberately does not publish hand-wavy latency tables; numbers go in the benchmark doc with the device, OS build, and trace section that produced them.
264+
Real device-number collection is tracked in [`docs/BENCHMARKS.md`](docs/BENCHMARKS.md). The v1.8.159 SM-S938B / Android 16 baseline records `am start -W` medians of `TotalTime` 31.0 ms and `WaitTime` 34.0 ms, plus benchmark-only `swiftfloris.ime.firstRenderMs` median 18.335469 ms. The repository deliberately does not publish hand-wavy latency tables; numbers go in the benchmark doc with the device, OS build, and trace section or log marker that produced them.
265265

266266
## Testing
267267

268268
- **Unit tests:** Kotest, run with `./gradlew test`. Last reported HEAD: 998+ tests (post-v1.8.40), expanding with each release. The v1.8.47 hardening pass added defensive tests around dictionary import limits, voice-model atomic install, theme asset traversal, and quick-action serializer fallback.
269269
- **Visual regression:** Roborazzi 1.60.0, plugin alias active. CI runs `:app:verifyRoborazziDebug` on every push / PR as a hard gate, backed by committed baselines for the maintainer chip, SwiftKey High Contrast, Aurora Animated, and Settings -> Addons surfaces.
270-
- **Macrobenchmark:** trace sections wired in production hot paths; device-number capture is tracked separately.
270+
- **Macrobenchmark:** `:benchmark` is wired for AndroidX trace/frame runs, and the adb first-render harness records repeatable IME cold-start baselines.
271271
- **No-network gate:** CI verifies the absence of `INTERNET` permission on every build.
272272
- **Repo hygiene gate:** CI runs `scripts/check-no-root-crash-logs.sh` so root
273273
`hs_err_pid*.log` / `replay_pid*.log` files cannot be committed.
@@ -276,6 +276,7 @@ Real device-number collection is tracked in [`docs/BENCHMARKS.md`](docs/BENCHMAR
276276

277277
The full release stream lives in the `RELEASE_NOTES_v*.md` files in the repository root, and on [GitHub Releases](https://github.com/SysAdminDoc/SwiftFloris/releases).
278278

279+
- **v1.8.159** (2026-05-18) — IME first-render benchmark baseline: `:benchmark` is active again, a benchmark-only input activity drives cold IME view creation, and SM-S938B / Android 16 first-render numbers are committed under `docs/benchmark-results/`. ([notes](RELEASE_NOTES_v1.8.159.md))
279280
- **v1.8.158** (2026-05-18) — Accessibility manual QA notes: contributor and accessibility docs now list TalkBack traversal, key-label, candidate-row, font-scale, non-color-state, and theme/layout checks. ([notes](RELEASE_NOTES_v1.8.158.md))
280281
- **v1.8.157** (2026-05-18) — Non-color state indicators: shared success/progress/neutral cards and extension-import row icons make readiness, progress, cancellation, and completion visible without relying on color alone. ([notes](RELEASE_NOTES_v1.8.157.md))
281282
- **v1.8.156** (2026-05-18) — Theme contrast audit: bundled keyboard/candidate/dialog styles and settings warning/error/dialog palettes now have selector-level AA coverage; low-contrast enter-key variants and card secondary text were tightened. ([notes](RELEASE_NOTES_v1.8.156.md))
@@ -424,7 +425,7 @@ limitations under the License.
424425

425426
## Status
426427

427-
🚀 **Active development.** Current release: **v1.8.158** (2026-05-18). Migration window for SwiftKey users closes **2026-05-31** — 13 days from this release.
428+
🚀 **Active development.** Current release: **v1.8.159** (2026-05-18). Migration window for SwiftKey users closes **2026-05-31** — 13 days from this release.
428429

429430
---
430431

RELEASE_NOTES_v1.8.159.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# SwiftFloris v1.8.159
2+
3+
Date: 2026-05-18
4+
5+
## IME First-Render Benchmark Baseline
6+
7+
This release starts Performance Instrumentation Workstream 7 by reactivating
8+
the benchmark module and committing the first repeatable cold IME first-render
9+
baseline.
10+
11+
### Changed
12+
13+
- Re-enabled `:benchmark` in `settings.gradle.kts` and updated the benchmark
14+
module for the AGP 9 / Gradle 9 build.
15+
- Retargeted benchmark sources at the `.bench` app id and added shared device
16+
helpers for selecting the benchmark IME and launching benchmark activities.
17+
- Added a benchmark-only `BenchmarkInputActivity` so adb and Macrobenchmark
18+
runs can show the IME without touching production UI.
19+
- Added a benchmark-build-only `SwiftFlorisPerf` first-render log marker in
20+
`FlorisImeService.onCreateInputView`.
21+
- Added `tools/benchmark-ime-first-render.ps1`, which installs the benchmark
22+
APK, selects the benchmark IME, records five adb runs, restores the previous
23+
input method, and writes JSON to `docs/benchmark-results/`.
24+
25+
### Baseline
26+
27+
Samsung SM-S938B / Android 16 (SDK 36), five iterations:
28+
29+
- `am start -W` median `TotalTime`: 31.0 ms.
30+
- `am start -W` median `WaitTime`: 34.0 ms.
31+
- `SwiftFlorisPerf` median `swiftfloris.ime.firstRenderMs`: 18.335469 ms.
32+
33+
Evidence: `docs/benchmark-results/baseline-2026-05-18-ime-first-render.json`.
34+
35+
### Tests
36+
37+
- `git diff --check` passed.
38+
- `.\gradlew.bat :app:assembleBenchmark :benchmark:assembleBenchmark` passed.
39+
- `pwsh -NoProfile -ExecutionPolicy Bypass -File .\tools\benchmark-ime-first-render.ps1 -Iterations 5` passed on device `R5CY34G070L` and restored the previous IME.
40+
- `.\gradlew.bat :app:testDebugUnitTest :app:lintDebug :app:assembleDebug` passed.
41+
42+
### Definition of Done
43+
44+
- Version bumped to `1.8.159` / code `1959`.
45+
- `README.md`, `ROADMAP.md`, `PROJECT_CONTEXT.md`, `ARCHITECTURE.md`,
46+
`AGENTS.md`, `IMPROVEMENT_PLAN.md`, and `docs/BENCHMARKS.md` updated.

0 commit comments

Comments
 (0)