1# Copyright 2012 Google Inc. All Rights Reserved. 2"""A script that symbolizes perf.data files.""" 3import optparse 4import os 5import shutil 6from subprocess import call 7from subprocess import PIPE 8from subprocess import Popen 9from cros_utils import misc 10 11GSUTIL_CMD = 'gsutil cp gs://chromeos-image-archive/%s-release/%s/debug.tgz %s' 12TAR_CMD = 'tar -zxvf %s -C %s' 13PERF_BINARY = '/google/data/ro/projects/perf/perf' 14VMLINUX_FLAG = ' --vmlinux=/usr/lib/debug/boot/vmlinux' 15PERF_CMD = PERF_BINARY + ' report -i %s -n --symfs=%s' + VMLINUX_FLAG 16 17 18def main(): 19 parser = optparse.OptionParser() 20 parser.add_option('--in', dest='in_dir') 21 parser.add_option('--out', dest='out_dir') 22 parser.add_option('--cache', dest='cache') 23 (opts, _) = parser.parse_args() 24 if not _ValidateOpts(opts): 25 return 1 26 else: 27 for filename in os.listdir(opts.in_dir): 28 try: 29 _DownloadSymbols(filename, opts.cache) 30 _PerfReport(filename, opts.in_dir, opts.out_dir, opts.cache) 31 except: 32 print 'Exception caught. Continuing...' 33 return 0 34 35 36def _ValidateOpts(opts): 37 """Ensures all directories exist, before attempting to populate.""" 38 if not os.path.exists(opts.in_dir): 39 print "Input directory doesn't exist." 40 return False 41 if not os.path.exists(opts.out_dir): 42 print "Output directory doesn't exist. Creating it..." 43 os.makedirs(opts.out_dir) 44 if not os.path.exists(opts.cache): 45 print "Cache directory doesn't exist." 46 return False 47 return True 48 49 50def _ParseFilename(filename, canonical=False): 51 """Returns a tuple (key, time, board, lsb_version). 52 If canonical is True, instead returns (database_key, board, canonical_vers) 53 canonical_vers includes the revision string. 54 """ 55 key, time, board, vers = filename.split('~') 56 if canonical: 57 vers = misc.GetChromeOSVersionFromLSBVersion(vers) 58 return (key, time, board, vers) 59 60 61def _FormReleaseDir(board, version): 62 return '%s-release~%s' % (board, version) 63 64 65def _DownloadSymbols(filename, cache): 66 """ Incrementally downloads appropriate symbols. 67 We store the downloads in cache, with each set of symbols in a TLD 68 named like cache/$board-release~$canonical_vers/usr/lib/debug 69 """ 70 _, _, board, vers = _ParseFilename(filename, canonical=True) 71 tmp_suffix = '.tmp' 72 73 tarball_subdir = _FormReleaseDir(board, vers) 74 tarball_dir = os.path.join(cache, tarball_subdir) 75 tarball_path = os.path.join(tarball_dir, 'debug.tgz') 76 77 symbol_subdir = os.path.join('usr', 'lib') 78 symbol_dir = os.path.join(tarball_dir, symbol_subdir) 79 80 if os.path.isdir(symbol_dir): 81 print 'Symbol directory %s exists, skipping download.' % symbol_dir 82 return 83 else: 84 # First download using gsutil. 85 if not os.path.isfile(tarball_path): 86 download_cmd = GSUTIL_CMD % (board, vers, tarball_path + tmp_suffix) 87 print 'Downloading symbols for %s' % filename 88 print download_cmd 89 ret = call(download_cmd.split()) 90 if ret != 0: 91 print 'gsutil returned non-zero error code: %s.' % ret 92 # Clean up the empty directory structures. 93 os.remove(tarball_path + tmp_suffix) 94 raise IOError 95 96 shutil.move(tarball_path + tmp_suffix, tarball_path) 97 98 # Next, untar the tarball. 99 os.makedirs(symbol_dir + tmp_suffix) 100 extract_cmd = TAR_CMD % (tarball_path, symbol_dir + tmp_suffix) 101 print 'Extracting symbols for %s' % filename 102 print extract_cmd 103 ret = call(extract_cmd.split()) 104 if ret != 0: 105 print 'tar returned non-zero code: %s.' % ret 106 raise IOError 107 shutil.move(symbol_dir + tmp_suffix, symbol_dir) 108 os.remove(tarball_path) 109 110 111def _PerfReport(filename, in_dir, out_dir, cache): 112 """ Call perf report on the file, storing output to the output dir. 113 The output is currently stored as $out_dir/$filename 114 """ 115 _, _, board, vers = _ParseFilename(filename, canonical=True) 116 symbol_cache_tld = _FormReleaseDir(board, vers) 117 input_file = os.path.join(in_dir, filename) 118 symfs = os.path.join(cache, symbol_cache_tld) 119 report_cmd = PERF_CMD % (input_file, symfs) 120 print 'Reporting.' 121 print report_cmd 122 report_proc = Popen(report_cmd.split(), stdout=PIPE) 123 outfile = open(os.path.join(out_dir, filename), 'w') 124 outfile.write(report_proc.stdout.read()) 125 outfile.close() 126 127 128if __name__ == '__main__': 129 exit(main()) 130