diff --git a/tools/get_about_memory.py b/tools/get_about_memory.py index d6739f6a..924e35ce 100755 --- a/tools/get_about_memory.py +++ b/tools/get_about_memory.py @@ -57,10 +57,14 @@ def process_dmd_files(dmd_files, args): ''')) traceback.print_exc(e) -def process_dmd_files_impl(dmd_files, args): - out_dir = os.path.dirname(dmd_files[0]) - procrank = open(os.path.join(out_dir, 'b2g-procrank'), 'r').read().split('\n') +def get_proc_names(out_dir): + """ + Retrieves a mapping of process names to their PID as well as the raw + output of b2g-procrank. + """ + with open(os.path.join(out_dir, 'b2g-procrank'), 'r') as f: + procrank = f.read().split('\n') proc_names = {} for line in procrank: # App names may contain spaces and special characters (e.g. @@ -73,6 +77,13 @@ def process_dmd_files_impl(dmd_files, args): if not match: continue proc_names[int(match.group(2))] = re.sub('\W', '', match.group(1)).lower() + return proc_names, procrank + + +def process_dmd_files_impl(dmd_files, args): + out_dir = os.path.dirname(dmd_files[0]) + + proc_names, procrank = get_proc_names(out_dir) for f in dmd_files: # Extract the PID (e.g. 111) and UNIX time (e.g. 9999999) from the name @@ -119,6 +130,33 @@ def write(str): if not args.keep_individual_reports: os.remove(f) + +def get_kgsl_files(out_dir): + """Retrieves kgsl graphics memory usage files.""" + print() + print('Processing kgsl files.') + + proc_names, _ = get_proc_names(out_dir) + + try: + kgsl_pids = utils.remote_ls('/d/kgsl/proc/', verbose=False) + except subprocess.CalledProcessError: + # Probably not a kgsl device. + print('kgsl graphics memory logs not available for this device.') + return + + for pid in filter(None, kgsl_pids): + name = proc_names[int(pid)] if int(pid) in proc_names else pid + remote_file = '/d/kgsl/proc/%s/mem' % pid + dest_file = os.path.join(out_dir, 'kgsl-%s-mem' % name) + try: + utils.pull_remote_file(remote_file, dest_file) + except subprocess.CalledProcessError: + print('Unable to retrieve kgsl file: %s' % remote_file) + + print('Done processing kgsl files.') + + def merge_files(dir, files): '''Merge the given memory reporter dump files into one giant file.''' dumps = [json.load(GzipFile(os.path.join(dir, f))) for f in files] @@ -232,6 +270,10 @@ def get_and_show_info(args): process_dmd_files(dmd_files, args) + if not args.no_kgsl_logs: + get_kgsl_files(out_dir) + + def main(): parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) @@ -278,6 +320,11 @@ def main(): default=False, help='Get an abbreviated GC/CC log, instead of a full one.') + parser.add_argument('--no-kgsl-logs', + action='store_true', + default=False, + help='''Don't get the kgsl graphics memory logs.''') + parser.add_argument('--no-dmd', action='store_true', default=False, help='''Don't process DMD logs, even if they're available.''') diff --git a/tools/include/device_utils.py b/tools/include/device_utils.py index 0779f1d1..6a7123b6 100644 --- a/tools/include/device_utils.py +++ b/tools/include/device_utils.py @@ -10,7 +10,7 @@ import textwrap from time import sleep -def remote_shell(cmd): +def remote_shell(cmd, verbose=True): '''Run the given command on on the device and return stdout. Throw an exception if the remote command returns a non-zero return code. @@ -32,13 +32,15 @@ def remote_shell(cmd): if retcode == '0': return cmd_out - print('Remote command %s failed with error code %s' % (cmd, retcode), - file=sys.stderr) - if cmd_out: - print(cmd_out, file=sys.stderr) + if verbose: + print('Remote command %s failed with error code %s' % (cmd, retcode), + file=sys.stderr) + if cmd_out: + print(cmd_out, file=sys.stderr) + raise subprocess.CalledProcessError(retcode, cmd, cmd_out) -def remote_toolbox_cmd(cmd, args=''): +def remote_toolbox_cmd(cmd, args='', verbose=True): '''Run the given command from /system/bin/toolbox on the device. Pass args, if specified, and return stdout. Throw an exception if the command returns a non-zero return code. @@ -53,11 +55,11 @@ def remote_toolbox_cmd(cmd, args=''): the same output regardless of whether busybox is installed. ''' - return remote_shell('/system/bin/toolbox "%s" %s' % (cmd, args)) + return remote_shell('/system/bin/toolbox "%s" %s' % (cmd, args), verbose) -def remote_ls(dir): +def remote_ls(dir, verbose=True): '''Run ls on the remote device, and return a set containing the results.''' - return {f.strip() for f in remote_toolbox_cmd('ls', dir).split('\n')} + return {f.strip() for f in remote_toolbox_cmd('ls', dir, verbose).split('\n')} def shell(cmd, cwd=None, show_errors=True): '''Run the given command as a shell script on the host machine. @@ -271,6 +273,11 @@ def notify_and_pull_files(outfiles_prefixes, return [os.path.basename(f) for f in new_files] +def pull_remote_file(remote_file, dest_file): + """Copies a file from the device.""" + shell('adb pull "%s" "%s"' % (remote_file, dest_file)) + + # You probably don't need to call the functions below from outside this module, # but hey, maybe you do.