1 # Copyright 2011 Google Inc. All Rights Reserved. 2 """Helper modules for Android toolchain test infrastructure. 3 4 Provides following Android toolchain test jobs and commands. 5 . Checkout Android toolchain source code 6 . Build Android toolchain 7 . Checkout and build Android tree 8 . Checkout/build/run Android benchmarks, generate size dashboard 9 . Transform size dashboard to report, send perflab jobid to 10 perflab dashboard server.(TODO) 11 """ 12 13 __author__ = 'jingyu (at] google.com (Jing Yu)' 14 15 import os.path 16 17 from automation.clients.helper import jobs 18 from automation.clients.helper import perforce 19 from automation.common import command as cmd 20 from automation.common import job 21 22 23 class JobsFactory(object): 24 25 def __init__(self, gcc_version='4.4.3', build_type='DEVELOPMENT'): 26 assert gcc_version in ['4.4.3', '4.6', 'google_main', 'fsf_trunk'] 27 assert build_type in ['DEVELOPMENT', 'RELEASE'] 28 29 self.gcc_version = gcc_version 30 self.commands = CommandsFactory(gcc_version, build_type) 31 self.tc_tag = 'gcc-%s-%s' % (gcc_version, build_type) 32 33 def CheckoutAndroidToolchain(self): 34 """Check out Android toolchain sources by release and gcc version.""" 35 command = self.commands.CheckoutAndroidToolchain() 36 new_job = jobs.CreateLinuxJob('AndroidCheckoutToolchain(%s)' % self.tc_tag, 37 command) 38 checkout_dir_dep = job.FolderDependency(new_job, self.commands.CHECKOUT_DIR) 39 return new_job, checkout_dir_dep 40 41 def BuildAndroidToolchain(self, checkout_dir_dep): 42 """Build Android Toolchain.""" 43 command = self.commands.BuildAndroidToolchain() 44 new_job = jobs.CreateLinuxJob('AndroidBuildToolchain(%s)' % self.tc_tag, 45 command) 46 new_job.DependsOnFolder(checkout_dir_dep) 47 tc_prefix_dep = job.FolderDependency(new_job, 48 self.commands.toolchain_prefix_dir) 49 return new_job, tc_prefix_dep 50 51 def BuildAndroidImage(self, 52 tc_prefix_dep, 53 product='stingray', 54 branch='ics-release'): 55 assert product in ['stingray', 'passion', 'trygon', 'soju'] 56 assert branch in ['honeycomb-release', 'ics-release'] 57 command = self.commands.BuildAndroidImage(product, branch) 58 new_job = jobs.CreateLinuxJob('AndroidGetBuildTree(%s)' % self.tc_tag, 59 command) 60 new_job.DependsOnFolder(tc_prefix_dep) 61 return new_job 62 63 def Benchmark(self, tc_prefix_dep, arch='soju'): 64 assert arch in ['soju', 'stingray'] 65 script_cmd = self.commands.CheckoutScripts() 66 experiment_tag = 'android/nightly/%s/%s/$JOB_ID' % (self.tc_tag, arch) 67 build_run_benchmark_cmd = self.commands.BuildRunBenchmark(arch, 68 experiment_tag) 69 command = cmd.Chain(script_cmd, build_run_benchmark_cmd) 70 new_job = jobs.CreateLinuxJob('AndroidBenchmarking(%s)' % self.tc_tag, 71 command) 72 new_job.DependsOnFolder(tc_prefix_dep) 73 return new_job 74 75 76 class CommandsFactory(object): 77 CHECKOUT_DIR = 'androidtc-checkout-dir' 78 TOOLCHAIN_SRC_DIR = os.path.join(CHECKOUT_DIR, 'src') 79 TOOLCHAIN_BUILD_DIR = 'obj' 80 ANDROID_TREES_DIR = 'android_trees' 81 TOOLS_DIR = 'android-tools' 82 BENCHMARK_OUT_DIR = 'results' 83 84 def __init__(self, gcc_version, build_type): 85 assert gcc_version in ['4.4.3', '4.6', 'google_main', 'fsf_trunk'] 86 assert build_type in ['DEVELOPMENT', 'RELEASE'] 87 88 self.build_type = build_type 89 self.gcc_version = gcc_version 90 self.binutils_version = '2.21' 91 self.gold_version = '2.21' 92 self.toolchain_prefix_dir = 'install-gcc-%s-%s' % (gcc_version, build_type) 93 self.p4client = self._CreatePerforceClient() 94 self.scripts = ScriptsFactory(self.gcc_version, self.binutils_version, 95 self.gold_version) 96 97 def _CreatePerforceClient(self): 98 p4_dev_path = 'gcctools/google_vendor_src_branch' 99 mobile_rel_branch = ('branches/' 100 'mobile_toolchain_v15_release_branch/gcctools/' 101 'google_vendor_src_branch') 102 gcc_443_rel_branch = ('branches/' 103 'android_compiler_v14_release_branch/gcctools/' 104 'google_vendor_src_branch') 105 106 # Common views for tools 107 p4view = perforce.View('depot2', perforce.PathMapping.ListFromPathTuples([( 108 'gcctools/android/build/...', 'src/build/...'), ( 109 'gcctools/android/Tarballs/...', 'src/tarballs/...')])) 110 for mapping in perforce.PathMapping.ListFromPathDict( 111 {'gcctools/android': ['tools/scripts/...', 'master/...']}): 112 p4view.add(mapping) 113 114 # Add views for gdb 115 p4view.add(perforce.PathMapping(p4_dev_path, 'src', 116 'gdb/gdb-7.1.x-android/...')) 117 118 # Add view for binutils for ld and gold 119 if self.build_type is 'RELEASE': 120 binutils_branch = mobile_rel_branch 121 else: 122 binutils_branch = p4_dev_path 123 p4view.add(perforce.PathMapping(binutils_branch, 'src', ( 124 'binutils/binutils-%s/...' % self.binutils_version))) 125 if self.binutils_version != self.gold_version: 126 p4view.add(perforce.PathMapping(binutils_branch, 'src', ( 127 'binutils/binutils-%s/...' % self.gold_version))) 128 129 # Add view for gcc if gcc_version is '4.4.3'. 130 if self.gcc_version == '4.4.3': 131 gcc443_path = 'gcc/gcc-4.4.3/...' 132 if self.build_type is 'RELEASE': 133 p4view.add(perforce.PathMapping(gcc_443_rel_branch, 'src', gcc443_path)) 134 else: 135 p4view.add(perforce.PathMapping(p4_dev_path, 'src', gcc443_path)) 136 137 return perforce.CommandsFactory(self.CHECKOUT_DIR, p4view) 138 139 def _CheckoutGCCFromSVN(self): 140 """Check out gcc from fsf svn. 141 142 Return the command that check out gcc from svn 143 to gcc_required_dir (=TOOLCHAIN_SRC_DIR/src/gcc/gcc-xxx). 144 145 TODO: 146 Create a svn class that does these jobs. 147 Parallelize p4 checkout and svn checkout. 148 """ 149 if self.gcc_version == '4.4.3': 150 return '' 151 assert self.gcc_version in ['4.6', 'google_main', 'fsf_trunk'] 152 153 gcc_branches_dir = {'4.6': 'branches/google/gcc-4_6', 154 'google_main': 'branches/google/main', 155 'fsf_trunk': 'trunk'} 156 157 # Find GCC revision number, output it to TOOLCHAIN_SRC_DIR/CLNUM_GCC 158 svn_get_revision = cmd.Pipe( 159 cmd.Shell('svn', 'info'), 160 cmd.Shell('grep', '"Revision:"'), 161 cmd.Shell('sed', '-E', '"s,Revision: ([0-9]+).*,\\1,"'), 162 output='../../../CLNUM_GCC') 163 164 svn_co_command = 'svn co svn://gcc.gnu.org/svn/gcc/%s .' % ( 165 gcc_branches_dir[self.gcc_version]) 166 167 gcc_required_dir = os.path.join(self.TOOLCHAIN_SRC_DIR, 'gcc', 168 'gcc-%s' % self.gcc_version) 169 170 return cmd.Chain( 171 cmd.MakeDir(gcc_required_dir), 172 cmd.Wrapper( 173 cmd.Chain(svn_co_command, svn_get_revision), 174 cwd=gcc_required_dir)) 175 176 def CheckoutAndroidToolchain(self): 177 p4client = self.p4client 178 command = p4client.SetupAndDo(p4client.Sync(), 179 p4client.SaveCurrentCLNumber('CLNUM'), 180 p4client.Remove()) 181 if self.gcc_version != '4.4.3': 182 command.append(self._CheckoutGCCFromSVN()) 183 184 return command 185 186 def BuildAndroidToolchain(self): 187 script_cmd = self.scripts.BuildAndroidToolchain( 188 self.toolchain_prefix_dir, self.CHECKOUT_DIR, self.TOOLCHAIN_BUILD_DIR, 189 self.TOOLCHAIN_SRC_DIR) 190 191 # Record toolchain and gcc CL number 192 record_cl_cmd = cmd.Copy( 193 os.path.join(self.CHECKOUT_DIR, 'CLNUM*'), 194 to_dir=self.toolchain_prefix_dir) 195 save_cmd = cmd.Tar( 196 os.path.join('$JOB_TMP', 'results', '%s.tar.bz2' % 197 self.toolchain_prefix_dir), self.toolchain_prefix_dir) 198 return cmd.Chain(script_cmd, record_cl_cmd, save_cmd) 199 200 def _BuildAndroidTree(self, local_android_branch_dir, product): 201 target_tools_prefix = os.path.join('$JOB_TMP', self.toolchain_prefix_dir, 202 'bin', 'arm-linux-androideabi-') 203 java_path = '/usr/lib/jvm/java-6-sun/bin' 204 build_cmd = cmd.Shell('make', '-j8', 'PRODUCT-%s-userdebug' % product, 205 'TARGET_TOOLS_PREFIX=%s' % target_tools_prefix, 206 'PATH=%s:$PATH' % java_path) 207 return cmd.Wrapper(build_cmd, cwd=local_android_branch_dir) 208 209 def BuildAndroidImage(self, product, branch): 210 assert product in ['stingray', 'passion', 'trygon', 'soju'] 211 212 # Copy the tree from atree.mtv.corp to ANDROID_TREES_DIR/branch 213 androidtrees_host = 'atree.mtv.corp.google.com' 214 androidtrees_path = ('/usr/local/google2/home/mobiletc-prebuild/' 215 'android_trees') 216 remote_android_branch_path = os.path.join(androidtrees_path, branch) 217 local_android_branch_dir = os.path.join(self.ANDROID_TREES_DIR, branch) 218 gettree_cmd = cmd.RemoteCopyFrom( 219 androidtrees_host, remote_android_branch_path, local_android_branch_dir) 220 221 # Configure and build the tree 222 buildtree_cmd = self._BuildAndroidTree(local_android_branch_dir, product) 223 224 # Compress and copy system.img to result 225 result_system_img = os.path.join(local_android_branch_dir, 'out', 'target', 226 'product', product, 'system.img') 227 copy_img = cmd.Copy(result_system_img, to_dir='results') 228 compress_img = cmd.Shell('bzip2', os.path.join('results', 'system.img')) 229 230 return cmd.Chain(gettree_cmd, buildtree_cmd, copy_img, compress_img) 231 232 def CheckoutScripts(self): 233 p4view = perforce.View('depot2', 234 [perforce.PathMapping('gcctools/android/tools/...', 235 'tools/...')]) 236 p4client = perforce.CommandsFactory(self.TOOLS_DIR, p4view) 237 return p4client.SetupAndDo(p4client.Sync(), p4client.Remove()) 238 239 def BuildRunBenchmark(self, arch, run_experiment): 240 # Copy base benchmark binaries from atree.mtv.corp 241 base_benchbin_host = 'atree.mtv.corp.google.com' 242 base_benchbin_path = ('/usr/local/google2/home/mobiletc-prebuild/' 243 'archive/v3binaries/2011-10-18') 244 local_basebenchbin_dir = 'base_benchmark_bin' 245 getbase_cmd = cmd.RemoteCopyFrom(base_benchbin_host, base_benchbin_path, 246 local_basebenchbin_dir) 247 248 # Build and run benchmark. 249 android_arch = 'android_%s' % arch 250 run_label = 'normal' 251 benchmark_cmd = self.scripts.RunBenchmark( 252 self.toolchain_prefix_dir, self.TOOLS_DIR, self.BENCHMARK_OUT_DIR, 253 run_label, run_experiment, android_arch, local_basebenchbin_dir) 254 255 # Extract jobid from BENCHMARK_OUT_DIR/log/jobid_normal.log file. 256 # Copy jobid to www server to generate performance dashboard. 257 # TODO(jingyu) 258 259 return cmd.Chain(getbase_cmd, benchmark_cmd) 260 261 262 class ScriptsFactory(object): 263 264 def __init__(self, gcc_version, binutils_version, gold_version): 265 self._gcc_version = gcc_version 266 self._binutils_version = binutils_version 267 self._gold_version = gold_version 268 269 def BuildAndroidToolchain(self, toolchain_prefix_dir, checkout_dir, 270 toolchain_build_dir, androidtc_src_dir): 271 if self._gcc_version == '4.4.3': 272 gold_option = 'both/gold' 273 else: 274 gold_option = 'default' 275 276 return cmd.Shell( 277 'build_androidtoolchain.sh', 278 '--toolchain-src=%s' % os.path.join('$JOB_TMP', androidtc_src_dir), 279 '--build-path=%s' % os.path.join('$JOB_TMP', toolchain_build_dir), 280 '--install-prefix=%s' % os.path.join('$JOB_TMP', toolchain_prefix_dir), 281 '--target=arm-linux-androideabi', 282 '--enable-gold=%s' % gold_option, 283 '--with-gcc-version=%s' % self._gcc_version, 284 '--with-binutils-version=%s' % self._binutils_version, 285 '--with-gold-version=%s' % self._gold_version, 286 '--with-gdb-version=7.1.x-android', 287 '--log-path=%s/logs' % '$JOB_HOME', 288 '--android-sysroot=%s' % os.path.join('$JOB_TMP', checkout_dir, 289 'gcctools', 'android', 'master', 290 'honeycomb_generic_sysroot'), 291 path=os.path.join(checkout_dir, 'gcctools', 'android', 'tools', 292 'scripts')) 293 294 def RunBenchmark(self, 295 toolchain_prefix_dir, 296 checkout_dir, 297 output_dir, 298 run_label, 299 run_experiment, 300 arch, 301 base_bench_bin=None): 302 if base_bench_bin: 303 base_bench_opt = '--base_benchmark_bin=%s' % base_bench_bin 304 else: 305 base_bench_opt = '' 306 307 return cmd.Shell( 308 'benchmark.sh', 309 '--android_toolchain=%s' % os.path.join('$JOB_TMP', 310 toolchain_prefix_dir), 311 '--bench_space=%s' % os.path.join('$JOB_TMP', 'bench'), 312 '--benchmark_bin=%s' % os.path.join('$JOB_TMP', output_dir, 313 'bench_bin'), 314 base_bench_opt, 315 '--log_path=%s' % os.path.join('$JOB_TMP', output_dir, 'log'), 316 '--arch=%s' % arch, 317 '--run_label=%s' % run_label, 318 '--run_experiment=%s' % run_experiment, 319 path=os.path.join(checkout_dir, 'tools', 'scripts')) 320