profile_cycler.py revision 9099a788cd7124024559c064e425ed9caef6e0ac
1#!/usr/bin/python
2#
3# Copyright 2011 Google Inc. All Rights Reserved.
4"""Script to profile a page cycler, and get it back to the host."""
5
6import copy
7import optparse
8import os
9import pickle
10import re
11import sys
12import tempfile
13import time
14
15import build_chrome_browser
16import cros_login
17import lock_machine
18import run_tests
19from cros_utils import command_executer
20from cros_utils import logger
21from cros_utils import misc
22
23
24class CyclerProfiler:
25  REMOTE_TMP_DIR = '/tmp'
26
27  def __init__(self, chromeos_root, board, cycler, profile_dir, remote):
28    self._chromeos_root = chromeos_root
29    self._cycler = cycler
30    self._profile_dir = profile_dir
31    self._remote = remote
32    self._board = board
33    self._ce = command_executer.GetCommandExecuter()
34    self._l = logger.GetLogger()
35
36    self._gcov_prefix = os.path.join(self.REMOTE_TMP_DIR, self._GetProfileDir())
37
38  def _GetProfileDir(self):
39    return misc.GetCtargetFromBoard(self._board, self._chromeos_root)
40
41  def _CopyTestData(self):
42    page_cycler_dir = os.path.join(self._chromeos_root, 'distfiles', 'target',
43                                   'chrome-src-internal', 'src', 'data',
44                                   'page_cycler')
45    if not os.path.isdir(page_cycler_dir):
46      raise RuntimeError('Page cycler dir %s not found!' % page_cycler_dir)
47    self._ce.CopyFiles(page_cycler_dir,
48                       os.path.join(self.REMOTE_TMP_DIR, 'page_cycler'),
49                       dest_machine=self._remote,
50                       chromeos_root=self._chromeos_root,
51                       recursive=True,
52                       dest_cros=True)
53
54  def _PrepareTestData(self):
55    # chmod files so everyone can read them.
56    command = ('cd %s && find page_cycler -type f | xargs chmod a+r' %
57               self.REMOTE_TMP_DIR)
58    self._ce.CrosRunCommand(command,
59                            chromeos_root=self._chromeos_root,
60                            machine=self._remote)
61    command = ('cd %s && find page_cycler -type d | xargs chmod a+rx' %
62               self.REMOTE_TMP_DIR)
63    self._ce.CrosRunCommand(command,
64                            chromeos_root=self._chromeos_root,
65                            machine=self._remote)
66
67  def _CopyProfileToHost(self):
68    dest_dir = os.path.join(self._profile_dir,
69                            os.path.basename(self._gcov_prefix))
70    # First remove the dir if it exists already
71    if os.path.exists(dest_dir):
72      command = 'rm -rf %s' % dest_dir
73      self._ce.RunCommand(command)
74
75    # Strip out the initial prefix for the Chrome directory before doing the
76    # copy.
77    chrome_dir_prefix = misc.GetChromeSrcDir()
78
79    command = 'mkdir -p %s' % dest_dir
80    self._ce.RunCommand(command)
81    self._ce.CopyFiles(self._gcov_prefix,
82                       dest_dir,
83                       src_machine=self._remote,
84                       chromeos_root=self._chromeos_root,
85                       recursive=True,
86                       src_cros=True)
87
88  def _RemoveRemoteProfileDir(self):
89    command = 'rm -rf %s' % self._gcov_prefix
90    self._ce.CrosRunCommand(command,
91                            chromeos_root=self._chromeos_root,
92                            machine=self._remote)
93
94  def _LaunchCycler(self, cycler):
95    command = (
96        'DISPLAY=:0 '
97        'XAUTHORITY=/home/chronos/.Xauthority '
98        'GCOV_PREFIX=%s '
99        'GCOV_PREFIX_STRIP=3 '
100        '/opt/google/chrome/chrome '
101        '--no-sandbox '
102        '--renderer-clean-exit '
103        '--user-data-dir=$(mktemp -d) '
104        "--url \"file:///%s/page_cycler/%s/start.html?iterations=10&auto=1\" "
105        '--enable-file-cookies '
106        '--no-first-run '
107        '--js-flags=expose_gc &' % (self._gcov_prefix, self.REMOTE_TMP_DIR,
108                                    cycler))
109
110    self._ce.CrosRunCommand(command,
111                            chromeos_root=self._chromeos_root,
112                            machine=self._remote,
113                            command_timeout=60)
114
115  def _PkillChrome(self, signal='9'):
116    command = 'pkill -%s chrome' % signal
117    self._ce.CrosRunCommand(command,
118                            chromeos_root=self._chromeos_root,
119                            machine=self._remote)
120
121  def DoProfile(self):
122    # Copy the page cycler data to the remote
123    self._CopyTestData()
124    self._PrepareTestData()
125    self._RemoveRemoteProfileDir()
126
127    for cycler in self._cycler.split(','):
128      self._ProfileOneCycler(cycler)
129
130    # Copy the profile back
131    self._CopyProfileToHost()
132
133  def _ProfileOneCycler(self, cycler):
134    # With aura, all that's needed is a stop/start ui.
135    self._PkillChrome()
136    cros_login.RestartUI(self._remote, self._chromeos_root, login=False)
137    # Run the cycler
138    self._LaunchCycler(cycler)
139    self._PkillChrome(signal='INT')
140    # Let libgcov dump the profile.
141    # TODO(asharif): There is a race condition here. Fix it later.
142    time.sleep(30)
143
144
145def Main(argv):
146  """The main function."""
147  # Common initializations
148  ###  command_executer.InitCommandExecuter(True)
149  command_executer.InitCommandExecuter()
150  l = logger.GetLogger()
151  ce = command_executer.GetCommandExecuter()
152  parser = optparse.OptionParser()
153  parser.add_option('--cycler',
154                    dest='cycler',
155                    default='alexa_us',
156                    help=('Comma-separated cyclers to profile. '
157                          'Example: alexa_us,moz,moz2'
158                          'Use all to profile all cyclers.'))
159  parser.add_option('--chromeos_root',
160                    dest='chromeos_root',
161                    default='../../',
162                    help='Output profile directory.')
163  parser.add_option('--board',
164                    dest='board',
165                    default='x86-zgb',
166                    help='The target board.')
167  parser.add_option('--remote',
168                    dest='remote',
169                    help=('The remote chromeos machine that'
170                          ' has the profile image.'))
171  parser.add_option('--profile_dir',
172                    dest='profile_dir',
173                    default='profile_dir',
174                    help='Store profiles in this directory.')
175
176  options, _ = parser.parse_args(argv)
177
178  all_cyclers = ['alexa_us', 'bloat', 'dhtml', 'dom', 'intl1', 'intl2',
179                 'morejs', 'morejsnp', 'moz', 'moz2']
180
181  if options.cycler == 'all':
182    options.cycler = ','.join(all_cyclers)
183
184  try:
185    cp = CyclerProfiler(options.chromeos_root, options.board, options.cycler,
186                        options.profile_dir, options.remote)
187    cp.DoProfile()
188    retval = 0
189  except Exception as e:
190    retval = 1
191    print e
192  finally:
193    print 'Exiting...'
194  return retval
195
196
197if __name__ == '__main__':
198  retval = Main(sys.argv)
199  sys.exit(retval)
200