Skip to content

Commit 67572ef

Browse files
committed
report first steady ping after initial resources loaded
1 parent babbfd7 commit 67572ef

File tree

3 files changed

+81
-40
lines changed

3 files changed

+81
-40
lines changed

front_end/core/host/RNPerfMetrics.ts

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class RNPerfMetrics {
2929
#telemetryInfo: Object = {};
3030
// map of panel location to panel name
3131
#currentPanels = new Map<PanelLocation, string>();
32+
#initialResourcesLoadedInfo: null|{count: number, time: number} = null;
3233

3334
isEnabled(): boolean {
3435
return globalThis.enableReactNativePerfMetrics === true;
@@ -186,13 +187,10 @@ class RNPerfMetrics {
186187
});
187188
}
188189

189-
allInitialDeveloperResourcesLoadingFinished(count: number): void {
190-
this.sendEvent({
191-
eventName: 'DeveloperResource.AllInitialLoadingFinished',
192-
params: {
193-
count,
194-
},
195-
});
190+
initialResourcesLoaded(info: {count: number, time: number}): void {
191+
// eslint-disable-next-line no-console
192+
console.info('Initial %d resources are loaded at %sms since launch', info.count, info.time);
193+
this.#initialResourcesLoadedInfo = info;
196194
}
197195

198196
fuseboxSetClientMetadataStarted(): void {
@@ -215,10 +213,30 @@ class RNPerfMetrics {
215213
}
216214
}
217215

218-
firstSteadyPing(): void {
216+
tryReportingCdpLowRoundtrip(cdpLowRoundtripStartTime: number): boolean {
217+
if (this.#initialResourcesLoadedInfo === null) {
218+
return false;
219+
}
220+
221+
// if the roundtrip is fine for a long time, just take the initial resources loading time
222+
// if it got better only after the initial resources were loaded, take the cdp low roundtrip time instead
223+
const startupTime = Math.max(cdpLowRoundtripStartTime, this.#initialResourcesLoadedInfo.time);
224+
225+
// eslint-disable-next-line no-console
226+
console.info('The app had a low CDP roundtrip at %sms since launch', cdpLowRoundtripStartTime);
227+
// eslint-disable-next-line no-console
228+
console.info('Startup time is %sms', startupTime);
229+
219230
this.sendEvent({
220-
eventName: 'FirstSteadyPing',
231+
eventName: 'StartUpFinished',
232+
params: {
233+
bundleCount: this.#initialResourcesLoadedInfo.count,
234+
duration: startupTime,
235+
initialResourcesLoadedTime: this.#initialResourcesLoadedInfo.time,
236+
cdpLowRoundtripStartTime,
237+
}
221238
});
239+
return true;
222240
}
223241

224242
heapSnapshotStarted(): void {
@@ -432,13 +450,6 @@ export type DeveloperResourceLoadingFinishedEvent = Readonly<{
432450
}>,
433451
}>;
434452

435-
export type AllInitialDeveloperResourcesLoadingFinished = Readonly<{
436-
eventName: 'DeveloperResource.AllInitialLoadingFinished',
437-
params: Readonly<{
438-
count: number,
439-
}>,
440-
}>;
441-
442453
export type FuseboxSetClientMetadataStartedEvent = Readonly<{
443454
eventName: 'FuseboxSetClientMetadataStarted',
444455
}>;
@@ -511,16 +522,22 @@ export type StackTraceFrameUrlResolutionFailed = Readonly<{
511522
}>,
512523
}>;
513524

514-
export type FirstSteadyPing = Readonly<{
515-
eventName: 'FirstSteadyPing',
525+
export type StartUpFinished = Readonly<{
526+
eventName: 'StartUpFinished',
527+
params: Readonly<{
528+
bundleCount: number,
529+
duration: number,
530+
initialResourcesLoadedTime: number,
531+
cdpLowRoundtripStartTime: number,
532+
}>,
516533
}>;
517534

518535
export type ReactNativeChromeDevToolsEvent =
519536
EntrypointLoadingStartedEvent|EntrypointLoadingFinishedEvent|DebuggerReadyEvent|BrowserVisibilityChangeEvent|
520537
BrowserErrorEvent|RemoteDebuggingTerminatedEvent|DeveloperResourceLoadingStartedEvent|
521-
DeveloperResourceLoadingFinishedEvent|AllInitialDeveloperResourcesLoadingFinished|FuseboxSetClientMetadataStartedEvent|
538+
DeveloperResourceLoadingFinishedEvent|FuseboxSetClientMetadataStartedEvent|
522539
FuseboxSetClientMetadataFinishedEvent|MemoryPanelActionStartedEvent|MemoryPanelActionFinishedEvent|
523540
PanelShownEvent|PanelClosedEvent|StackTraceSymbolicationSucceeded|StackTraceSymbolicationFailed|
524-
StackTraceFrameUrlResolutionSucceeded|StackTraceFrameUrlResolutionFailed|FirstSteadyPing;
541+
StackTraceFrameUrlResolutionSucceeded|StackTraceFrameUrlResolutionFailed|StartUpFinished;
525542

526543
export type DecoratedReactNativeChromeDevToolsEvent = CommonEventFields&ReactNativeChromeDevToolsEvent;

front_end/core/sdk/PageResourceLoader.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ const UIStrings = {
2929
const str_ = i18n.i18n.registerUIStrings('core/sdk/PageResourceLoader.ts', UIStrings);
3030
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
3131

32+
const MS_WAIT_ENSURING_ALL_RESOUCES_ARE_LOADED = 3000;
33+
3234
export interface ExtensionInitiator {
3335
target: null;
3436
frameId: null;
@@ -82,7 +84,8 @@ interface LoadQueueEntry {
8284
*/
8385
export class PageResourceLoader extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
8486
#currentlyLoading = 0;
85-
#reportedAllInitialResourcesLoaded = false;
87+
#initialResourcesLoadedTimeout: number|null = null;
88+
#reportedInitialResourcesLoaded = false;
8689
#currentlyLoadingPerTarget = new Map<Protocol.Target.TargetID|'main', number>();
8790
readonly #maxConcurrentLoads: number;
8891
#pageResources = new Map<string, PageResource>();
@@ -356,13 +359,22 @@ export class PageResourceLoader extends Common.ObjectWrapper.ObjectWrapper<Event
356359
Host.rnPerfMetrics.developerResourceLoadingFinished(
357360
parsedURL, Host.UserMetrics.DeveloperResourceLoaded.FALLBACK_AFTER_FAILURE, result);
358361

359-
// Will be decreased to 0 right after this function in "releaseLoadSlot".
360-
// Tracking it here so it is next to the rest of "rnPerfMetrics" in this file.
361-
const allResourcesLoaded = this.#currentlyLoading === 1;
362-
if (allResourcesLoaded && !this.#reportedAllInitialResourcesLoaded) {
363-
Host.rnPerfMetrics.allInitialDeveloperResourcesLoadingFinished(this.getNumberOfResources().resources);
364-
this.#reportedAllInitialResourcesLoaded = true;
362+
// Wait for several seconds to ensure no new resources were loaded,
363+
// possibly by the resources that just finished loading
364+
const resourceLoadingTime = performance.now();
365+
if (this.#initialResourcesLoadedTimeout) {
366+
window.clearTimeout(this.#initialResourcesLoadedTimeout);
365367
}
368+
this.#initialResourcesLoadedTimeout = window.setTimeout(() => {
369+
const allResourcesLoaded = this.#currentlyLoading === 0;
370+
if (allResourcesLoaded && !this.#reportedInitialResourcesLoaded) {
371+
Host.rnPerfMetrics.initialResourcesLoaded({
372+
count: this.getNumberOfResources().resources,
373+
time: Math.round(resourceLoadingTime)
374+
});
375+
this.#reportedInitialResourcesLoaded = true;
376+
}
377+
}, MS_WAIT_ENSURING_ALL_RESOUCES_ARE_LOADED);
366378

367379
return result;
368380
}

front_end/entrypoints/inspector_main/InspectorMain.ts

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import * as UI from '../../ui/legacy/legacy.js';
1515

1616
import nodeIconStyles from './nodeIcon.css.js';
1717

18-
const COOLDOWN_BETWEEN_PINGS = 3000;
19-
const LOW_PING_THRESHOLD = 200;
18+
const MS_BETWEEN_ROUNDTRIP_MEASUREMENTS = 3000;
19+
const MS_MAX_LOW_ROUNDTRIP = 200;
2020

2121
const UIStrings = {
2222
/**
@@ -49,7 +49,7 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
4949
let inspectorMainImplInstance: InspectorMainImpl;
5050

5151
export class InspectorMainImpl implements Common.Runnable.Runnable {
52-
#consecutiveLowPing = 0;
52+
#consecutiveLowRoundtrips = 0;
5353

5454
static instance(opts: {
5555
forceNew: boolean|null,
@@ -62,25 +62,37 @@ export class InspectorMainImpl implements Common.Runnable.Runnable {
6262
return inspectorMainImplInstance;
6363
}
6464

65-
async #measureMainConnectionPing(debuggerModel: SDK.DebuggerModel.DebuggerModel): Promise<void> {
65+
async #measureMainConnectionRoundtrip(debuggerModel: SDK.DebuggerModel.DebuggerModel): Promise<void> {
6666
if (!debuggerModel.debuggerEnabled()) {
6767
return;
6868
}
6969

7070
const startMs = Date.now();
71+
// Issues and waits for a response from a simple "Debugger.enable" when the debugger is enabled
72+
// which noops and retuns a truthy response:
73+
// https://github.com/facebook/hermes/blob/ae235193b9329867afaa2838183cbffa34aca098/API/hermes/cdp/DebuggerDomainAgent.cpp#L224-L228
74+
// https://github.com/facebook/hermes/blob/ae235193b9329867afaa2838183cbffa34aca098/API/hermes/cdp/DebuggerDomainAgent.cpp#L183-L185
75+
// It measures the round trip time for CDP message after being queued in the CDP queue in each direction.
7176
await debuggerModel.syncDebuggerId();
72-
const ping = Date.now() - startMs;
77+
const roundtripTime = Date.now() - startMs;
7378

74-
if (ping > LOW_PING_THRESHOLD) {
75-
this.#consecutiveLowPing = 0;
79+
if (roundtripTime > MS_MAX_LOW_ROUNDTRIP) {
80+
this.#consecutiveLowRoundtrips = 0;
7681
} else {
77-
this.#consecutiveLowPing++;
82+
this.#consecutiveLowRoundtrips++;
7883
}
7984

80-
if (this.#consecutiveLowPing > 1) {
81-
Host.rnPerfMetrics.firstSteadyPing();
82-
} else {
83-
setTimeout(() => void this.#measureMainConnectionPing(debuggerModel), COOLDOWN_BETWEEN_PINGS);
85+
let reportedLowRoundrip = false;
86+
if (this.#consecutiveLowRoundtrips >= 2) {
87+
reportedLowRoundrip = Host.rnPerfMetrics.tryReportingCdpLowRoundtrip(
88+
Math.round(performance.now() - ((this.#consecutiveLowRoundtrips - 1) * MS_BETWEEN_ROUNDTRIP_MEASUREMENTS))
89+
);
90+
}
91+
92+
if (!reportedLowRoundrip) {
93+
setTimeout(() => {
94+
void this.#measureMainConnectionRoundtrip(debuggerModel);
95+
}, MS_BETWEEN_ROUNDTRIP_MEASUREMENTS);
8496
}
8597
}
8698

@@ -123,7 +135,7 @@ export class InspectorMainImpl implements Common.Runnable.Runnable {
123135

124136
const debuggerModel = target.model(SDK.DebuggerModel.DebuggerModel);
125137
if (debuggerModel) {
126-
void this.#measureMainConnectionPing(debuggerModel);
138+
void this.#measureMainConnectionRoundtrip(debuggerModel);
127139
if (waitForDebuggerInPage) {
128140
if (!debuggerModel.isReadyToPause()) {
129141
await debuggerModel.once(SDK.DebuggerModel.Events.DebuggerIsReadyToPause);

0 commit comments

Comments
 (0)