Skip to content

Commit f044c34

Browse files
feat: use anim+layout+draw sum for primary table
Compute per-frame UI thread time (animation + layout + draw) natively so percentiles are statistically correct. Show this as the primary metric on Android with avg/p95/p99.
1 parent 6c296b4 commit f044c34

3 files changed

Lines changed: 17 additions & 4 deletions

File tree

example/modules/frame-metrics/android/src/main/java/expo/modules/framemetrics/FrameMetricsModule.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ class FrameMetricsModule : Module() {
7474
"avgAnimationTime" to 0.0,
7575
"p95AnimationTime" to 0.0,
7676
"p99AnimationTime" to 0.0,
77+
"avgUiThreadTime" to 0.0,
78+
"p95UiThreadTime" to 0.0,
79+
"p99UiThreadTime" to 0.0,
7780
"avgLayoutTime" to 0.0,
7881
"avgDrawTime" to 0.0,
7982
)
@@ -86,6 +89,7 @@ class FrameMetricsModule : Module() {
8689
val dropped = totalDurations.count { it > 16.67 }
8790

8891
val animDurations = samples.map { it.animationMs }.sorted()
92+
val uiThreadDurations = samples.map { it.animationMs + it.layoutMs + it.drawMs }.sorted()
8993

9094
mapOf(
9195
"avgFrameTime" to avg,
@@ -97,6 +101,9 @@ class FrameMetricsModule : Module() {
97101
"avgAnimationTime" to animDurations.average(),
98102
"p95AnimationTime" to animDurations[(animDurations.size * 0.95).toInt().coerceAtMost(animDurations.size - 1)],
99103
"p99AnimationTime" to animDurations[(animDurations.size * 0.99).toInt().coerceAtMost(animDurations.size - 1)],
104+
"avgUiThreadTime" to uiThreadDurations.average(),
105+
"p95UiThreadTime" to uiThreadDurations[(uiThreadDurations.size * 0.95).toInt().coerceAtMost(uiThreadDurations.size - 1)],
106+
"p99UiThreadTime" to uiThreadDurations[(uiThreadDurations.size * 0.99).toInt().coerceAtMost(uiThreadDurations.size - 1)],
100107
"avgLayoutTime" to samples.map { it.layoutMs }.average(),
101108
"avgDrawTime" to samples.map { it.drawMs }.average(),
102109
)

example/modules/frame-metrics/src/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ interface FrameMetricsResult {
1919
p95AnimationTime?: number;
2020
/** P99 animation time (Android only) */
2121
p99AnimationTime?: number;
22+
/** Average UI thread time: anim + layout + draw (Android only) */
23+
avgUiThreadTime?: number;
24+
/** P95 UI thread time (Android only) */
25+
p95UiThreadTime?: number;
26+
/** P99 UI thread time (Android only) */
27+
p99UiThreadTime?: number;
2228
/** Average layout/measure time (Android only) */
2329
avgLayoutTime?: number;
2430
/** Average draw time (Android only) */

example/src/demos/BenchmarkDemo.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ export function BenchmarkDemo() {
355355
{/* Primary table: animation time (Android) or frame time (iOS) */}
356356
<Text style={styles.subtitleText}>
357357
{isAndroid
358-
? 'Animation evaluator time per frame (ms). Lower is better.'
358+
? 'UI thread time per frame: anim + layout + draw (ms). Lower is better.'
359359
: 'Frame delivery time (ms). Lower is better.'}
360360
</Text>
361361
<View style={styles.tableHeader}>
@@ -368,9 +368,9 @@ export function BenchmarkDemo() {
368368
</View>
369369
{APPROACHES.filter((a) => results[a.key]).map((a) => {
370370
const r = results[a.key]!;
371-
const avg = isAndroid ? r.avgAnimationTime ?? 0 : r.avgFrameTime;
372-
const p95 = isAndroid ? r.p95AnimationTime ?? 0 : r.p95FrameTime;
373-
const p99 = isAndroid ? r.p99AnimationTime ?? 0 : r.p99FrameTime;
371+
const avg = isAndroid ? r.avgUiThreadTime ?? 0 : r.avgFrameTime;
372+
const p95 = isAndroid ? r.p95UiThreadTime ?? 0 : r.p95FrameTime;
373+
const p99 = isAndroid ? r.p99UiThreadTime ?? 0 : r.p99FrameTime;
374374
return (
375375
<View key={a.key} style={styles.tableRow}>
376376
<Text

0 commit comments

Comments
 (0)