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