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