@farmslot/adapter-rn 0.30.0 → 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/android-gfxinfo-performance.d.ts +87 -0
- package/dist/android-gfxinfo-performance.d.ts.map +1 -0
- package/dist/android-gfxinfo-performance.js +451 -0
- package/dist/android-gfxinfo-performance.js.map +1 -0
- package/dist/performance-capture.d.ts +192 -0
- package/dist/performance-capture.d.ts.map +1 -0
- package/dist/performance-capture.js +751 -0
- package/dist/performance-capture.js.map +1 -0
- package/dist/performance-observer.d.ts +9 -0
- package/dist/performance-observer.d.ts.map +1 -0
- package/dist/performance-observer.js +24 -0
- package/dist/performance-observer.js.map +1 -0
- package/dist/runner.d.ts +1 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +38 -4
- package/dist/runner.js.map +1 -1
- package/package.json +9 -4
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,16 @@ All notable changes to `@farmslot/adapter-rn` (published as `@farmslot/expo-reci
|
|
|
6
6
|
|
|
7
7
|
- Active-development baseline; add user-facing changes here before release or package publication.
|
|
8
8
|
|
|
9
|
+
## 0.31.1 - 2026-11-03
|
|
10
|
+
|
|
11
|
+
- Align published dependency pins with the coordinated protocol, recorded-evidence and duplicate-timestamp timeline fixes.
|
|
12
|
+
|
|
13
|
+
## 0.31.0 - 2026-11-02
|
|
14
|
+
|
|
15
|
+
- `app.performance_capture` measures native UI frames on the slot's Android device from `adb shell dumpsys gfxinfo <app> framestats`. `phase: "start"` and `phase: "end"` bound a named window. The end writes `performance/<id>-summary.json`: the frame summary; the lowest FPS over any 500 ms of continuous rendering (recipe-runner's `lowestWindowedFps`, frames up to 100 ms apart), so a slow cadence or steady slow frames fail; and the latency of every `ui.press` and `ui.key_press`, overall and per target. A press in the end node's `shown_markers` runs from the frame that handled the touch past its screen's `[farmslot-perf] shown <screen>` logcat line (streamed with `adb logcat -v monotonic`, the frames' clock), which the app logs after React commits the screen, e.g. from the second `requestAnimationFrame` after focus: a press ends at the end of the last frame that started by two vsyncs after the screen's post-commit marker, or at the marker when that is later. It can over-read by up to ~2 light frames, and could still miss a mount frame that starts more than two vsyncs after the marker (not seen in 24 Pixel 6 presses); the report says so. No line before the next press leaves it untimed. Any other press, and every press in a window whose app logged no such line (noted), runs to the first frame that stands out as its mount within 600 ms, or past that up to 900 ms, after a pause too, a frame with a whole frame budget of UI-thread work; or to the first frame when none does. Devices before Android 12 leave presses untimed and say why. Given a `budget`, the window gets a verdict: failures name the metric, the limit, the measured value, the target and, given a `baseline`, its value. A coverage gap (failed polls, frames gfxinfo overwrote), or frames with no refresh budget, make it `inconclusive` whatever else failed, never a pass. `targets` are reported, never failed on. `<id>-frames.json` keeps the frames the latencies were read from. `phase: "report"` writes one report with the device, the app build and the checkout's HEAD, and fails when a window broke its budget or is inconclusive. A project enables it by declaring the action in its manifest with `"execution_capabilities": []`.
|
|
16
|
+
- New `@farmslot/adapter-rn/performance-observer` export, moved from mm-harness: `createAndroidGfxinfoPerformanceBackend({ serial, packageId, adbPath, shownMarkers })` (no MetaMask package default; `shownMarkers` also reads the app's shown lines from logcat) and `createReactNativeTracePerformanceBackend(client, { kind, platform, markerPrefix })` for a CDP host such as Hermes on iOS. Android frame samples also mark the frames that handled input and their UI-thread time.
|
|
17
|
+
- Align `@farmslot/recipe-runner` 0.46.4 and `@farmslot/agent-runtime` 0.39.26.
|
|
18
|
+
|
|
9
19
|
## 0.30.0 - 2026-11-02
|
|
10
20
|
|
|
11
21
|
- `run` takes `--recording-reason=<why>` and passes it to the recipe runner, which requires a reason to run a UI recipe with `--record-video=off` (for example on a physical phone, where nothing outside the app may be recorded).
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { type FrameSample, type NativeUiPerformanceSourceResult, type PerformanceBackend, type PerformanceCaptureResult, type TraceClockSync, type TraceEvent } from '@farmslot/recipe-runner/runtime/cdp-trace';
|
|
2
|
+
export interface AndroidGfxinfoPerformanceOptions {
|
|
3
|
+
/** adb serial of the device. */
|
|
4
|
+
serial: string;
|
|
5
|
+
/** Application id whose frames are read, e.g. `com.example.app`. */
|
|
6
|
+
packageId: string;
|
|
7
|
+
/** adb binary; `adb` on PATH by default. */
|
|
8
|
+
adbPath?: string;
|
|
9
|
+
/** Where `describe()` reports an adb read it had to skip; console by default. */
|
|
10
|
+
logger?: Pick<Console, 'warn'>;
|
|
11
|
+
/**
|
|
12
|
+
* Also read the `[farmslot-perf] shown <screen>` lines the app logs from
|
|
13
|
+
* `adb logcat` during each capture (`shownMarkers` on the result).
|
|
14
|
+
*/
|
|
15
|
+
shownMarkers?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** An app's `[farmslot-perf] shown <screen>` logcat line. */
|
|
18
|
+
export interface AndroidShownMarker {
|
|
19
|
+
screen: string;
|
|
20
|
+
atEpochMs: number;
|
|
21
|
+
}
|
|
22
|
+
/** A gfxinfo frame: a recipe-runner frame sample plus what the UI thread did in it. */
|
|
23
|
+
export interface AndroidFrameSample extends FrameSample {
|
|
24
|
+
startedAtEpochMs: number;
|
|
25
|
+
/** The frame handled an input event (a touch or key reached the app in it). */
|
|
26
|
+
input?: true;
|
|
27
|
+
/** UI-thread time from the frame's vsync until it handed the frame to the render thread. */
|
|
28
|
+
uiThreadMs?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface AndroidGfxinfoCaptureResult extends PerformanceCaptureResult<'android'> {
|
|
31
|
+
nativeUi: NativeUiPerformanceSourceResult & {
|
|
32
|
+
samples: AndroidFrameSample[];
|
|
33
|
+
};
|
|
34
|
+
/** `missing` when the device's framestats has no InputEventId column (before Android 12). */
|
|
35
|
+
inputEvents: 'available' | 'missing';
|
|
36
|
+
/** With the `shownMarkers` option: the marker lines read, or why logcat gave none. */
|
|
37
|
+
shownMarkers?: {
|
|
38
|
+
markers: AndroidShownMarker[];
|
|
39
|
+
unavailableReason?: string;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** What a report says about the device and app it measured. */
|
|
43
|
+
export interface AndroidDeviceDescription {
|
|
44
|
+
serial: string;
|
|
45
|
+
model?: string;
|
|
46
|
+
androidRelease?: string;
|
|
47
|
+
packageId: string;
|
|
48
|
+
versionName?: string;
|
|
49
|
+
versionCode?: string;
|
|
50
|
+
/** `debug` when the installed package is debuggable. */
|
|
51
|
+
buildType?: 'debug' | 'release';
|
|
52
|
+
lastUpdateTime?: string;
|
|
53
|
+
}
|
|
54
|
+
export interface AndroidGfxinfoPerformanceBackend extends PerformanceBackend<'android'> {
|
|
55
|
+
end(id: string): Promise<AndroidGfxinfoCaptureResult>;
|
|
56
|
+
describe?(): Promise<AndroidDeviceDescription>;
|
|
57
|
+
}
|
|
58
|
+
export interface AndroidFrameRow {
|
|
59
|
+
completedNs: number;
|
|
60
|
+
deadlineNs: number;
|
|
61
|
+
frameIntervalNs: number;
|
|
62
|
+
inputEventId: string;
|
|
63
|
+
intendedVsyncNs: number;
|
|
64
|
+
syncQueuedNs: number;
|
|
65
|
+
vsyncId: string;
|
|
66
|
+
vsyncNs: number;
|
|
67
|
+
}
|
|
68
|
+
export interface AndroidClockSync {
|
|
69
|
+
hostEpochAtDeviceUptimeMs: number;
|
|
70
|
+
uncertaintyMs: number;
|
|
71
|
+
}
|
|
72
|
+
interface ParsedFrameStats {
|
|
73
|
+
bufferCapacityReached: boolean;
|
|
74
|
+
frames: AndroidFrameRow[];
|
|
75
|
+
/** False when a framestats header had no InputEventId column. */
|
|
76
|
+
inputEventColumn: boolean;
|
|
77
|
+
}
|
|
78
|
+
export declare function createAndroidGfxinfoPerformanceBackend(options: AndroidGfxinfoPerformanceOptions): AndroidGfxinfoPerformanceBackend;
|
|
79
|
+
/** `[farmslot-perf] shown <screen>` lines of `adb logcat -v monotonic` output, on the host clock. */
|
|
80
|
+
export declare function parseShownMarkers(output: string, clock: AndroidClockSync): AndroidShownMarker[];
|
|
81
|
+
export declare function androidFrameSample(row: AndroidFrameRow, clock: AndroidClockSync, fallbackBudgetMs: number | undefined): AndroidFrameSample;
|
|
82
|
+
export declare function parseFrameStats(output: string): ParsedFrameStats;
|
|
83
|
+
export declare function buildAndroidFrameTraceEvents(rows: readonly AndroidFrameRow[], clock: AndroidClockSync, fallbackBudgetMs: number | undefined): TraceEvent[];
|
|
84
|
+
/** The host epoch of device uptime 0, from the host-clock midpoint of the read that printed `Uptime:`. */
|
|
85
|
+
export declare function androidClockSync(midpoint: TraceClockSync, deviceUptimeMs: number): AndroidClockSync;
|
|
86
|
+
export {};
|
|
87
|
+
//# sourceMappingURL=android-gfxinfo-performance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android-gfxinfo-performance.d.ts","sourceRoot":"","sources":["../src/android-gfxinfo-performance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
// Android native UI frames for a performance capture: polls
|
|
2
|
+
// `adb shell dumpsys gfxinfo <package> framestats` from the host, maps the
|
|
3
|
+
// device uptime clock onto the host clock, and summarizes the merged frames
|
|
4
|
+
// with recipe-runner's frame metrics. The frames that handled input keep that
|
|
5
|
+
// mark, so a host can time a press from the touch to the frame that answers it.
|
|
6
|
+
// Given `shownMarkers`, it also streams the app's `[farmslot-perf] shown
|
|
7
|
+
// <screen>` logcat lines on the same clock, so a press can be timed by the line
|
|
8
|
+
// its screen logs after React commits it.
|
|
9
|
+
import { execFile, spawn } from 'node:child_process';
|
|
10
|
+
import { promisify } from 'node:util';
|
|
11
|
+
import { clockMidpoint, estimateRefreshBudgetMs, summarizeFrames, } from '@farmslot/recipe-runner/runtime/cdp-trace';
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
13
|
+
const POLL_INTERVAL_MS = 750;
|
|
14
|
+
const MAX_FRAMES = 100_000;
|
|
15
|
+
const GFXINFO_FRAME_BUFFER_SIZE = 120;
|
|
16
|
+
const GFXINFO_SAFE_NEW_FRAME_LIMIT = Math.floor(GFXINFO_FRAME_BUFFER_SIZE * 0.9);
|
|
17
|
+
const MAX_MARKER_LOG_CHARS = 1024 * 1024;
|
|
18
|
+
// React Native logs console output under this tag, in release builds too.
|
|
19
|
+
// `-v monotonic` prints CLOCK_MONOTONIC seconds, the clock of IntendedVsync.
|
|
20
|
+
const SHOWN_MARKER_LINE = /^\s*(\d+\.\d+)\s+\d+\s+\d+\s+[VDIWEF]\s+ReactNativeJS\s*:\s*\[farmslot-perf\] shown (\S+)\s*$/u;
|
|
21
|
+
export function createAndroidGfxinfoPerformanceBackend(options) {
|
|
22
|
+
const serial = options.serial.trim();
|
|
23
|
+
const packageId = options.packageId.trim();
|
|
24
|
+
if (!serial)
|
|
25
|
+
throw new Error('Android performance capture requires the device adb serial.');
|
|
26
|
+
if (!packageId)
|
|
27
|
+
throw new Error('Android performance capture requires the app package id.');
|
|
28
|
+
const adb = options.adbPath ?? 'adb';
|
|
29
|
+
const logger = options.logger ?? console;
|
|
30
|
+
let active;
|
|
31
|
+
return {
|
|
32
|
+
async start(id) {
|
|
33
|
+
if (active) {
|
|
34
|
+
throw new Error('Only one Android performance trace may be active.');
|
|
35
|
+
}
|
|
36
|
+
// Streaming before the clock sync, so no marker after it is missed.
|
|
37
|
+
const markerLog = options.shownMarkers ? startMarkerLog(adb, serial) : undefined;
|
|
38
|
+
let clock;
|
|
39
|
+
try {
|
|
40
|
+
clock = await synchronizeAndroidClock(adb, serial, packageId);
|
|
41
|
+
await adbCommand(adb, serial, ['shell', 'dumpsys', 'gfxinfo', packageId, 'reset']);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (markerLog)
|
|
45
|
+
await stopMarkerLog(markerLog);
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
const capture = {
|
|
49
|
+
clock,
|
|
50
|
+
coverageGapReasons: [],
|
|
51
|
+
frames: new Map(),
|
|
52
|
+
inputEventsMissing: false,
|
|
53
|
+
id,
|
|
54
|
+
...(markerLog ? { markerLog } : {}),
|
|
55
|
+
poll: Promise.resolve(),
|
|
56
|
+
polling: false,
|
|
57
|
+
};
|
|
58
|
+
active = capture;
|
|
59
|
+
capture.timer = setInterval(() => queuePoll(capture), POLL_INTERVAL_MS);
|
|
60
|
+
},
|
|
61
|
+
async end(id) {
|
|
62
|
+
const capture = active;
|
|
63
|
+
if (!capture || capture.id !== id) {
|
|
64
|
+
throw new Error(`Performance capture is not active: ${id}`);
|
|
65
|
+
}
|
|
66
|
+
if (capture.timer)
|
|
67
|
+
clearInterval(capture.timer);
|
|
68
|
+
await capture.poll;
|
|
69
|
+
await queuePoll(capture);
|
|
70
|
+
if (capture.markerLog)
|
|
71
|
+
await stopMarkerLog(capture.markerLog);
|
|
72
|
+
active = undefined;
|
|
73
|
+
return captureResult(capture);
|
|
74
|
+
},
|
|
75
|
+
async close() {
|
|
76
|
+
const capture = active;
|
|
77
|
+
if (!capture)
|
|
78
|
+
return;
|
|
79
|
+
if (capture.timer)
|
|
80
|
+
clearInterval(capture.timer);
|
|
81
|
+
await capture.poll;
|
|
82
|
+
await queuePoll(capture);
|
|
83
|
+
if (capture.markerLog)
|
|
84
|
+
await stopMarkerLog(capture.markerLog);
|
|
85
|
+
active = undefined;
|
|
86
|
+
},
|
|
87
|
+
async describe() {
|
|
88
|
+
const [model, androidRelease, packageInfo] = await Promise.all([
|
|
89
|
+
['shell', 'getprop', 'ro.product.model'],
|
|
90
|
+
['shell', 'getprop', 'ro.build.version.release'],
|
|
91
|
+
['shell', 'dumpsys', 'package', packageId],
|
|
92
|
+
].map((args) => adbCommand(adb, serial, args).catch((error) => {
|
|
93
|
+
// A field the device didn't answer is left out of the report, which
|
|
94
|
+
// still renders; the reason is logged.
|
|
95
|
+
logger.warn(`Android device description skipped adb ${args.join(' ')}: ${errorMessage(error).slice(0, 180)}`);
|
|
96
|
+
return '';
|
|
97
|
+
})));
|
|
98
|
+
const field = (name) => new RegExp(`\\b${name}=([^\\s]+)`, 'u').exec(packageInfo ?? '')?.[1];
|
|
99
|
+
const lastUpdateTime = /lastUpdateTime=([^\n]+)/u.exec(packageInfo ?? '')?.[1]?.trim();
|
|
100
|
+
const flags = /pkgFlags=\[([^\]]*)\]/u.exec(packageInfo ?? '')?.[1];
|
|
101
|
+
return {
|
|
102
|
+
serial,
|
|
103
|
+
packageId,
|
|
104
|
+
...(model?.trim() ? { model: model.trim() } : {}),
|
|
105
|
+
...(androidRelease?.trim() ? { androidRelease: androidRelease.trim() } : {}),
|
|
106
|
+
...(field('versionName') ? { versionName: field('versionName') } : {}),
|
|
107
|
+
...(field('versionCode') ? { versionCode: field('versionCode') } : {}),
|
|
108
|
+
...(flags === undefined
|
|
109
|
+
? {}
|
|
110
|
+
: {
|
|
111
|
+
buildType: flags.includes('DEBUGGABLE') ? 'debug' : 'release',
|
|
112
|
+
}),
|
|
113
|
+
...(lastUpdateTime ? { lastUpdateTime } : {}),
|
|
114
|
+
};
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
function queuePoll(capture) {
|
|
118
|
+
if (capture.polling)
|
|
119
|
+
return capture.poll;
|
|
120
|
+
capture.polling = true;
|
|
121
|
+
capture.poll = (async () => {
|
|
122
|
+
try {
|
|
123
|
+
const output = await adbCommand(adb, serial, [
|
|
124
|
+
'shell',
|
|
125
|
+
'dumpsys',
|
|
126
|
+
'gfxinfo',
|
|
127
|
+
packageId,
|
|
128
|
+
'framestats',
|
|
129
|
+
]);
|
|
130
|
+
const parsed = parseFrameStats(output);
|
|
131
|
+
capture.inputEventsMissing ||= !parsed.inputEventColumn;
|
|
132
|
+
let newFrameCount = 0;
|
|
133
|
+
for (const frame of parsed.frames) {
|
|
134
|
+
if (capture.frames.size >= MAX_FRAMES) {
|
|
135
|
+
addGap(capture, 'Android frame retention limit was reached.');
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
const key = `${frame.vsyncId}:${frame.vsyncNs}`;
|
|
139
|
+
if (!capture.frames.has(key))
|
|
140
|
+
newFrameCount += 1;
|
|
141
|
+
capture.frames.set(key, frame);
|
|
142
|
+
}
|
|
143
|
+
if (parsed.bufferCapacityReached && newFrameCount >= GFXINFO_SAFE_NEW_FRAME_LIMIT) {
|
|
144
|
+
addGap(capture, 'Android gfxinfo may have overwritten frames between polls.');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
addGap(capture, `Android gfxinfo poll failed: ${errorMessage(error).slice(0, 180)}`);
|
|
149
|
+
}
|
|
150
|
+
})().finally(() => {
|
|
151
|
+
capture.polling = false;
|
|
152
|
+
});
|
|
153
|
+
return capture.poll;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function captureResult(capture) {
|
|
157
|
+
const rows = [...capture.frames.values()].sort((first, second) => first.intendedVsyncNs - second.intendedVsyncNs);
|
|
158
|
+
const fallbackBudgetMs = estimateFrameBudgetMs(rows);
|
|
159
|
+
const samples = rows.map((row) => androidFrameSample(row, capture.clock, fallbackBudgetMs));
|
|
160
|
+
const noFrames = samples.length === 0;
|
|
161
|
+
const status = noFrames
|
|
162
|
+
? 'unavailable'
|
|
163
|
+
: capture.coverageGapReasons.length > 0
|
|
164
|
+
? 'partial'
|
|
165
|
+
: 'complete';
|
|
166
|
+
const unavailableReasons = noFrames ? ['No Android gfxinfo frame samples were recorded.'] : [];
|
|
167
|
+
const coverageGapReasons = [...capture.coverageGapReasons];
|
|
168
|
+
const rawTraceEvents = buildAndroidFrameTraceEvents(rows, capture.clock, fallbackBudgetMs);
|
|
169
|
+
return {
|
|
170
|
+
platform: 'android',
|
|
171
|
+
javascript: notApplicableJavaScript(),
|
|
172
|
+
nativeUi: {
|
|
173
|
+
status,
|
|
174
|
+
kind: 'android-gfxinfo-framestats',
|
|
175
|
+
unavailableReasons,
|
|
176
|
+
coverageGapReasons,
|
|
177
|
+
samples,
|
|
178
|
+
summary: summarizeFrames(samples),
|
|
179
|
+
clockSyncUncertaintyMs: capture.clock.uncertaintyMs,
|
|
180
|
+
},
|
|
181
|
+
trace: {
|
|
182
|
+
beginFrameCount: rows.length,
|
|
183
|
+
dataLossOccurred: coverageGapReasons.length > 0,
|
|
184
|
+
drawFrameCount: rows.length,
|
|
185
|
+
overflow: capture.frames.size >= MAX_FRAMES,
|
|
186
|
+
profileChunkCount: 0,
|
|
187
|
+
runTaskCount: 0,
|
|
188
|
+
scope: 'mobile-host',
|
|
189
|
+
totalEventCount: rawTraceEvents.length,
|
|
190
|
+
},
|
|
191
|
+
rawTraceEvents,
|
|
192
|
+
inputEvents: capture.inputEventsMissing ? 'missing' : 'available',
|
|
193
|
+
...(capture.markerLog
|
|
194
|
+
? { shownMarkers: shownMarkersResult(capture.markerLog, capture.clock) }
|
|
195
|
+
: {}),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function startMarkerLog(adb, serial) {
|
|
199
|
+
const child = spawn(adb, ['-s', serial, 'logcat', '-v', 'monotonic', '-T', '1', 'ReactNativeJS:I', '*:S'], { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
200
|
+
const log = { child, closed: Promise.resolve(), output: '' };
|
|
201
|
+
let stderr = '';
|
|
202
|
+
child.stdout?.setEncoding('utf8');
|
|
203
|
+
child.stdout?.on('data', (chunk) => {
|
|
204
|
+
if (log.output.length < MAX_MARKER_LOG_CHARS)
|
|
205
|
+
log.output += chunk;
|
|
206
|
+
});
|
|
207
|
+
child.stderr?.setEncoding('utf8');
|
|
208
|
+
child.stderr?.on('data', (chunk) => {
|
|
209
|
+
stderr += chunk;
|
|
210
|
+
});
|
|
211
|
+
log.closed = new Promise((resolve) => {
|
|
212
|
+
child.once('error', (error) => {
|
|
213
|
+
log.error = `adb logcat failed: ${errorMessage(error).slice(0, 180)}`;
|
|
214
|
+
resolve();
|
|
215
|
+
});
|
|
216
|
+
child.once('close', (code, signal) => {
|
|
217
|
+
// An exit before the stop lost the stream.
|
|
218
|
+
if (!log.stopping) {
|
|
219
|
+
log.error ??= `adb logcat exited ${code ?? signal}: ${stderr.trim().slice(0, 180)}`;
|
|
220
|
+
}
|
|
221
|
+
resolve();
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
return log;
|
|
225
|
+
}
|
|
226
|
+
async function stopMarkerLog(log) {
|
|
227
|
+
log.stopping = true;
|
|
228
|
+
if (log.child.exitCode === null && log.child.signalCode === null)
|
|
229
|
+
log.child.kill('SIGTERM');
|
|
230
|
+
const forced = setTimeout(() => log.child.kill('SIGKILL'), 2_000);
|
|
231
|
+
await log.closed;
|
|
232
|
+
clearTimeout(forced);
|
|
233
|
+
}
|
|
234
|
+
function shownMarkersResult(log, clock) {
|
|
235
|
+
const markers = parseShownMarkers(log.output, clock);
|
|
236
|
+
return {
|
|
237
|
+
markers,
|
|
238
|
+
...(log.error
|
|
239
|
+
? { unavailableReason: log.error }
|
|
240
|
+
: markers.length === 0
|
|
241
|
+
? { unavailableReason: 'logcat had no [farmslot-perf] shown line' }
|
|
242
|
+
: {}),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/** `[farmslot-perf] shown <screen>` lines of `adb logcat -v monotonic` output, on the host clock. */
|
|
246
|
+
export function parseShownMarkers(output, clock) {
|
|
247
|
+
const markers = [];
|
|
248
|
+
for (const line of output.split('\n')) {
|
|
249
|
+
const match = SHOWN_MARKER_LINE.exec(line);
|
|
250
|
+
if (!match?.[1] || !match[2])
|
|
251
|
+
continue;
|
|
252
|
+
markers.push({
|
|
253
|
+
screen: match[2],
|
|
254
|
+
atEpochMs: clock.hostEpochAtDeviceUptimeMs + Number(match[1]) * 1000,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
return markers;
|
|
258
|
+
}
|
|
259
|
+
export function androidFrameSample(row, clock, fallbackBudgetMs) {
|
|
260
|
+
const measurement = frameMeasurement(row, fallbackBudgetMs);
|
|
261
|
+
const startedAtEpochMs = clock.hostEpochAtDeviceUptimeMs + row.intendedVsyncNs / 1_000_000;
|
|
262
|
+
return {
|
|
263
|
+
completedAtEpochMs: startedAtEpochMs + measurement.durationMs,
|
|
264
|
+
durationMs: measurement.durationMs,
|
|
265
|
+
...(measurement.frameBudgetMs ? { frameBudgetMs: measurement.frameBudgetMs } : {}),
|
|
266
|
+
...(measurement.overBudget === undefined ? {} : { overBudget: measurement.overBudget }),
|
|
267
|
+
startedAtEpochMs,
|
|
268
|
+
...(row.inputEventId !== '0' ? { input: true } : {}),
|
|
269
|
+
...(row.syncQueuedNs > row.intendedVsyncNs
|
|
270
|
+
? { uiThreadMs: (row.syncQueuedNs - row.intendedVsyncNs) / 1_000_000 }
|
|
271
|
+
: {}),
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
export function parseFrameStats(output) {
|
|
275
|
+
const frames = [];
|
|
276
|
+
let bufferCapacityReached = false;
|
|
277
|
+
let columnsByName;
|
|
278
|
+
let sectionRowCount = 0;
|
|
279
|
+
let sawHeader = false;
|
|
280
|
+
let inputEventColumn = true;
|
|
281
|
+
for (const line of output.split(/\r?\n/u)) {
|
|
282
|
+
if (line === '---PROFILEDATA---') {
|
|
283
|
+
bufferCapacityReached ||= sectionRowCount >= GFXINFO_FRAME_BUFFER_SIZE;
|
|
284
|
+
columnsByName = undefined;
|
|
285
|
+
sectionRowCount = 0;
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (line.startsWith('Flags,')) {
|
|
289
|
+
columnsByName = new Map(line.split(',').map((name, index) => [name.trim(), index]));
|
|
290
|
+
sawHeader = true;
|
|
291
|
+
inputEventColumn &&= columnsByName.has('InputEventId');
|
|
292
|
+
const missing = ['Flags', 'IntendedVsync', 'Vsync', 'FrameCompleted'].filter((name) => !columnsByName?.has(name));
|
|
293
|
+
if (missing.length > 0) {
|
|
294
|
+
throw new Error(`Unsupported Android gfxinfo framestats header; missing ${missing.join(', ')}.`);
|
|
295
|
+
}
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (!/^\d+,/u.test(line))
|
|
299
|
+
continue;
|
|
300
|
+
if (!columnsByName)
|
|
301
|
+
continue;
|
|
302
|
+
const columns = line.split(',');
|
|
303
|
+
sectionRowCount += 1;
|
|
304
|
+
if (Number(column(columns, columnsByName, 'Flags')) !== 0)
|
|
305
|
+
continue;
|
|
306
|
+
const intendedVsyncNs = Number(column(columns, columnsByName, 'IntendedVsync'));
|
|
307
|
+
const vsyncNs = Number(column(columns, columnsByName, 'Vsync'));
|
|
308
|
+
const deadlineNs = Number(column(columns, columnsByName, 'FrameDeadline') ?? 0);
|
|
309
|
+
const frameIntervalNs = Number(column(columns, columnsByName, 'FrameInterval') ?? 0);
|
|
310
|
+
const completedNs = Number(column(columns, columnsByName, 'FrameCompleted'));
|
|
311
|
+
if (!positiveFinite(intendedVsyncNs) ||
|
|
312
|
+
!positiveFinite(vsyncNs) ||
|
|
313
|
+
!positiveFinite(completedNs) ||
|
|
314
|
+
completedNs <= intendedVsyncNs) {
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
const syncQueuedNs = Number(column(columns, columnsByName, 'SyncQueued') ?? 0);
|
|
318
|
+
frames.push({
|
|
319
|
+
completedNs,
|
|
320
|
+
deadlineNs,
|
|
321
|
+
frameIntervalNs,
|
|
322
|
+
inputEventId: (column(columns, columnsByName, 'InputEventId') ?? '0').trim() || '0',
|
|
323
|
+
intendedVsyncNs,
|
|
324
|
+
syncQueuedNs: Number.isFinite(syncQueuedNs) ? syncQueuedNs : 0,
|
|
325
|
+
vsyncId: String(column(columns, columnsByName, 'FrameTimelineVsyncId') ?? intendedVsyncNs),
|
|
326
|
+
vsyncNs,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
bufferCapacityReached ||= sectionRowCount >= GFXINFO_FRAME_BUFFER_SIZE;
|
|
330
|
+
if (output.includes('---PROFILEDATA---') && !sawHeader) {
|
|
331
|
+
throw new Error('Android gfxinfo framestats header was not found.');
|
|
332
|
+
}
|
|
333
|
+
return { bufferCapacityReached, frames, inputEventColumn };
|
|
334
|
+
}
|
|
335
|
+
function column(columns, columnsByName, name) {
|
|
336
|
+
const index = columnsByName.get(name);
|
|
337
|
+
return index === undefined ? undefined : columns[index];
|
|
338
|
+
}
|
|
339
|
+
export function buildAndroidFrameTraceEvents(rows, clock, fallbackBudgetMs) {
|
|
340
|
+
return rows.flatMap((row, index) => {
|
|
341
|
+
const measurement = frameMeasurement(row, fallbackBudgetMs);
|
|
342
|
+
const args = {
|
|
343
|
+
frameSeqId: row.vsyncId || String(index),
|
|
344
|
+
durationMs: measurement.durationMs,
|
|
345
|
+
...(measurement.frameBudgetMs ? { frameBudgetMs: measurement.frameBudgetMs } : {}),
|
|
346
|
+
...(measurement.overBudget === undefined
|
|
347
|
+
? {}
|
|
348
|
+
: {
|
|
349
|
+
overBudget: measurement.overBudget,
|
|
350
|
+
overBudgetClassification: measurement.classification,
|
|
351
|
+
}),
|
|
352
|
+
...(measurement.classification === 'frame-deadline'
|
|
353
|
+
? { frameDeadlineMissed: measurement.overBudget }
|
|
354
|
+
: {}),
|
|
355
|
+
source: 'android-gfxinfo',
|
|
356
|
+
};
|
|
357
|
+
const intendedVsyncEpochUs = (clock.hostEpochAtDeviceUptimeMs + row.intendedVsyncNs / 1_000_000) * 1000;
|
|
358
|
+
const completedEpochUs = (clock.hostEpochAtDeviceUptimeMs + row.completedNs / 1_000_000) * 1000;
|
|
359
|
+
return [
|
|
360
|
+
{
|
|
361
|
+
name: 'BeginFrame',
|
|
362
|
+
cat: 'disabled-by-default-devtools.timeline.frame',
|
|
363
|
+
ph: 'I',
|
|
364
|
+
ts: intendedVsyncEpochUs,
|
|
365
|
+
pid: 1,
|
|
366
|
+
tid: 1,
|
|
367
|
+
args,
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
name: 'DrawFrame',
|
|
371
|
+
cat: 'disabled-by-default-devtools.timeline.frame',
|
|
372
|
+
ph: 'I',
|
|
373
|
+
ts: completedEpochUs,
|
|
374
|
+
pid: 1,
|
|
375
|
+
tid: 1,
|
|
376
|
+
args,
|
|
377
|
+
},
|
|
378
|
+
];
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
function frameMeasurement(row, fallbackBudgetMs) {
|
|
382
|
+
const durationMs = (row.completedNs - row.intendedVsyncNs) / 1_000_000;
|
|
383
|
+
const frameBudgetMs = row.frameIntervalNs > 0 ? row.frameIntervalNs / 1_000_000 : fallbackBudgetMs;
|
|
384
|
+
if (row.deadlineNs > row.intendedVsyncNs) {
|
|
385
|
+
return {
|
|
386
|
+
classification: 'frame-deadline',
|
|
387
|
+
durationMs,
|
|
388
|
+
...(frameBudgetMs ? { frameBudgetMs } : {}),
|
|
389
|
+
overBudget: row.completedNs > row.deadlineNs,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
return {
|
|
393
|
+
...(frameBudgetMs
|
|
394
|
+
? {
|
|
395
|
+
classification: 'refresh-budget',
|
|
396
|
+
frameBudgetMs,
|
|
397
|
+
overBudget: durationMs > frameBudgetMs * 1.01,
|
|
398
|
+
}
|
|
399
|
+
: {}),
|
|
400
|
+
durationMs,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
async function synchronizeAndroidClock(adb, serial, packageId) {
|
|
404
|
+
const { value: output, ...midpoint } = await clockMidpoint(() => adbCommand(adb, serial, ['shell', 'dumpsys', 'gfxinfo', packageId, 'framestats']));
|
|
405
|
+
const deviceUptimeMs = Number(/Uptime:\s+(\d+)/u.exec(output)?.[1]);
|
|
406
|
+
return androidClockSync(midpoint, deviceUptimeMs);
|
|
407
|
+
}
|
|
408
|
+
/** The host epoch of device uptime 0, from the host-clock midpoint of the read that printed `Uptime:`. */
|
|
409
|
+
export function androidClockSync(midpoint, deviceUptimeMs) {
|
|
410
|
+
if (!positiveFinite(deviceUptimeMs)) {
|
|
411
|
+
throw new Error('Android performance capture could not read device uptime.');
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
hostEpochAtDeviceUptimeMs: midpoint.hostEpochMs - deviceUptimeMs,
|
|
415
|
+
uncertaintyMs: midpoint.uncertaintyMs,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
async function adbCommand(adb, serial, args) {
|
|
419
|
+
const { stdout } = await execFileAsync(adb, ['-s', serial, ...args], {
|
|
420
|
+
encoding: 'utf8',
|
|
421
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
422
|
+
timeout: 10_000,
|
|
423
|
+
});
|
|
424
|
+
return stdout;
|
|
425
|
+
}
|
|
426
|
+
function estimateFrameBudgetMs(rows) {
|
|
427
|
+
return estimateRefreshBudgetMs(rows.map((row) => row.intendedVsyncNs / 1_000_000));
|
|
428
|
+
}
|
|
429
|
+
function notApplicableJavaScript() {
|
|
430
|
+
return {
|
|
431
|
+
applicability: 'not_applicable',
|
|
432
|
+
status: 'unavailable',
|
|
433
|
+
kind: 'not-applicable-mobile-js-tasks',
|
|
434
|
+
unavailableReasons: [],
|
|
435
|
+
coverageGapReasons: [],
|
|
436
|
+
samples: [],
|
|
437
|
+
summary: {},
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
function addGap(capture, reason) {
|
|
441
|
+
if (!capture.coverageGapReasons.includes(reason)) {
|
|
442
|
+
capture.coverageGapReasons.push(reason);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
function positiveFinite(value) {
|
|
446
|
+
return Number.isFinite(value) && value > 0;
|
|
447
|
+
}
|
|
448
|
+
function errorMessage(error) {
|
|
449
|
+
return error instanceof Error ? error.message : String(error);
|
|
450
|
+
}
|
|
451
|
+
//# sourceMappingURL=android-gfxinfo-performance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android-gfxinfo-performance.js","sourceRoot":"","sources":["../src/android-gfxinfo-performance.ts"],"names":[],"mappings":"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"}
|