1 # Copyright 2012 Google Inc. All Rights Reserved. 2 """A script that symbolizes perf.data files.""" 3 import optparse 4 import os 5 import shutil 6 from subprocess import call 7 from subprocess import PIPE 8 from subprocess import Popen 9 from cros_utils import misc 10 11 GSUTIL_CMD = 'gsutil cp gs://chromeos-image-archive/%s-release/%s/debug.tgz %s' 12 TAR_CMD = 'tar -zxvf %s -C %s' 13 PERF_BINARY = '/google/data/ro/projects/perf/perf' 14 VMLINUX_FLAG = ' --vmlinux=/usr/lib/debug/boot/vmlinux' 15 PERF_CMD = PERF_BINARY + ' report -i %s -n --symfs=%s' + VMLINUX_FLAG 16 17 18 def 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 36 def _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 50 def _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 61 def _FormReleaseDir(board, version): 62 return '%s-release~%s' % (board, version) 63 64 65 def _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 111 def _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 128 if __name__ == '__main__': 129 exit(main()) 130