A draggable debug panel that shows how long each stage of a frame takes, and which one is slowing you down.
input, anim, layout, draw on the main thread, then sync, command,
swap on the render thread, and gpuframehud-metrics collects and reports with no window and no
permissiondebugImplementation leaves out the panel, its provider and the
SYSTEM_ALERT_WINDOW it declaresdependencies {
debugImplementation("com.timkrest:framehud:0.18.1")
}
There is nothing to call. A ContentProvider starts the panel, and it follows whichever activity
has focus.
Requires minSdk 24. Frame phases come from FrameMetrics; GPU timings need API 31+ and a driver
that reports them.
debugImplementation already keeps everything out of a release build. Add framehud-noop only if
you call FrameHud outside src/debug, because a release build still has to compile those lines.
It mirrors the API with empty bodies:
releaseImplementation("com.timkrest:framehud-noop:0.18.1")
ui 59/s · 16.7ms 58 FPS
⚠ layout 8.4 ms
CPU now avg peak
input 0.1 0.2 1.1
anim 0.3 0.4 2.0
layout 7.9 8.4 22.3 ◀
draw 1.2 1.4 6.7
RENDER
sync 0.4 0.5 1.9
command 0.6 0.7 3.1
swap 0.2 0.3 1.4
GPU
gpu 2.1 2.4 9.8
delay 0.3 0.4 2.2
other 0.3 0.3
TOTAL 11.3 12.6 38.6
over -5.4 -4.1 21.9
pipe:cpu 9.5 10.4
win jank 7.5% p95 18.4 max 22.3
ses p50 11.8 p95 19.6 p99 28.4
ses 4312f 1m12s jank 6.4% frz0 run3
lost 2.1s
mem 84/256 ▲96 · nat 37 ▲41 MB
gc x3 · 18 ms
therm none · hr 0.68
cpu 62% ▲140 · pss 214 ▲240 MB
thr 38 ▲44 · fd 210 ▲260
The header shows the main thread's Choreographer tick rate, the frame budget and FPS. The verdict
under it names the row to look at, and ◀ marks that row. Columns read now avg peak: the current
frame, the average over the window, and the peak since the last reset. A tap steps through the three
views — every row, the frame rows on their own, and one line; holding freezes the readings, and ▤
switches to the worst screens and back.
Reading the panel explains every row and what to do when one turns red.
androidTestImplementation("com.timkrest:framehud-instrumentation:0.18.1")
@get:Rule val noJank = DetectJankAfterTestSuccess(JankThresholds(maxJankPercent = 2f))
Thresholds can be fixed, as above, or relative to a baseline of earlier runs on the same device.
./gradlew :sample:installDebug
Load stresses the frame pipeline with six toggles, Readouts shows every reading taken from the flows instead of the panel, and Session is what a QA run ends with: baselines, past runs, incidents, export.
111 commits
Kotlin
100.0%
A draggable debug panel that shows how long each stage of a frame takes, and which one is slowing you down.
input, anim, layout, draw on the main thread, then sync, command,
swap on the render thread, and gpuframehud-metrics collects and reports with no window and no
permissiondebugImplementation leaves out the panel, its provider and the
SYSTEM_ALERT_WINDOW it declaresdependencies {
debugImplementation("com.timkrest:framehud:0.18.1")
}
There is nothing to call. A ContentProvider starts the panel, and it follows whichever activity
has focus.
Requires minSdk 24. Frame phases come from FrameMetrics; GPU timings need API 31+ and a driver
that reports them.
debugImplementation already keeps everything out of a release build. Add framehud-noop only if
you call FrameHud outside src/debug, because a release build still has to compile those lines.
It mirrors the API with empty bodies:
releaseImplementation("com.timkrest:framehud-noop:0.18.1")
ui 59/s · 16.7ms 58 FPS
⚠ layout 8.4 ms
CPU now avg peak
input 0.1 0.2 1.1
anim 0.3 0.4 2.0
layout 7.9 8.4 22.3 ◀
draw 1.2 1.4 6.7
RENDER
sync 0.4 0.5 1.9
command 0.6 0.7 3.1
swap 0.2 0.3 1.4
GPU
gpu 2.1 2.4 9.8
delay 0.3 0.4 2.2
other 0.3 0.3
TOTAL 11.3 12.6 38.6
over -5.4 -4.1 21.9
pipe:cpu 9.5 10.4
win jank 7.5% p95 18.4 max 22.3
ses p50 11.8 p95 19.6 p99 28.4
ses 4312f 1m12s jank 6.4% frz0 run3
lost 2.1s
mem 84/256 ▲96 · nat 37 ▲41 MB
gc x3 · 18 ms
therm none · hr 0.68
cpu 62% ▲140 · pss 214 ▲240 MB
thr 38 ▲44 · fd 210 ▲260
The header shows the main thread's Choreographer tick rate, the frame budget and FPS. The verdict
under it names the row to look at, and ◀ marks that row. Columns read now avg peak: the current
frame, the average over the window, and the peak since the last reset. A tap steps through the three
views — every row, the frame rows on their own, and one line; holding freezes the readings, and ▤
switches to the worst screens and back.
Reading the panel explains every row and what to do when one turns red.
androidTestImplementation("com.timkrest:framehud-instrumentation:0.18.1")
@get:Rule val noJank = DetectJankAfterTestSuccess(JankThresholds(maxJankPercent = 2f))
Thresholds can be fixed, as above, or relative to a baseline of earlier runs on the same device.
./gradlew :sample:installDebug
Load stresses the frame pipeline with six toggles, Readouts shows every reading taken from the flows instead of the panel, and Session is what a QA run ends with: baselines, past runs, incidents, export.
111 commits
Kotlin
100.0%