Skip to content

Commit a8cffb7

Browse files
committed
Add Simpleperf app_profiler options and use --android.simpleperf.
Extend commands.simpleperf.start() to support for Simpleperf's general app_profiler options. This allows users to pass options like Simpleperf's -nb flag which skips generating a binary cache i.e. a dumped symbols directory (this is useful when symbols are not needed after profiling or when Simpleperf is failing to create a binary cache). Replace --android.ndk with --android.simpleperf. --android.simpleperf is more flexible as it expects the path directly to the directory containing Simpleperf (whereas --android.ndk expects the directory to the NDK installation, which is then used to find Simpleperf via a hardcoded relative path: simpleperf/app_profiler.py). This is particularly useful when Simpleperf is provided standalone, without the NDK (as is the case with a Simpleperf repack).
1 parent 3208168 commit a8cffb7

File tree

4 files changed

+34
-13
lines changed

4 files changed

+34
-13
lines changed

lib/core/engine/command/simpleperf.js

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { isAndroidConfigured } from '../../../android/index.js';
1414

1515
const log = getLogger('browsertime.command.simpleperf');
1616

17-
const defaultOptions =
17+
const defaultRecordOptions =
1818
'--call-graph fp --duration 240 -f 1000 --trace-offcpu -e cpu-clock';
1919

2020
/**
@@ -72,7 +72,11 @@ export class SimplePerfProfiler {
7272
* @throws {Error} Throws an error if app_profiler.py fails to execute.
7373
*/
7474

75-
async start(profilerOptions = defaultOptions, dirName = 'simpleperf') {
75+
async start(
76+
profilerOptions = [],
77+
recordOptions = defaultRecordOptions,
78+
dirName = 'simpleperf'
79+
) {
7680
if (!isAndroidConfigured(this.options)) {
7781
throw new Error('Simpleperf profiling is only available on Android.');
7882
}
@@ -83,6 +87,8 @@ export class SimplePerfProfiler {
8387
let dirname = `${dirName}-${this.index}`;
8488
let counter = 0;
8589

90+
this.profilerOptions = profilerOptions;
91+
8692
while (true) {
8793
log.info(`Checking if ${dirname} exists...`);
8894

@@ -102,13 +108,14 @@ export class SimplePerfProfiler {
102108
this.options.browser === 'firefox'
103109
? this.options.firefox?.android?.package
104110
: this.options.chrome?.android?.package;
105-
let ndkPath = this.options.androidNDK;
106-
let cmd = `${ndkPath}/simpleperf/app_profiler.py`;
111+
let simpleperfPath = this.options.androidSimpleperf;
112+
let cmd = join(simpleperfPath, 'app_profiler.py');
107113
let args = [
114+
...profilerOptions,
108115
'-p',
109116
packageName,
110117
'-r',
111-
profilerOptions,
118+
recordOptions,
112119
'--log',
113120
'debug',
114121
'-o',
@@ -167,11 +174,24 @@ export class SimplePerfProfiler {
167174
stderrStream.on('data', data => {
168175
const dataStr = data.toString();
169176
log.info(dataStr);
177+
// Resolve immediately if -nb or --skip_collect_binaries is passed
178+
// into the app_profiler options as a binary cache will not be produced.
179+
if (
180+
this.profilerOptions.includes('-nb') ||
181+
this.profilerOptions.includes('--skip_collect_binaries')
182+
) {
183+
stderrStream.removeAllListeners('data');
184+
return resolve();
185+
}
170186
if (/profiling is finished./.test(dataStr)) {
171187
stderrStream.removeAllListeners('data');
172-
// There is no way to specify the output of binary_cache, so manually move
173-
// it into the data directory.
174-
renameSync('binary_cache', join(this.dataDir, 'binary_cache'));
188+
// There is no way to specify the output of binary_cache,
189+
// so manually move it (if it exists) into the data directory.
190+
if (existsSync('binary_cache')) {
191+
renameSync('binary_cache', join(this.dataDir, 'binary_cache'));
192+
} else {
193+
log.info('binary_cache does not exist.');
194+
}
175195
return resolve();
176196
}
177197
});

lib/support/cli.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -837,10 +837,10 @@ export function parseCommandLine() {
837837
'Before a test start, verify that the device has a Internet connection by pinging 8.8.8.8 (or a configurable domain with --androidPingAddress)',
838838
group: 'android'
839839
})
840-
.option('android.ndk', {
841-
alias: 'androidNDK',
840+
.option('android.simpleperf', {
841+
alias: 'androidSimpleperf',
842842
type: 'string',
843-
describe: 'Path to the Android NDK (required for simpleperf profiling).',
843+
describe: 'Path to the Simpleperf profiler from the Android NDK.',
844844
group: 'android'
845845
})
846846
.option('android.perfettoTrace', {

types/core/engine/command/simpleperf.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export class SimplePerfProfiler {
2727
* @returns {Promise<void>} A promise that resolves when simpleperf has started profiling.
2828
* @throws {Error} Throws an error if app_profiler.py fails to execute.
2929
*/
30-
start(profilerOptions?: string, dirName?: string): Promise<void>;
30+
start(profilerOptions?: any[], recordOptions?: string, dirName?: string): Promise<void>;
31+
profilerOptions: any[];
3132
dataDir: any;
3233
simpleperfProcess: import("execa").ResultPromise<{}>;
3334
/**

types/core/engine/command/simpleperf.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)