Measure the performance of any Android app 🚀
- 🙅 No installation required, supports even production app
- ✨ Generates beautiful web report (like this Flatlist/Flashlist comparison)
- 💻 Via CLI, e2e test or Flipper plugin
- Getting started with the automated profiler
- Using Appium
- Running in CI
- Flipper Plugin
- CLI
- Getting FPS Data
- Contributing
Getting started with the automated profiler
- Install the profiler
yarn add --dev @perf-profiler/e2e
- Create a TS script including a performance test
For instance, here we'll be testing the start up performance of the app for 10 iterations:
// performance.ts
import { execSync } from "child_process";
import { TestCase, measurePerformance } from "@perf-profiler/e2e";
// `npx @perf-profiler/profiler getCurrentApp` will display info for the current app
const bundleId = "com.reactnativefeed";
const stopApp = () => execSync(`adb shell am force-stop ${bundleId}`);
const startApp = () =>
execSync(
`adb shell monkey -p ${bundleId} -c android.intent.category.LAUNCHER 1`
);
const startTestCase: TestCase = {
duration: 10000,
beforeTest: () => {
stopApp();
},
run: () => {
startApp();
},
};
const test = async () => {
const { measures, writeResults } = await measurePerformance(
bundleId,
startTestCase,
10
);
writeResults();
};
test();
- Run your script:
npx ts-node performance.ts
- Open the JSON file generated in the web profiler:
npx @perf-profiler/web-reporter results.json
Using Appium
Appium is an e2e testing framework which works with no installation required on your app.
We created @bam.tech/appium-helper
to simplify its use and you can use integrate the performance measures like so:
- Install
yarn add --dev @perf-profiler/e2e @bam.tech/appium-helper
- Create a test file including a performance test
import { AppiumDriver } from "@bam.tech/appium-helper";
import { TestCase, measurePerformance } from "@perf-profiler/e2e";
// `npx @perf-profiler/profiler getCurrentApp` will display info for the current app
const bundleId = "com.reactnativefeed";
const appActivity = `com.reactnativefeed.MainActivity`,
test("e2e", async () => {
const driver = await AppiumDriver.create({
appPackage: bundleId,
appActivity,
});
const startApp: TestCase = {
beforeTest: async () => {
driver.stopApp();
await driver.wait(3000);
},
run: async () => {
driver.startApp();
await driver.findElementByText("As you may");
},
duration: 10000,
};
const { writeResults } = await measurePerformance(bundleId, startApp);
writeResults();
});
- Run
npx appium
in one tab - Run
yarn jest yourtest
in a separate tab - Open the JSON file generated in the web profiler:
npx @perf-profiler/web-reporter results.json
Running in CI
To run in CI, you'll need the CI to be connected to an Android device. An emulator running on the CI will likely be too slow, so it's best to be connected to a device farm cloud. The profiler needs full adb
access, so only few device cloud are compatible:
Our choice is AWS Device Farm but some other options should work as well (though they haven't been tested):
- Saucelabs with Entreprise plan and Virtual USB
- Genymotion Cloud (using emulators will not accurately reproduce the performance of a real device)
AWS Device Farm
We've added a neat tool to seamlessly run your tests on AWS Device Farm and get the measures back:
export AWS_ACCESS_KEY_ID="ADD YOUR AWS KEY ID HERE" AWS_SECRET_ACCESS_KEY="ADD YOUR AWS SECRET HERE"
# Run from your root folder, containing `node_modules`
npx @perf-profiler/aws-device-farm runTest \
--apkPath app-release.apk \
--deviceName "A10s" \
--testCommand "yarn jest appium"
Flipper Plugin
prod-profiler.mp4
Install
Search for android-performance-profiler
in the Flipper marketplace
CLI
You can profile directly in CLI with:
npx @perf-profiler/profiler profile --fps --ram --threadNames "(mqt_js)" "UI Thread"
You can also use a custom script:
Via Custom script
For instance:
import {
detectCurrentAppBundleId,
getAverageCpuUsage,
getPidId,
Measure,
pollPerformanceMeasures,
} from "@perf-profiler/profiler";
const { bundleId } = detectCurrentAppBundleId();
const pid = getPidId(bundleId);
const measures: Measure[] = [];
const polling = pollPerformanceMeasures(pid, (measure) => {
measures.push(measure);
console.log(`JS Thread CPU Usage: ${measure.perName["(mqt_js)"]}%`);
});
setTimeout(() => {
polling.stop();
const averageCpuUsage = getAverageCpuUsage(measures);
console.log(`Average CPU Usage: ${averageCpuUsage}%`);
}, 10000);
Contributing
web-reporter
At the root of the repo:
yarn
yarn tsc --build --w
and run in another terminal:
yarn workspace @perf-profiler/web-reporter start
Then in packages/web-reporter/src/App.tsx
, uncomment the lines to add your own measures:
// Uncomment with when locally testing
// eslint-disable-next-line @typescript-eslint/no-var-requires
testCaseResults = [require("../measures.json")];
You should now be able to open the local server
Run yarn jest Plugin -u
after modifications.