test_toolchains.py revision 94bc470daff948021e754e6a63061da221faaf77
1#!/usr/bin/python
2
3# Script to test different toolchains against ChromeOS benchmarks.
4import optparse
5import os
6import sys
7import build_chromeos
8import setup_chromeos
9import time
10from utils import command_executer
11from utils import misc
12from utils import logger
13
14
15WEEKLY_REPORTS_ROOT="/usr/local/google/crostc/weekly_test_data"
16
17class GCCConfig(object):
18  def __init__(self, githash):
19    self.githash = githash
20
21
22class ToolchainConfig:
23  def __init__(self, gcc_config=None, binutils_config=None):
24    self.gcc_config = gcc_config
25
26
27class ChromeOSCheckout(object):
28  def __init__(self, board, chromeos_root):
29    self._board = board
30    self._chromeos_root = chromeos_root
31    self._ce = command_executer.GetCommandExecuter()
32    self._l = logger.GetLogger()
33
34  def _DeleteChroot(self):
35    command = "cd %s; cros_sdk --delete" % self._chromeos_root
36    return self._ce.RunCommand(command)
37
38  def _DeleteCcahe(self):
39    # crosbug.com/34956
40    command = "sudo rm -rf %s" % os.path.join(self._chromeos_root, ".cache")
41    return self._ce.RunCommand(command)
42
43  def _BuildAndImage(self, label=""):
44    if (not label or
45        not misc.DoesLabelExist(self._chromeos_root, self._board, label)):
46      build_chromeos_args = [build_chromeos.__file__,
47                             "--chromeos_root=%s" % self._chromeos_root,
48                             "--board=%s" % self._board,
49                             "--rebuild"]
50      if self._public:
51        build_chromeos_args.append("--env=USE=-chrome_internal")
52      if label == "vanilla":
53        build_chromeos_args.append("--vanilla_image")
54      ret = build_chromeos.Main(build_chromeos_args)
55      if ret:
56        raise Exception("Couldn't build ChromeOS!")
57      if label:
58        misc.LabelLatestImage(self._chromeos_root, self._board, label)
59    return label
60
61  def _SetupBoard(self, env_dict):
62    env_string = misc.GetEnvStringFromDict(env_dict)
63    command = ("%s %s" %
64               (env_string,
65                misc.GetSetupBoardCommand(self._board,
66                                          usepkg=False)))
67    ret = self._ce.ChrootRunCommand(self._chromeos_root,
68                                    command)
69    assert ret == 0, "Could not setup board with new toolchain."
70
71  def _UnInstallToolchain(self):
72    command = ("sudo CLEAN_DELAY=0 emerge -C cross-%s/gcc" %
73               misc.GetCtargetFromBoard(self._board,
74                                   self._chromeos_root))
75    ret = self._ce.ChrootRunCommand(self._chromeos_root,
76                                    command)
77    if ret:
78      raise Exception("Couldn't uninstall the toolchain!")
79
80  def _CheckoutChromeOS(self):
81    # TODO(asharif): Setup a fixed ChromeOS version (quarterly snapshot).
82    if not os.path.exists(self._chromeos_root):
83      setup_chromeos_args = [setup_chromeos.__file__,
84                             "--dir=%s" % self._chromeos_root]
85      if self._public:
86        setup_chromeos_args.append("--public")
87      ret = setup_chromeos.Main(setup_chromeos_args)
88      if ret:
89        raise Exception("Couldn't run setup_chromeos!")
90
91
92  def _BuildToolchain(self, config):
93    self._UnInstallToolchain()
94    self._SetupBoard({"USE": "git_gcc",
95                      "GCC_GITHASH": config.gcc_config.githash,
96                      "EMERGE_DEFAULT_OPTS": "--exclude=gcc"})
97
98
99class ToolchainComparator(ChromeOSCheckout):
100  def __init__(self, board, remotes, configs, clean, public, force_mismatch):
101    self._board = board
102    self._remotes = remotes
103    self._chromeos_root = "chromeos"
104    self._configs = configs
105    self._clean = clean
106    self._public = public
107    self._force_mismatch = force_mismatch
108    self._ce = command_executer.GetCommandExecuter()
109    self._l = logger.GetLogger()
110    ChromeOSCheckout.__init__(self, board, self._chromeos_root)
111
112
113  def _FinishSetup(self):
114    # Get correct .boto file
115    current_dir = os.getcwd()
116    src = "/home/mobiletc-prebuild/.boto"
117    dest = os.path.join(current_dir, self._chromeos_root,
118                        "src/private-overlays/chromeos-overlay/"
119                        "googlestorage_account.boto")
120    # Copy the file to the correct place
121    copy_cmd = "cp %s %s" % (src, dest)
122    retval = self._ce.RunCommand(copy_cmd)
123    if retval:
124      raise Exception("Couldn't copy .boto file for google storage.")
125
126    # Fix protections on ssh key
127    command = ("chmod 600 /var/cache/chromeos-cache/distfiles/target"
128               "/chrome-src-internal/src/third_party/chromite/ssh_keys"
129               "/testing_rsa")
130    retval = self._ce.ChrootRunCommand(self._chromeos_root, command)
131    if retval:
132      raise Exception("chmod for testing_rsa failed")
133
134  def _TestLabels(self, labels):
135    experiment_file = "toolchain_experiment.txt"
136    image_args = ""
137    if self._force_mismatch:
138      image_args = "--force-mismatch"
139    experiment_header = """
140    board: %s
141    remote: %s
142    """ % (self._board, self._remotes)
143    experiment_tests = """
144    benchmark: all_perfv2 {
145      suite: telemetry_Crosperf
146      iterations: 3
147    }
148    """
149    with open(experiment_file, "w") as f:
150      print >>f, experiment_header
151      print >>f, experiment_tests
152      for label in labels:
153        # TODO(asharif): Fix crosperf so it accepts labels with symbols
154        crosperf_label = label
155        crosperf_label = crosperf_label.replace("-", "minus")
156        crosperf_label = crosperf_label.replace("+", "plus")
157        crosperf_label = crosperf_label.replace(".", "")
158        experiment_image = """
159        %s {
160          chromeos_image: %s
161          image_args: %s
162        }
163        """ % (crosperf_label,
164               os.path.join(misc.GetImageDir(self._chromeos_root, self._board),
165                            label,
166                            "chromiumos_test_image.bin"),
167               image_args)
168        print >>f, experiment_image
169    images_path = os.path.join(os.path.realpath(self._chromeos_root),
170                               "src/build/images", self._board)
171    weekday = time.strftime("%a")
172    for l in labels:
173      test_path = os.path.join(images_path, l)
174      if os.path.exists(test_path):
175        data_dir = os.path.join(WEEKLY_REPORTS_ROOT, self._board)
176        if l == "vanilla":
177          label_name = l
178        else:
179          label_name = "test"
180        tar_file_name = "%s_%s_image.tar" % (weekday, label_name)
181        dest_dir = os.path.join (data_dir, weekday)
182        if not os.path.exists(dest_dir):
183          os.makedirs(dest_dir)
184        cmd="cd %s; tar -cvf %s %s/*; cp %s %s/." % (images_path,tar_file_name,
185                                                     l, tar_file_name,
186                                                     dest_dir)
187        tar_ret = self._ce.RunCommand(cmd)
188        if tar_ret:
189          self._l.LogOutput("Error while creating/copying test tar file (%s)."
190                            % tar_file_name)
191    crosperf = os.path.join(os.path.dirname(__file__),
192                            "crosperf",
193                            "crosperf")
194    command = "%s --email=c-compiler-chrome %s" % (crosperf, experiment_file)
195    ret = self._ce.RunCommand(command)
196    if ret:
197      raise Exception("Couldn't run crosperf!")
198
199  def DoAll(self):
200    self._CheckoutChromeOS()
201    labels = []
202    vanilla_label = self._BuildAndImage("vanilla")
203    labels.append(vanilla_label)
204    for config in self._configs:
205      label = misc.GetFilenameFromString(config.gcc_config.githash)
206      if (not misc.DoesLabelExist(self._chromeos_root,
207                                  self._board,
208                                  label)):
209        self._BuildToolchain(config)
210        label = self._BuildAndImage(label)
211      labels.append(label)
212    self._FinishSetup()
213    self._TestLabels(labels)
214    if self._clean:
215      ret = self._DeleteChroot()
216      if ret: return ret
217      ret = self._DeleteCcahe()
218      if ret: return ret
219    return 0
220
221
222def Main(argv):
223  """The main function."""
224  # Common initializations
225###  command_executer.InitCommandExecuter(True)
226  command_executer.InitCommandExecuter()
227  parser = optparse.OptionParser()
228  parser.add_option("--remote",
229                    dest="remote",
230                    help="Remote machines to run tests on.")
231  parser.add_option("--board",
232                    dest="board",
233                    default="x86-zgb",
234                    help="The target board.")
235  parser.add_option("--githashes",
236                    dest="githashes",
237                    default="master",
238                    help="The gcc githashes to test.")
239  parser.add_option("--clean",
240                    dest="clean",
241                    default=False,
242                    action="store_true",
243                    help="Clean the chroot after testing.")
244  parser.add_option("--public",
245                    dest="public",
246                    default=False,
247                    action="store_true",
248                    help="Use the public checkout/build.")
249  parser.add_option("--force-mismatch",
250                    dest="force_mismatch",
251                    default="",
252                    help="Force the image regardless of board mismatch")
253  options, _ = parser.parse_args(argv)
254  if not options.board:
255    print "Please give a board."
256    return 1
257  if not options.remote:
258    print "Please give at least one remote machine."
259    return 1
260  toolchain_configs = []
261  for githash in options.githashes.split(","):
262    gcc_config = GCCConfig(githash=githash)
263    toolchain_config = ToolchainConfig(gcc_config=gcc_config)
264    toolchain_configs.append(toolchain_config)
265  fc = ToolchainComparator(options.board, options.remote, toolchain_configs,
266                           options.clean, options.public,
267                           options.force_mismatch)
268  return fc.DoAll()
269
270
271if __name__ == "__main__":
272  retval = Main(sys.argv)
273  sys.exit(retval)
274