Home | History | Annotate | Download | only in interpreter
      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