def main(): disable_debug_log() adb = AdbHelper() device_arch = adb.get_device_arch() simpleperf_binary = get_target_binary_path(device_arch, 'simpleperf') adb.check_run(['push', simpleperf_binary, '/data/local/tmp']) adb.check_run(['shell', 'chmod', 'a+x', '/data/local/tmp/simpleperf']) shell_cmd = 'cd /data/local/tmp && ./simpleperf ' + ' '.join(sys.argv[1:]) sys.exit(subprocess.call([adb.adb_path, 'shell', shell_cmd]))
def stop_recording(args): adb = AdbHelper() result = adb.run(['shell', 'pidof', 'simpleperf']) if not result: log_warning('No simpleperf process on device. The recording has ended.') else: adb.run(['shell', 'pkill', '-l', '2', 'simpleperf']) print('Waiting for simpleperf process to finish...') while adb.run(['shell', 'pidof', 'simpleperf']): time.sleep(1) adb.run(['shell', 'cat', '/data/local/tmp/simpleperf_output']) adb.check_run(['pull', '/data/local/tmp/perf.data', args.perf_data_path]) print('The recording data has been collected in %s.' % args.perf_data_path)
def stop_recording(args): adb = AdbHelper() result = adb.run(['shell', 'pidof', 'simpleperf']) if not result: log_warning( 'No simpleperf process on device. The recording has ended.') else: adb.run(['shell', 'pkill', '-l', '2', 'simpleperf']) print('Waiting for simpleperf process to finish...') while adb.run(['shell', 'pidof', 'simpleperf']): time.sleep(1) adb.run(['shell', 'cat', '/data/local/tmp/simpleperf_output']) adb.check_run(['pull', '/data/local/tmp/perf.data', args.perf_data_path]) print('The recording data has been collected in %s.' % args.perf_data_path)
def start_recording(args): adb = AdbHelper() device_arch = adb.get_device_arch() simpleperf_binary = get_target_binary_path(device_arch, 'simpleperf') adb.check_run(['push', simpleperf_binary, '/data/local/tmp']) adb.check_run(['shell', 'chmod', 'a+x', '/data/local/tmp/simpleperf']) adb.check_run([ 'shell', 'rm', '-rf', '/data/local/tmp/perf.data', '/data/local/tmp/simpleperf_output' ]) shell_cmd = 'cd /data/local/tmp && nohup ./simpleperf record ' + args.record_options if args.app: shell_cmd += ' --app ' + args.app if args.size_limit: shell_cmd += ' --size-limit ' + args.size_limit shell_cmd += ' >/data/local/tmp/simpleperf_output 2>&1' print('shell_cmd: %s' % shell_cmd) subproc = subprocess.Popen([adb.adb_path, 'shell', shell_cmd]) # Wait 2 seconds to see if the simpleperf command fails to start. time.sleep(2) if subproc.poll() is None: print( 'Simpleperf recording has started. Please unplug the usb cable and run the app.' ) print('After that, run `%s stop` to get recording result.' % sys.argv[0]) else: adb.run(['shell', 'cat', '/data/local/tmp/simpleperf_output']) sys.exit(subproc.returncode)
def start_recording(args): adb = AdbHelper() device_arch = adb.get_device_arch() simpleperf_binary = get_target_binary_path(device_arch, 'simpleperf') adb.check_run(['push', simpleperf_binary, '/data/local/tmp']) adb.check_run(['shell', 'chmod', 'a+x', '/data/local/tmp/simpleperf']) adb.check_run(['shell', 'rm', '-rf', '/data/local/tmp/perf.data', '/data/local/tmp/simpleperf_output']) shell_cmd = 'cd /data/local/tmp && nohup ./simpleperf record ' + args.record_options if args.app: shell_cmd += ' --app ' + args.app if args.size_limit: shell_cmd += ' --size-limit ' + args.size_limit shell_cmd += ' >/data/local/tmp/simpleperf_output 2>&1' print('shell_cmd: %s' % shell_cmd) subproc = subprocess.Popen([adb.adb_path, 'shell', shell_cmd]) # Wait 2 seconds to see if the simpleperf command fails to start. time.sleep(2) if subproc.poll() is None: print('Simpleperf recording has started. Please unplug the usb cable and run the app.') print('After that, run `%s stop` to get recording result.' % sys.argv[0]) else: adb.run(['shell', 'cat', '/data/local/tmp/simpleperf_output']) sys.exit(subproc.returncode)
class ProfilerBase(object): """Base class of all Profilers.""" def __init__(self, args): self.args = args self.adb = AdbHelper(enable_switch_to_root=not args.disable_adb_root) self.is_root_device = self.adb.switch_to_root() self.android_version = self.adb.get_android_version() if self.android_version < 7: log_exit( """app_profiler.py isn't supported on Android < N, please switch to use simpleperf binary directly.""") self.device_arch = self.adb.get_device_arch() self.record_subproc = None def profile(self): log_info('prepare profiling') self.prepare() log_info('start profiling') self.start() self.wait_profiling() log_info('collect profiling data') self.collect_profiling_data() log_info('profiling is finished.') def prepare(self): """Prepare recording. """ self.download_simpleperf() if self.args.native_lib_dir: self.download_libs() def download_simpleperf(self): simpleperf_binary = get_target_binary_path(self.device_arch, 'simpleperf') self.adb.check_run(['push', simpleperf_binary, '/data/local/tmp']) self.adb.check_run( ['shell', 'chmod', 'a+x', '/data/local/tmp/simpleperf']) def download_libs(self): downloader = NativeLibDownloader(self.args.ndk_path, self.device_arch, self.adb) downloader.collect_native_libs_on_host(self.args.native_lib_dir) downloader.collect_native_libs_on_device() downloader.sync_native_libs_on_device() def start(self): raise NotImplementedError def start_profiling(self, target_args): """Start simpleperf reocrd process on device.""" args = [ '/data/local/tmp/simpleperf', 'record', '-o', '/data/local/tmp/perf.data', self.args.record_options ] if self.adb.run( ['shell', 'ls', NATIVE_LIBS_DIR_ON_DEVICE, '>/dev/null', '2>&1']): args += ['--symfs', NATIVE_LIBS_DIR_ON_DEVICE] args += ['--log', self.args.log] args += target_args adb_args = [self.adb.adb_path, 'shell'] + args log_info('run adb cmd: %s' % adb_args) self.record_subproc = subprocess.Popen(adb_args) def wait_profiling(self): """Wait until profiling finishes, or stop profiling when user presses Ctrl-C.""" returncode = None try: returncode = self.record_subproc.wait() except KeyboardInterrupt: self.stop_profiling() self.record_subproc = None # Don't check return value of record_subproc. Because record_subproc also # receives Ctrl-C, and always returns non-zero. returncode = 0 log_debug('profiling result [%s]' % (returncode == 0)) if returncode != 0: log_exit('Failed to record profiling data.') def stop_profiling(self): """Stop profiling by sending SIGINT to simpleperf, and wait until it exits to make sure perf.data is completely generated.""" has_killed = False while True: (result, _) = self.adb.run_and_return_output( ['shell', 'pidof', 'simpleperf']) if not result: break if not has_killed: has_killed = True self.adb.run_and_return_output( ['shell', 'pkill', '-l', '2', 'simpleperf']) time.sleep(1) def collect_profiling_data(self): self.adb.check_run_and_return_output( ['pull', '/data/local/tmp/perf.data', self.args.perf_data_path]) if not self.args.skip_collect_binaries: binary_cache_args = [ sys.executable, os.path.join(get_script_dir(), 'binary_cache_builder.py') ] binary_cache_args += [ '-i', self.args.perf_data_path, '--log', self.args.log ] if self.args.native_lib_dir: binary_cache_args += ['-lib', self.args.native_lib_dir] if self.args.disable_adb_root: binary_cache_args += ['--disable_adb_root'] if self.args.ndk_path: binary_cache_args += ['--ndk_path', self.args.ndk_path] subprocess.check_call(binary_cache_args)
class ProfilerBase(object): """Base class of all Profilers.""" def __init__(self, args): self.args = args self.adb = AdbHelper(enable_switch_to_root=not args.disable_adb_root) self.is_root_device = self.adb.switch_to_root() self.android_version = self.adb.get_android_version() if self.android_version < 7: log_exit("""app_profiler.py isn't supported on Android < N, please switch to use simpleperf binary directly.""") self.device_arch = self.adb.get_device_arch() self.record_subproc = None def profile(self): log_info('prepare profiling') self.prepare() log_info('start profiling') self.start() self.wait_profiling() log_info('collect profiling data') self.collect_profiling_data() log_info('profiling is finished.') def prepare(self): """Prepare recording. """ self.download_simpleperf() if self.args.native_lib_dir: self.download_libs() def download_simpleperf(self): simpleperf_binary = get_target_binary_path(self.device_arch, 'simpleperf') self.adb.check_run(['push', simpleperf_binary, '/data/local/tmp']) self.adb.check_run(['shell', 'chmod', 'a+x', '/data/local/tmp/simpleperf']) def download_libs(self): downloader = NativeLibDownloader(self.args.ndk_path, self.device_arch, self.adb) downloader.collect_native_libs_on_host(self.args.native_lib_dir) downloader.collect_native_libs_on_device() downloader.sync_natives_libs_on_device() def start(self): raise NotImplementedError def start_profiling(self, target_args): """Start simpleperf reocrd process on device.""" args = ['/data/local/tmp/simpleperf', 'record', '-o', '/data/local/tmp/perf.data', self.args.record_options] if self.adb.run(['shell', 'ls', NATIVE_LIBS_DIR_ON_DEVICE]): args += ['--symfs', NATIVE_LIBS_DIR_ON_DEVICE] args += target_args adb_args = [self.adb.adb_path, 'shell'] + args log_debug('run adb cmd: %s' % adb_args) self.record_subproc = subprocess.Popen(adb_args) def wait_profiling(self): """Wait until profiling finishes, or stop profiling when user presses Ctrl-C.""" returncode = None try: returncode = self.record_subproc.wait() except KeyboardInterrupt: self.stop_profiling() self.record_subproc = None # Don't check return value of record_subproc. Because record_subproc also # receives Ctrl-C, and always returns non-zero. returncode = 0 log_debug('profiling result [%s]' % (returncode == 0)) if returncode != 0: log_exit('Failed to record profiling data.') def stop_profiling(self): """Stop profiling by sending SIGINT to simpleperf, and wait until it exits to make sure perf.data is completely generated.""" has_killed = False while True: (result, _) = self.adb.run_and_return_output(['shell', 'pidof', 'simpleperf']) if not result: break if not has_killed: has_killed = True self.adb.run_and_return_output(['shell', 'pkill', '-l', '2', 'simpleperf']) time.sleep(1) def collect_profiling_data(self): self.adb.check_run_and_return_output(['pull', '/data/local/tmp/perf.data', self.args.perf_data_path]) if not self.args.skip_collect_binaries: binary_cache_args = [sys.executable, os.path.join(get_script_dir(), 'binary_cache_builder.py')] binary_cache_args += ['-i', self.args.perf_data_path] if self.args.native_lib_dir: binary_cache_args += ['-lib', self.args.native_lib_dir] if self.args.disable_adb_root: binary_cache_args += ['--disable_adb_root'] if self.args.ndk_path: binary_cache_args += ['--ndk_path', self.args.ndk_path] subprocess.check_call(binary_cache_args)