Home | History | Annotate | Download | only in fdo_scripts
      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 
      6 import copy
      7 import optparse
      8 import os
      9 import pickle
     10 import re
     11 import sys
     12 import tempfile
     13 import time
     14 
     15 import build_chrome_browser
     16 import cros_login
     17 import lock_machine
     18 import run_tests
     19 from cros_utils import command_executer
     20 from cros_utils import logger
     21 from cros_utils import misc
     22 
     23 
     24 class 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 
    145 def 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 
    197 if __name__ == '__main__':
    198   retval = Main(sys.argv)
    199   sys.exit(retval)
    200