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