diff --git a/packages/commands/measure/src/__tests__/__snapshots__/measure.test.tsx.snap b/packages/commands/measure/src/__tests__/__snapshots__/measure.test.tsx.snap
index cbf25089..be3847f5 100644
--- a/packages/commands/measure/src/__tests__/__snapshots__/measure.test.tsx.snap
+++ b/packages/commands/measure/src/__tests__/__snapshots__/measure.test.tsx.snap
@@ -11,8 +11,8 @@ Average Test Runtime
Time taken to run the test.
Can be helpful to measure Time To Interactive of your app, if the test is checking app start for instance.
Average FPS
-60 FPS
-Frame Per Second. Your app should display 60 Frames Per Second to give an impression of fluidity. This number should be close to 60, otherwise it will seem laggy.
+120 FPS
+Frame Per Second. Your app should display 120 Frames Per Second to give an impression of fluidity. This number should be close to 120, otherwise it will seem laggy.
See
@@ -34,7 +34,7 @@ RN JS Thread
0.5
s
-High CPU usage by a single process can cause app unresponsiveness, even with low overall CPU usage. For instance, an overworked JS thread in a React Native app may lead to unresponsiveness despite maintaining 60 FPS.
+High CPU usage by a single process can cause app unresponsiveness, even with low overall CPU usage. For instance, an overworked JS thread in a React Native app may lead to unresponsiveness despite maintaining 120 FPS.
Average RAM usage
375.8 MB
If an app consumes a large amount of RAM (random-access memory), it can impact the overall performance of the device and drain the battery more quickly.
@@ -106,11 +106,11 @@ Frame rate (FPS)
"data": [
{
"x": 0,
- "y": 60
+ "y": 120
},
{
"x": 500,
- "y": 60
+ "y": 120
}
]
}
@@ -752,7 +752,7 @@ exports[`flashlight measure interactive it displays measures: Web app with measu
- 60 FPS
+ 120 FPS
- Frame Per Second. Your app should display 60 Frames Per Second to give an impression of fluidity. This number should be close to 60, otherwise it will seem laggy.
+ Frame Per Second. Your app should display 120 Frames Per Second to give an impression of fluidity. This number should be close to 120, otherwise it will seem laggy.
See
- High CPU usage by a single process can cause app unresponsiveness, even with low overall CPU usage. For instance, an overworked JS thread in a React Native app may lead to unresponsiveness despite maintaining 60 FPS.
+ High CPU usage by a single process can cause app unresponsiveness, even with low overall CPU usage. For instance, an overworked JS thread in a React Native app may lead to unresponsiveness despite maintaining 120 FPS.
@@ -1100,11 +1100,11 @@ exports[`flashlight measure interactive it displays measures: Web app with measu
"data": [
{
"x": 0,
- "y": 60
+ "y": 120
},
{
"x": 500,
- "y": 60
+ "y": 120
}
]
}
@@ -3813,7 +3813,7 @@ Time taken to run the test.
Can be helpful to measure Time To Interactive of your app, if the test is checking app start for instance.
Average FPS
-
-Frame Per Second. Your app should display 60 Frames Per Second to give an impression of fluidity. This number should be close to 60, otherwise it will seem laggy.
+Frame Per Second. Your app should display 120 Frames Per Second to give an impression of fluidity. This number should be close to 120, otherwise it will seem laggy.
See
@@ -3829,7 +3829,7 @@ An app might run at high frame rates, such as 60 FPS or higher, but might be usi
High CPU Usage
-
Impacted threads:
-High CPU usage by a single process can cause app unresponsiveness, even with low overall CPU usage. For instance, an overworked JS thread in a React Native app may lead to unresponsiveness despite maintaining 60 FPS.
+High CPU usage by a single process can cause app unresponsiveness, even with low overall CPU usage. For instance, an overworked JS thread in a React Native app may lead to unresponsiveness despite maintaining 120 FPS.
Average RAM usage
-
If an app consumes a large amount of RAM (random-access memory), it can impact the overall performance of the device and drain the battery more quickly.
@@ -4146,7 +4146,7 @@ exports[`flashlight measure interactive it displays measures: Web app with no me
- Frame Per Second. Your app should display 60 Frames Per Second to give an impression of fluidity. This number should be close to 60, otherwise it will seem laggy.
+ Frame Per Second. Your app should display 120 Frames Per Second to give an impression of fluidity. This number should be close to 120, otherwise it will seem laggy.
See
- High CPU usage by a single process can cause app unresponsiveness, even with low overall CPU usage. For instance, an overworked JS thread in a React Native app may lead to unresponsiveness despite maintaining 60 FPS.
+ High CPU usage by a single process can cause app unresponsiveness, even with low overall CPU usage. For instance, an overworked JS thread in a React Native app may lead to unresponsiveness despite maintaining 120 FPS.
diff --git a/packages/commands/measure/src/server/ServerSocketConnectionApp.tsx b/packages/commands/measure/src/server/ServerSocketConnectionApp.tsx
index ee48be93..677fda09 100644
--- a/packages/commands/measure/src/server/ServerSocketConnectionApp.tsx
+++ b/packages/commands/measure/src/server/ServerSocketConnectionApp.tsx
@@ -30,15 +30,14 @@ export const ServerSocketConnectionApp = ({ socket, url }: { socket: SocketType;
setState((state) =>
addNewResultReducer(
state,
- `${bundleId}${state.results.length > 0 ? ` (${state.results.length + 1})` : ""}`
+ `${bundleId}${state.results.length > 0 ? ` (${state.results.length + 1})` : ""}`,
+ profiler.detectDeviceRefreshRate()
)
);
socket.on(SocketEvents.START, async () => {
- const refreshRate = profiler.detectDeviceRefreshRate();
setState({
isMeasuring: true,
- refreshRate,
});
if (!state.bundleId) {
@@ -46,6 +45,7 @@ export const ServerSocketConnectionApp = ({ socket, url }: { socket: SocketType;
return;
}
+ profiler.installProfilerOnDevice();
performanceMeasureRef.current = new PerformanceMeasurer(state.bundleId, {
recordOptions: {
record: false,
diff --git a/packages/commands/measure/src/server/socket/socketInterface.ts b/packages/commands/measure/src/server/socket/socketInterface.ts
index adaee861..6c70fba2 100644
--- a/packages/commands/measure/src/server/socket/socketInterface.ts
+++ b/packages/commands/measure/src/server/socket/socketInterface.ts
@@ -5,7 +5,6 @@ export interface SocketData {
isMeasuring: boolean;
bundleId: string | null;
results: TestCaseResult[];
- refreshRate: number;
}
export interface ServerToClientEvents {
@@ -46,7 +45,6 @@ export enum SocketEvents {
RESET = "reset",
AUTODETECT_BUNDLE_ID = "autodetectBundleId",
SET_BUNDLE_ID = "setBundleId",
- AUTODETECT_REFRESH_RATE = "autodetectRefreshRate",
UPDATE_STATE = "updateState",
SEND_ERROR = "sendError",
PING = "ping",
diff --git a/packages/commands/measure/src/server/socket/socketState.ts b/packages/commands/measure/src/server/socket/socketState.ts
index 945c633c..890465ef 100644
--- a/packages/commands/measure/src/server/socket/socketState.ts
+++ b/packages/commands/measure/src/server/socket/socketState.ts
@@ -7,7 +7,6 @@ export const useSocketState = (socket: SocketType) => {
isMeasuring: false,
bundleId: null,
results: [],
- refreshRate: 60,
});
const setState = (
@@ -47,7 +46,11 @@ export const updateMeasuresReducer = (state: SocketData, measures: Measure[]): S
],
});
-export const addNewResultReducer = (state: SocketData, name: string): SocketData => ({
+export const addNewResultReducer = (
+ state: SocketData,
+ name: string,
+ refreshRate: number
+): SocketData => ({
...state,
results: [
...state.results,
@@ -56,7 +59,7 @@ export const addNewResultReducer = (state: SocketData, name: string): SocketData
iterations: [],
status: "SUCCESS",
specs: {
- refreshRate: state.refreshRate,
+ refreshRate,
},
},
],
diff --git a/packages/commands/measure/src/server/useBundleIdControls.ts b/packages/commands/measure/src/server/useBundleIdControls.ts
index fba9b315..5a18c84a 100644
--- a/packages/commands/measure/src/server/useBundleIdControls.ts
+++ b/packages/commands/measure/src/server/useBundleIdControls.ts
@@ -30,19 +30,9 @@ export const useBundleIdControls = (
}
});
- socket.on(SocketEvents.AUTODETECT_REFRESH_RATE, () => {
- stop();
-
- const refreshRate = profiler.detectDeviceRefreshRate();
- setState({
- refreshRate,
- });
- });
-
return () => {
socket.removeAllListeners(SocketEvents.SET_BUNDLE_ID);
socket.removeAllListeners(SocketEvents.AUTODETECT_BUNDLE_ID);
- socket.removeAllListeners(SocketEvents.AUTODETECT_REFRESH_RATE);
};
}, [setState, socket, stop]);
};
diff --git a/packages/commands/measure/src/webapp/useMeasures.ts b/packages/commands/measure/src/webapp/useMeasures.ts
index f4d5b7e3..ce4db76c 100644
--- a/packages/commands/measure/src/webapp/useMeasures.ts
+++ b/packages/commands/measure/src/webapp/useMeasures.ts
@@ -15,10 +15,8 @@ export const useMeasures = () => {
return {
bundleId: state?.bundleId ?? null,
- refreshRate: state?.refreshRate ?? 60,
autodetect: () => {
socket.emit(SocketEvents.AUTODETECT_BUNDLE_ID);
- socket.emit(SocketEvents.AUTODETECT_REFRESH_RATE);
},
setBundleId: (bundleId: string) => {
socket.emit(SocketEvents.SET_BUNDLE_ID, bundleId);
diff --git a/packages/commands/test/src/__tests__/__snapshots__/PerformanceMeasurer.test.ts.snap b/packages/commands/test/src/__tests__/__snapshots__/PerformanceMeasurer.test.ts.snap
index 8c5dfbda..d68153b8 100644
--- a/packages/commands/test/src/__tests__/__snapshots__/PerformanceMeasurer.test.ts.snap
+++ b/packages/commands/test/src/__tests__/__snapshots__/PerformanceMeasurer.test.ts.snap
@@ -59,7 +59,7 @@ exports[`PerformanceMeasurer handles c++ errors correctly 1`] = `
"queued-work-loo (3)": 0,
},
},
- "fps": 60,
+ "fps": 120,
"ram": 375.76171875,
"time": 500,
},
@@ -120,7 +120,7 @@ exports[`PerformanceMeasurer handles c++ errors correctly 1`] = `
"queued-work-loo (3)": 0,
},
},
- "fps": 60,
+ "fps": 120,
"ram": 375.76171875,
"time": 1000,
},
diff --git a/packages/commands/test/src/utils/test/mockChildProcess.ts b/packages/commands/test/src/utils/test/mockChildProcess.ts
index 2cd03449..f885fb3d 100644
--- a/packages/commands/test/src/utils/test/mockChildProcess.ts
+++ b/packages/commands/test/src/utils/test/mockChildProcess.ts
@@ -21,6 +21,8 @@ jest.mock("child_process", () => {
return "arm64-v8a";
case "adb shell getprop ro.build.version.sdk":
return "30";
+ case 'adb shell dumpsys display | grep -E "mRefreshRate|DisplayDeviceInfo"':
+ return "fps=120";
case "adb shell setprop debug.hwui.profile true":
case "adb shell atrace --async_stop 1>/dev/null":
case "adb shell chmod 755 /data/local/tmp/BAMPerfProfiler":
diff --git a/packages/platforms/android/src/commands/atrace/pollFpsUsage.ts b/packages/platforms/android/src/commands/atrace/pollFpsUsage.ts
index 3f9a201e..ccde7b0b 100644
--- a/packages/platforms/android/src/commands/atrace/pollFpsUsage.ts
+++ b/packages/platforms/android/src/commands/atrace/pollFpsUsage.ts
@@ -28,10 +28,6 @@ export const parseLine = (
};
};
-const TARGET_FRAME_RATE = refreshRateManager.getRefreshRate();
-const TARGET_FRAME_TIME = 1000 / TARGET_FRAME_RATE;
-Logger.info(`Target frame rate: ${TARGET_FRAME_RATE} Hz`);
-
export class FrameTimeParser {
private methodStartedCount = 0;
private doFrameStartedTimeStamp: number | null = null;
@@ -97,6 +93,9 @@ ${error instanceof Error ? error.message : error}`);
static getFps(frameTimes: number[], timeInterval: number, uiCpuUsage: number) {
const frameCount = frameTimes.length;
+ const TARGET_FRAME_RATE = refreshRateManager.getRefreshRate();
+ const TARGET_FRAME_TIME = 1000 / TARGET_FRAME_RATE;
+
const totalFrameTime = frameTimes.reduce(
(sum, time) => sum + Math.max(TARGET_FRAME_TIME, time),
0
diff --git a/packages/platforms/android/src/commands/detectCurrentDeviceRefreshRate.ts b/packages/platforms/android/src/commands/detectCurrentDeviceRefreshRate.ts
index 6936828d..15c01cb2 100644
--- a/packages/platforms/android/src/commands/detectCurrentDeviceRefreshRate.ts
+++ b/packages/platforms/android/src/commands/detectCurrentDeviceRefreshRate.ts
@@ -1,16 +1,26 @@
import { executeCommand } from "./shell";
import { Logger } from "@perf-profiler/logger";
+const DEFAULT_FRAME_RATE = 60;
+
function deviceRefreshRateManager() {
- let refreshRate = 60; // Default to 60 fps
+ let refreshRate: number | null = null;
return {
- getRefreshRate: () => refreshRate,
+ isInitialized: () => refreshRate !== null,
+ getRefreshRate: () => {
+ if (refreshRate === null) {
+ throw new Error("Refresh rate not initialized");
+ }
+ return refreshRate;
+ },
setRefreshRate: () => {
try {
refreshRate = detectCurrentDeviceRefreshRate();
+ Logger.info(`Target frame rate: ${refreshRate} Hz`);
} catch (e) {
Logger.error(`Could not detect device refresh rate: ${e}`);
+ refreshRate = DEFAULT_FRAME_RATE;
}
},
};
@@ -47,6 +57,5 @@ export const detectCurrentDeviceRefreshRate = () => {
};
const refreshRateManager = deviceRefreshRateManager();
-refreshRateManager.setRefreshRate();
export { refreshRateManager };
diff --git a/packages/platforms/android/src/commands/platforms/AndroidProfiler.ts b/packages/platforms/android/src/commands/platforms/AndroidProfiler.ts
index 2ae87fd5..5c3712c7 100644
--- a/packages/platforms/android/src/commands/platforms/AndroidProfiler.ts
+++ b/packages/platforms/android/src/commands/platforms/AndroidProfiler.ts
@@ -12,6 +12,7 @@ export class AndroidProfiler extends UnixProfiler {
installProfilerOnDevice(): void {
super.installProfilerOnDevice();
+ if (!refreshRateManager.isInitialized()) refreshRateManager.setRefreshRate();
if (!this.aTraceProcess) this.startATrace();
}