blob: 44239b87e3617e43758d70eb9dad903b1a726afe [file] [log] [blame]
Rico Wind3d369b42021-01-12 10:26:24 +01001#!/usr/bin/env python3
Christoffer Quist Adamsenf2e8db72020-11-07 14:09:49 +01002# Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
3# for details. All rights reserved. Use of this source code is governed by a
4# BSD-style license that can be found in the LICENSE file.
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01005
Ian Zerny161ff742022-01-20 12:39:40 +01006import argparse
7import hashlib
8import os
9import shutil
10import sys
11import time
12import zipfile
13from datetime import datetime
14
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +010015import adb
16import apk_masseur
Christoffer Quist Adamsenf79f1a22021-01-12 16:24:34 +010017import as_utils
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010018import compiledump
19import gradle
Rico Wind61a034f2021-03-16 09:37:11 +010020import jdk
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +020021import thread_utils
22from thread_utils import print_thread
Morten Krogh-Jespersen47764032020-11-11 15:09:39 +010023import update_prebuilds_in_android
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010024import utils
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010025
Ian Zerny161ff742022-01-20 12:39:40 +010026GOLEM_BUILD_TARGETS = ['R8Lib', 'R8Retrace']
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010027SHRINKERS = ['r8', 'r8-full', 'r8-nolib', 'r8-nolib-full']
28
29class AttrDict(dict):
30 def __getattr__(self, name):
31 return self.get(name, None)
32
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010033# To generate the files for a new app, navigate to the app source folder and
34# run:
35# ./gradlew clean :app:assembleRelease -Dcom.android.tools.r8.dumpinputtodirectory=<path>
36# and store the dump and the apk.
37# If the app has instrumented tests, adding `testBuildType "release"` and
38# running:
39# ./gradlew assembleAndroidTest -Dcom.android.tools.r8.dumpinputtodirectory=<path>
40# will also generate dumps and apk for tests.
41
42class App(object):
43 def __init__(self, fields):
44 defaults = {
45 'id': None,
46 'name': None,
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +010047 'collections': [],
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010048 'dump_app': None,
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +010049 'apk_app': None,
Morten Krogh-Jespersen571cfe72020-11-09 23:44:03 +010050 'dump_test': None,
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +010051 'apk_test': None,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010052 'skip': False,
53 'url': None, # url is not used but nice to have for updating apps
54 'revision': None,
55 'folder': None,
56 'skip_recompilation': False,
Morten Krogh-Jespersen43f3cea2020-11-12 17:09:51 +010057 'compiler_properties': [],
Morten Krogh-Jespersen86222742021-03-02 11:13:33 +010058 'internal': False,
Morten Krogh-Jespersen9e7951b2022-08-10 15:05:26 +020059 'golem_duration': None,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010060 }
61 # This below does not work in python3
62 defaults.update(fields.items())
63 self.__dict__ = defaults
64
65
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +010066class AppCollection(object):
67 def __init__(self, fields):
68 defaults = {
69 'name': None
70 }
71 # This below does not work in python3
72 defaults.update(fields.items())
73 self.__dict__ = defaults
74
75
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010076APPS = [
77 App({
Morten Krogh-Jespersen0f85fa52020-11-04 13:40:43 +010078 'id': 'com.numix.calculator',
79 'name': 'Calculator',
80 'dump_app': 'dump_app.zip',
81 'apk_app': 'app-release.apk',
82 # Compiling tests fail: Library class android.content.res.XmlResourceParser
83 # implements program class org.xmlpull.v1.XmlPullParser. Nothing to really
84 # do about that.
85 'id_test': 'com.numix.calculator.test',
86 'dump_test': 'dump_test.zip',
87 'apk_test': 'app-release-androidTest.apk',
88 'url': 'https://github.com/numixproject/android-suite/tree/master/Calculator',
89 'revision': 'f58e1b53f7278c9b675d5855842c6d8a44cccb1f',
90 'folder': 'android-suite-calculator',
91 }),
92 App({
Morten Krogh-Jespersen3f0d72f2020-11-04 15:49:17 +010093 'id': 'dev.dworks.apps.anexplorer.pro',
94 'name': 'AnExplorer',
95 'dump_app': 'dump_app.zip',
96 'apk_app': 'AnExplorer-googleMobileProRelease-4.0.3.apk',
97 'url': 'https://github.com/christofferqa/AnExplorer',
98 'revision': '365927477b8eab4052a1882d5e358057ae3dee4d',
99 'folder': 'anexplorer',
100 }),
101 App({
Morten Krogh-Jespersen09e2fda2020-11-04 16:43:25 +0100102 'id': 'de.danoeh.antennapod',
103 'name': 'AntennaPod',
104 'dump_app': 'dump_app.zip',
105 'apk_app': 'app-free-release.apk',
106 # TODO(b/172452102): Tests and monkey do not work
107 'id_test': 'de.danoeh.antennapod.test',
108 'dump_test': 'dump_test.zip',
109 'apk_test': 'app-free-release-androidTest.apk',
110 'url': 'https://github.com/christofferqa/AntennaPod.git',
111 'revision': '77e94f4783a16abe9cc5b78dc2d2b2b1867d8c06',
112 'folder': 'antennapod',
Morten Krogh-Jespersen09e2fda2020-11-04 16:43:25 +0100113 }),
114 App({
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100115 'id': 'com.example.applymapping',
116 'name': 'applymapping',
117 'dump_app': 'dump_app.zip',
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100118 'apk_app': 'app-release.apk',
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100119 'id_test': 'com.example.applymapping.test',
120 'dump_test': 'dump_test.zip',
121 'apk_test': 'app-release-androidTest.apk',
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100122 'url': 'https://github.com/mkj-gram/applymapping',
123 'revision': 'e3ae14b8c16fa4718e5dea8f7ad00937701b3c48',
124 'folder': 'applymapping',
Morten Krogh-Jespersen90912fd2020-11-05 09:21:16 +0100125 }),
126 App({
Morten Krogh-Jespersena98a4222020-11-05 10:50:10 +0100127 'id': 'com.chanapps.four.activity',
128 'name': 'chanu',
129 'dump_app': 'dump_app.zip',
130 'apk_app': 'app-release.apk',
131 'url': 'https://github.com/mkj-gram/chanu.git',
132 'revision': '6e53458f167b6d78398da60c20fd0da01a232617',
133 'folder': 'chanu',
Morten Krogh-Jespersen43f3cea2020-11-12 17:09:51 +0100134 # The app depends on a class file that has access flags interface but
135 # not abstract
136 'compiler_properties': ['-Dcom.android.tools.r8.allowInvalidCfAccessFlags=true']
Morten Krogh-Jespersena98a4222020-11-05 10:50:10 +0100137 }),
Christoffer Quist Adamsen00840062021-12-16 12:24:13 +0100138 App({
139 'id': 'com.example.myapplication',
140 'name': 'empty-activity',
141 'dump_app': 'dump_app.zip',
142 'apk_app': 'app-release.apk',
143 'url': 'https://github.com/christofferqa/empty_android_activity.git',
144 'revision': '2d297ec3373dadb03cbae916b9feba4792563156',
145 'folder': 'empty-activity',
146 }),
147 App({
148 'id': 'com.example.emptycomposeactivity',
149 'name': 'empty-compose-activity',
150 'dump_app': 'dump_app.zip',
151 'apk_app': 'app-release.apk',
152 'url': 'https://github.com/christofferqa/empty_android_compose_activity.git',
153 'revision': '3c8111b8b7d6e9184049a07e2b96702d7b33d03e',
154 'folder': 'empty-compose-activity',
155 }),
Morten Krogh-Jespersend06ff012020-11-05 10:50:21 +0100156 # TODO(b/172539375): Monkey runner fails on recompilation.
157 App({
158 'id': 'com.google.firebase.example.fireeats',
159 'name': 'FriendlyEats',
160 'dump_app': 'dump_app.zip',
161 'apk_app': 'app-release-unsigned.apk',
162 'url': 'https://github.com/firebase/friendlyeats-android',
163 'revision': '7c6dd016fc31ea5ecb948d5166b8479efc3775cc',
164 'folder': 'friendlyeats',
165 }),
Morten Krogh-Jespersena98a4222020-11-05 10:50:10 +0100166 App({
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100167 'id': 'com.google.samples.apps.sunflower',
168 'name': 'Sunflower',
169 'dump_app': 'dump_app.zip',
170 'apk_app': 'app-debug.apk',
171 # TODO(b/172549283): Compiling tests fails
Morten Krogh-Jespersend0389c02020-11-09 23:42:51 +0100172 'id_test': 'com.google.samples.apps.sunflower.test',
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100173 'dump_test': 'dump_test.zip',
174 'apk_test': 'app-debug-androidTest.apk',
175 'url': 'https://github.com/android/sunflower',
176 'revision': '0c4c88fdad2a74791199dffd1a6559559b1dbd4a',
177 'folder': 'sunflower',
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100178 }),
Morten Krogh-Jespersenac9de3f2020-11-05 17:07:26 +0100179 # TODO(b/172565385): Monkey runner fails on recompilation
180 App({
181 'id': 'com.google.samples.apps.iosched',
182 'name': 'iosched',
183 'dump_app': 'dump_app.zip',
184 'apk_app': 'mobile-release.apk',
185 'url': 'https://github.com/christofferqa/iosched.git',
186 'revision': '581cbbe2253711775dbccb753cdb53e7e506cb02',
187 'folder': 'iosched',
188 }),
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100189 App({
Morten Krogh-Jespersend0389c02020-11-09 23:42:51 +0100190 'id': 'fr.neamar.kiss',
191 'name': 'KISS',
192 'dump_app': 'dump_app.zip',
193 'apk_app': 'app-release.apk',
194 # TODO(b/172569220): Running tests fails due to missing keep rules
195 'id_test': 'fr.neamar.kiss.test',
196 'dump_test': 'dump_test.zip',
197 'apk_test': 'app-release-androidTest.apk',
198 'url': 'https://github.com/Neamar/KISS',
199 'revision': '8ccffaadaf0d0b8fc4418ed2b4281a0935d3d971',
200 'folder': 'kiss',
201 }),
Morten Krogh-Jespersenaaacd722020-11-09 23:43:24 +0100202 # TODO(b/172577344): Monkey runner not working.
203 App({
204 'id': 'io.github.hidroh.materialistic',
205 'name': 'materialistic',
206 'dump_app': 'dump_app.zip',
207 'apk_app': 'app-release.apk',
208 'url': 'https://github.com/christofferqa/materialistic.git',
209 'revision': '2b2b2ee25ce9e672d5aab1dc90a354af1522b1d9',
210 'folder': 'materialistic',
211 }),
Morten Krogh-Jespersend0389c02020-11-09 23:42:51 +0100212 App({
Morten Krogh-Jespersen571cfe72020-11-09 23:44:03 +0100213 'id': 'com.avjindersinghsekhon.minimaltodo',
214 'name': 'MinimalTodo',
215 'dump_app': 'dump_app.zip',
216 'apk_app': 'app-release.apk',
217 'url': 'https://github.com/christofferqa/Minimal-Todo',
218 'revision': '9d8c73746762cd376b718858ec1e8783ca07ba7c',
219 'folder': 'minimal-todo',
220 }),
221 App({
Morten Krogh-Jespersen3e3781f2020-11-09 23:44:33 +0100222 'id': 'net.nurik.roman.muzei',
223 'name': 'muzei',
224 'dump_app': 'dump_app.zip',
225 'apk_app': 'muzei-release.apk',
226 'url': 'https://github.com/romannurik/muzei',
227 'revision': '9eac6e98aebeaf0ae40bdcd85f16dd2886551138',
228 'folder': 'muzei',
229 }),
Morten Krogh-Jespersenf8e77032020-11-09 23:44:58 +0100230 # TODO(b/172806281): Monkey runner does not work.
231 App({
232 'id': 'org.schabi.newpipe',
233 'name': 'NewPipe',
234 'dump_app': 'dump_app.zip',
235 'apk_app': 'app-release-unsigned.apk',
236 'url': 'https://github.com/TeamNewPipe/NewPipe',
237 'revision': 'f4435f90313281beece70c544032f784418d85fa',
238 'folder': 'newpipe',
Morten Krogh-Jespersenf8e77032020-11-09 23:44:58 +0100239 }),
Morten Krogh-Jespersendf700642020-11-09 23:45:25 +0100240 # TODO(b/172806808): Monkey runner does not work.
241 App({
242 'id': 'io.rover.app.debug',
243 'name': 'Rover',
244 'dump_app': 'dump_app.zip',
245 'apk_app': 'example-app-release-unsigned.apk',
246 'url': 'https://github.com/RoverPlatform/rover-android',
247 'revision': '94342117097770ea3ca2c6df6ab496a1a55c3ce7',
248 'folder': 'rover-android',
249 }),
Morten Krogh-Jespersen2f1be952020-11-09 23:45:48 +0100250 # TODO(b/172808159): Monkey runner does not work
251 App({
252 'id': 'com.google.android.apps.santatracker',
253 'name': 'SantaTracker',
254 'dump_app': 'dump_app.zip',
255 'apk_app': 'santa-tracker-release.apk',
256 'url': 'https://github.com/christofferqa/santa-tracker-android',
257 'revision': '8dee74be7d9ee33c69465a07088c53087d24a6dd',
258 'folder': 'santa-tracker',
259 }),
260 App({
Morten Krogh-Jespersen88cc0772020-11-09 23:46:13 +0100261 'id': 'org.thoughtcrime.securesms',
262 'name': 'Signal',
263 'dump_app': 'dump_app.zip',
264 'apk_app': 'Signal-Android-play-prod-universal-release-4.76.2.apk',
265 # TODO(b/172812839): Instrumentation test fails.
266 'id_test': 'org.thoughtcrime.securesms.test',
267 'dump_test': 'dump_test.zip',
268 'apk_test': 'Signal-Android-play-prod-release-androidTest.apk',
269 'url': 'https://github.com/signalapp/Signal-Android',
270 'revision': '91ca19f294362ccee2c2b43c247eba228e2b30a1',
271 'folder': 'signal-android',
272 }),
Morten Krogh-Jespersen733bcff2020-11-09 23:46:43 +0100273 # TODO(b/172815827): Monkey runner does not work
274 App({
275 'id': 'com.simplemobiletools.calendar.pro',
276 'name': 'Simple-Calendar',
277 'dump_app': 'dump_app.zip',
278 'apk_app': 'calendar-release.apk',
279 'url': 'https://github.com/SimpleMobileTools/Simple-Calendar',
280 'revision': '906209874d0a091c7fce5a57972472f272d6b068',
281 'folder': 'simple-calendar',
282 }),
Morten Krogh-Jespersen8a564d32020-11-09 23:47:07 +0100283 # TODO(b/172815534): Monkey runner does not work
284 App({
285 'id': 'com.simplemobiletools.camera.pro',
286 'name': 'Simple-Camera',
287 'dump_app': 'dump_app.zip',
288 'apk_app': 'camera-release.apk',
289 'url': 'https://github.com/SimpleMobileTools/Simple-Camera',
290 'revision': 'ebf9820c51e960912b3238287e30a131244fdee6',
291 'folder': 'simple-camera',
292 }),
Morten Krogh-Jespersen88cc0772020-11-09 23:46:13 +0100293 App({
Morten Krogh-Jespersen805e31a2020-11-09 23:47:32 +0100294 'id': 'com.simplemobiletools.filemanager.pro',
295 'name': 'Simple-File-Manager',
296 'dump_app': 'dump_app.zip',
297 'apk_app': 'file-manager-release.apk',
298 'url': 'https://github.com/SimpleMobileTools/Simple-File-Manager',
299 'revision': '2b7fa68ea251222cc40cf6d62ad1de260a6f54d9',
300 'folder': 'simple-file-manager',
301 }),
302 App({
Morten Krogh-Jespersendc29e992020-11-09 23:48:01 +0100303 'id': 'com.simplemobiletools.gallery.pro',
304 'name': 'Simple-Gallery',
305 'dump_app': 'dump_app.zip',
306 'apk_app': 'gallery-326-foss-release.apk',
307 'url': 'https://github.com/SimpleMobileTools/Simple-Gallery',
308 'revision': '564e56b20d33b28d0018c8087ec705beeb60785e',
309 'folder': 'simple-gallery',
Morten Krogh-Jespersendc29e992020-11-09 23:48:01 +0100310 }),
311 App({
Morten Krogh-Jespersen4a9657a2020-11-09 23:48:21 +0100312 'id': 'com.example.sqldelight.hockey',
313 'name': 'SQLDelight',
314 'dump_app': 'dump_app.zip',
315 'apk_app': 'android-release.apk',
316 'url': 'https://github.com/christofferqa/sqldelight',
317 'revision': '2e67a1126b6df05e4119d1e3a432fde51d76cdc8',
318 'folder': 'sqldelight',
319 }),
Morten Krogh-Jespersenf12a57e2020-11-09 23:48:53 +0100320 # TODO(b/172824096): Monkey runner does not work.
321 App({
322 'id': 'eu.kanade.tachiyomi',
323 'name': 'Tachiyomi',
324 'dump_app': 'dump_app.zip',
325 'apk_app': 'app-dev-release.apk',
326 'url': 'https://github.com/inorichi/tachiyomi',
327 'revision': '8aa6486bf76ab9a61a5494bee284b1a5e9180bf3',
328 'folder': 'tachiyomi',
329 }),
Morten Krogh-Jespersen58974522020-11-10 00:20:46 +0100330 # TODO(b/172862042): Monkey runner does not work.
331 App({
332 'id': 'app.tivi',
333 'name': 'Tivi',
334 'dump_app': 'dump_app.zip',
335 'apk_app': 'app-release.apk',
336 'url': 'https://github.com/chrisbanes/tivi',
Morten Krogh-Jespersen44e2f892020-12-17 09:18:35 +0100337 'revision': '5c6d9ed338885c59b1fc64050d92d056417bb4de',
Morten Krogh-Jespersen58974522020-11-10 00:20:46 +0100338 'folder': 'tivi',
Rico Windf664f792023-08-04 14:12:27 +0200339 'golem_duration': 300
Morten Krogh-Jespersen58974522020-11-10 00:20:46 +0100340 }),
Morten Krogh-Jespersen4a9657a2020-11-09 23:48:21 +0100341 App({
Morten Krogh-Jespersen9033d1a2020-11-09 23:49:23 +0100342 'id': 'com.keylesspalace.tusky',
343 'name': 'Tusky',
344 'dump_app': 'dump_app.zip',
345 'apk_app': 'app-blue-release.apk',
346 'url': 'https://github.com/tuskyapp/Tusky',
347 'revision': '814a9b8f9bacf8d26f712b06a0313a3534a2be95',
348 'folder': 'tusky',
Morten Krogh-Jespersen9033d1a2020-11-09 23:49:23 +0100349 }),
350 App({
Morten Krogh-Jespersen90912fd2020-11-05 09:21:16 +0100351 'id': 'org.wikipedia',
352 'name': 'Wikipedia',
353 'dump_app': 'dump_app.zip',
354 'apk_app': 'app-prod-release.apk',
355 'url': 'https://github.com/wikimedia/apps-android-wikipedia',
356 'revision': '0fa7cad843c66313be8e25790ef084cf1a1fa67e',
357 'folder': 'wikipedia',
358 }),
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100359 # TODO(b/173167253): Check if monkey testing works.
360 App({
361 'id': 'androidx.compose.samples.crane',
362 'name': 'compose-crane',
363 'collections': ['compose-samples'],
364 'dump_app': 'dump_app.zip',
365 'apk_app': 'app-release-unsigned.apk',
366 'url': 'https://github.com/android/compose-samples',
367 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
368 'folder': 'android/compose-samples/crane',
Morten Krogh-Jespersen9e7951b2022-08-10 15:05:26 +0200369 'golem_duration': 240
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100370 }),
371 # TODO(b/173167253): Check if monkey testing works.
372 App({
373 'id': 'com.example.jetcaster',
374 'name': 'compose-jetcaster',
375 'collections': ['compose-samples'],
376 'dump_app': 'dump_app.zip',
377 'apk_app': 'app-release-unsigned.apk',
378 'url': 'https://github.com/android/compose-samples',
379 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
380 'folder': 'android/compose-samples/jetcaster',
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100381 }),
382 # TODO(b/173167253): Check if monkey testing works.
383 App({
384 'id': 'com.example.compose.jetchat',
385 'name': 'compose-jetchat',
386 'collections': ['compose-samples'],
387 'dump_app': 'dump_app.zip',
388 'apk_app': 'app-release-unsigned.apk',
389 'url': 'https://github.com/android/compose-samples',
390 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
391 'folder': 'android/compose-samples/jetchat',
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100392 }),
393 # TODO(b/173167253): Check if monkey testing works.
394 App({
395 'id': 'com.example.jetnews',
396 'name': 'compose-jetnews',
397 'collections': ['compose-samples'],
398 'dump_app': 'dump_app.zip',
399 'apk_app': 'app-release-unsigned.apk',
400 'url': 'https://github.com/android/compose-samples',
401 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
402 'folder': 'android/compose-samples/jetnews',
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100403 }),
404 # TODO(b/173167253): Check if monkey testing works.
405 App({
406 'id': 'com.example.jetsnack',
407 'name': 'compose-jetsnack',
408 'collections': ['compose-samples'],
409 'dump_app': 'dump_app.zip',
410 'apk_app': 'app-release-unsigned.apk',
411 'url': 'https://github.com/android/compose-samples',
412 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
413 'folder': 'android/compose-samples/jetsnack',
414 }),
415 # TODO(b/173167253): Check if monkey testing works.
416 App({
417 'id': 'com.example.compose.jetsurvey',
418 'name': 'compose-jetsurvey',
419 'collections': ['compose-samples'],
420 'dump_app': 'dump_app.zip',
421 'apk_app': 'app-release-unsigned.apk',
422 'url': 'https://github.com/android/compose-samples',
423 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
424 'folder': 'android/compose-samples/jetsurvey',
425 }),
426 # TODO(b/173167253): Check if monkey testing works.
427 App({
428 'id': 'com.example.owl',
429 'name': 'compose-owl',
430 'collections': ['compose-samples'],
431 'dump_app': 'dump_app.zip',
432 'apk_app': 'app-release-unsigned.apk',
433 'url': 'https://github.com/android/compose-samples',
434 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
435 'folder': 'android/compose-samples/owl',
436 }),
437 # TODO(b/173167253): Check if monkey testing works.
438 App({
439 'id': 'com.example.compose.rally',
440 'name': 'compose-rally',
441 'collections': ['compose-samples'],
442 'dump_app': 'dump_app.zip',
443 'apk_app': 'app-release-unsigned.apk',
444 'url': 'https://github.com/android/compose-samples',
445 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
446 'folder': 'android/compose-samples/rally',
447 }),
448]
449
450
451APP_COLLECTIONS = [
452 AppCollection({
453 'name': 'compose-samples',
454 })
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100455]
456
Morten Krogh-Jespersenf8e77032020-11-09 23:44:58 +0100457
Morten Krogh-Jespersendfeb0e32020-11-04 14:55:55 +0100458def remove_print_lines(file):
459 with open(file) as f:
460 lines = f.readlines()
461 with open(file, 'w') as f:
462 for line in lines:
463 if '-printconfiguration' not in line:
464 f.write(line)
465
466
Rico Wind61a034f2021-03-16 09:37:11 +0100467def download_sha(app_sha, internal, quiet=False):
Morten Krogh-Jespersen86222742021-03-02 11:13:33 +0100468 if internal:
469 utils.DownloadFromX20(app_sha)
470 else:
Rico Wind59593922021-03-03 09:12:36 +0100471 utils.DownloadFromGoogleCloudStorage(app_sha, quiet=quiet)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100472
473
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100474def is_logging_enabled_for(app, options):
475 if options.no_logging:
476 return False
477 if options.app_logging_filter and app.name not in options.app_logging_filter:
478 return False
479 return True
480
481
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100482def is_minified_r8(shrinker):
483 return '-nolib' not in shrinker
484
485
486def is_full_r8(shrinker):
Morten Krogh-Jespersen270d0932020-11-11 11:05:57 +0100487 return '-full' in shrinker
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100488
489
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100490def version_is_built_jar(version):
Rico Wind1b52acf2021-03-21 12:36:55 +0100491 return version != 'main' and version != 'source'
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100492
493
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100494def compute_size_of_dex_files_in_package(path):
495 dex_size = 0
496 z = zipfile.ZipFile(path, 'r')
497 for filename in z.namelist():
498 if filename.endswith('.dex'):
499 dex_size += z.getinfo(filename).file_size
500 return dex_size
501
502
503def dump_for_app(app_dir, app):
504 return os.path.join(app_dir, app.dump_app)
505
506
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100507def dump_test_for_app(app_dir, app):
508 return os.path.join(app_dir, app.dump_test)
509
510
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100511def get_r8_jar(options, temp_dir, shrinker):
512 if (options.version == 'source'):
513 return None
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200514 jar = os.path.abspath(
515 os.path.join(
516 temp_dir,
517 '..',
518 'r8lib.jar' if is_minified_r8(shrinker) else 'r8.jar'))
519 return jar
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100520
521
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200522def get_results_for_app(app, options, temp_dir, worker_id):
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100523 app_folder = app.folder if app.folder else app.name + "_" + app.revision
Rico Windb2ae4c62021-06-01 15:09:56 +0200524 # Golem extraction will extract to the basename under the benchmarks dir.
525 app_location = os.path.basename(app_folder) if options.golem else app_folder
Rico Winde32a9c72021-03-16 09:00:06 +0100526 opensource_basedir = (os.path.join('benchmarks', app.name) if options.golem
527 else utils.OPENSOURCE_DUMPS_DIR)
Rico Windb2ae4c62021-06-01 15:09:56 +0200528 app_dir = (os.path.join(utils.INTERNAL_DUMPS_DIR, app_location) if app.internal
529 else os.path.join(opensource_basedir, app_location))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100530 if not os.path.exists(app_dir) and not options.golem:
531 # Download the app from google storage.
Rico Wind61a034f2021-03-16 09:37:11 +0100532 download_sha(app_dir + ".tar.gz.sha1", app.internal)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100533
534 # Ensure that the dumps are in place
535 assert os.path.isfile(dump_for_app(app_dir, app)), "Could not find dump " \
536 "for app " + app.name
537
538 result = {}
539 result['status'] = 'success'
540 result_per_shrinker = build_app_with_shrinkers(
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200541 app, options, temp_dir, app_dir, worker_id=worker_id)
Christoffer Quist Adamsena9ff1cf2021-01-13 08:49:48 +0100542 for shrinker, shrinker_result in result_per_shrinker.items():
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100543 result[shrinker] = shrinker_result
544 return result
545
546
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200547def build_app_with_shrinkers(app, options, temp_dir, app_dir, worker_id):
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100548 result_per_shrinker = {}
549 for shrinker in options.shrinker:
550 results = []
551 build_app_and_run_with_shrinker(
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200552 app, options, temp_dir, app_dir, shrinker, results, worker_id=worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100553 result_per_shrinker[shrinker] = results
554 if len(options.apps) > 1:
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200555 print_thread('', worker_id)
556 log_results_for_app(app, result_per_shrinker, options, worker_id=worker_id)
557 print_thread('', worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100558
559 return result_per_shrinker
560
561
562def is_last_build(index, compilation_steps):
563 return index == compilation_steps - 1
564
565
566def build_app_and_run_with_shrinker(app, options, temp_dir, app_dir, shrinker,
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200567 results, worker_id):
568 print_thread(
569 '[{}] Building {} with {}'.format(
570 datetime.now().strftime("%H:%M:%S"),
571 app.name,
572 shrinker),
573 worker_id)
574 print_thread(
575 'To compile locally: '
576 'tools/run_on_app_dump.py --shrinker {} --r8-compilation-steps {} '
577 '--app {} --minify {} --optimize {} --shrink {}'.format(
578 shrinker,
579 options.r8_compilation_steps,
580 app.name,
581 options.minify,
582 options.optimize,
583 options.shrink),
584 worker_id)
585 print_thread(
586 'HINT: use --shrinker r8-nolib --no-build if you have a local R8.jar',
587 worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100588 recomp_jar = None
589 status = 'success'
Morten Krogh-Jespersenee89b3a2020-11-13 11:59:43 +0100590 if options.r8_compilation_steps < 1:
591 return
592 compilation_steps = 1 if app.skip_recompilation else options.r8_compilation_steps
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100593 for compilation_step in range(0, compilation_steps):
594 if status != 'success':
595 break
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200596 print_thread(
597 'Compiling {} of {}'.format(compilation_step + 1, compilation_steps),
598 worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100599 result = {}
600 try:
601 start = time.time()
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100602 (app_jar, mapping, new_recomp_jar) = \
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100603 build_app_with_shrinker(
604 app, options, temp_dir, app_dir, shrinker, compilation_step,
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200605 compilation_steps, recomp_jar, worker_id=worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100606 end = time.time()
607 dex_size = compute_size_of_dex_files_in_package(app_jar)
608 result['build_status'] = 'success'
609 result['recompilation_status'] = 'success'
610 result['output_jar'] = app_jar
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100611 result['output_mapping'] = mapping
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100612 result['dex_size'] = dex_size
613 result['duration'] = int((end - start) * 1000) # Wall time
614 if (new_recomp_jar is None
615 and not is_last_build(compilation_step, compilation_steps)):
616 result['recompilation_status'] = 'failed'
617 warn('Failed to build {} with {}'.format(app.name, shrinker))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100618 recomp_jar = new_recomp_jar
619 except Exception as e:
620 warn('Failed to build {} with {}'.format(app.name, shrinker))
621 if e:
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200622 print_thread('Error: ' + str(e), worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100623 result['build_status'] = 'failed'
624 status = 'failed'
625
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100626 original_app_apk = os.path.join(app_dir, app.apk_app)
627 app_apk_destination = os.path.join(
628 temp_dir,"{}_{}.apk".format(app.id, compilation_step))
629
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100630 if result.get('build_status') == 'success' and options.monkey:
631 # Make a copy of the given APK, move the newly generated dex files into the
632 # copied APK, and then sign the APK.
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100633 apk_masseur.masseur(
634 original_app_apk, dex=app_jar, resources='META-INF/services/*',
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100635 out=app_apk_destination,
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100636 quiet=options.quiet, logging=is_logging_enabled_for(app, options),
637 keystore=options.keystore)
638
639 result['monkey_status'] = 'success' if adb.run_monkey(
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100640 app.id, options.emulator_id, app_apk_destination, options.monkey_events,
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100641 options.quiet, is_logging_enabled_for(app, options)) else 'failed'
642
Morten Krogh-Jespersen571cfe72020-11-09 23:44:03 +0100643 if (result.get('build_status') == 'success'
644 and options.run_tests and app.dump_test):
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100645 if not os.path.isfile(app_apk_destination):
646 apk_masseur.masseur(
647 original_app_apk, dex=app_jar, resources='META-INF/services/*',
648 out=app_apk_destination,
649 quiet=options.quiet, logging=is_logging_enabled_for(app, options),
650 keystore=options.keystore)
651
652 # Compile the tests with the mapping file.
653 test_jar = build_test_with_shrinker(
654 app, options, temp_dir, app_dir,shrinker, compilation_step,
655 result['output_mapping'])
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100656 if not test_jar:
657 result['instrumentation_test_status'] = 'compilation_failed'
658 else:
659 original_test_apk = os.path.join(app_dir, app.apk_test)
660 test_apk_destination = os.path.join(
661 temp_dir,"{}_{}.test.apk".format(app.id_test, compilation_step))
662 apk_masseur.masseur(
663 original_test_apk, dex=test_jar, resources='META-INF/services/*',
664 out=test_apk_destination,
665 quiet=options.quiet, logging=is_logging_enabled_for(app, options),
666 keystore=options.keystore)
667 result['instrumentation_test_status'] = 'success' if adb.run_instrumented(
668 app.id, app.id_test, options.emulator_id, app_apk_destination,
669 test_apk_destination, options.quiet,
670 is_logging_enabled_for(app, options)) else 'failed'
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100671
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100672 results.append(result)
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100673 if result.get('recompilation_status') != 'success':
674 break
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100675
Rico Wind33936d12021-04-07 08:04:14 +0200676def get_jdk_home(options, app):
Rico Winda74174d2021-04-07 09:10:35 +0200677 if options.golem:
Rico Wind33936d12021-04-07 08:04:14 +0200678 return os.path.join('benchmarks', app.name, 'linux')
679 return None
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100680
681def build_app_with_shrinker(app, options, temp_dir, app_dir, shrinker,
682 compilation_step_index, compilation_steps,
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200683 prev_recomp_jar, worker_id):
Christoffer Quist Adamsen3f21c2b2023-02-28 09:37:22 +0100684 def config_files_consumer(files):
685 for file in files:
686 compiledump.clean_config(file, options)
687 remove_print_lines(file)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100688 args = AttrDict({
689 'dump': dump_for_app(app_dir, app),
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100690 'r8_jar': get_r8_jar(options, temp_dir, shrinker),
Christoffer Quist Adamsen2f48f3f2021-10-14 17:25:03 +0200691 'r8_flags': options.r8_flags,
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200692 'ea': not options.disable_assertions,
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100693 'version': options.version,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100694 'compiler': 'r8full' if is_full_r8(shrinker) else 'r8',
695 'debug_agent': options.debug_agent,
696 'program_jar': prev_recomp_jar,
Morten Krogh-Jespersendfeb0e32020-11-04 14:55:55 +0100697 'nolib': not is_minified_r8(shrinker),
Christoffer Quist Adamsen3f21c2b2023-02-28 09:37:22 +0100698 'config_files_consumer': config_files_consumer,
Morten Krogh-Jespersen43f3cea2020-11-12 17:09:51 +0100699 'properties': app.compiler_properties,
Morten Krogh-Jespersend86a81b2020-11-13 12:33:26 +0100700 'disable_desugared_lib': False,
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200701 'print_times': options.print_times,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100702 })
703
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100704 app_jar = os.path.join(
705 temp_dir, '{}_{}_{}_dex_out.jar'.format(
706 app.name, shrinker, compilation_step_index))
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100707 app_mapping = os.path.join(
708 temp_dir, '{}_{}_{}_dex_out.jar.map'.format(
709 app.name, shrinker, compilation_step_index))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100710 recomp_jar = None
Rico Wind33936d12021-04-07 08:04:14 +0200711 jdkhome = get_jdk_home(options, app)
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100712 with utils.TempDir() as compile_temp_dir:
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200713 compile_result = compiledump.run1(
714 compile_temp_dir, args, [], jdkhome, worker_id=worker_id)
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100715 out_jar = os.path.join(compile_temp_dir, "out.jar")
716 out_mapping = os.path.join(compile_temp_dir, "out.jar.map")
717
718 if compile_result != 0 or not os.path.isfile(out_jar):
719 assert False, 'Compilation of {} failed'.format(dump_for_app(app_dir, app))
720 shutil.move(out_jar, app_jar)
721 shutil.move(out_mapping, app_mapping)
722
723 if compilation_step_index < compilation_steps - 1:
724 args['classfile'] = True
725 args['min_api'] = "10000"
Morten Krogh-Jespersend86a81b2020-11-13 12:33:26 +0100726 args['disable_desugared_lib'] = True
Rico Wind33936d12021-04-07 08:04:14 +0200727 compile_result = compiledump.run1(compile_temp_dir, args, [], jdkhome)
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100728 if compile_result == 0:
729 recomp_jar = os.path.join(
730 temp_dir, '{}_{}_{}_cf_out.jar'.format(
731 app.name, shrinker, compilation_step_index))
732 shutil.move(out_jar, recomp_jar)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100733
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100734 return (app_jar, app_mapping, recomp_jar)
735
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100736
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100737def build_test_with_shrinker(app, options, temp_dir, app_dir, shrinker,
738 compilation_step_index, mapping):
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100739
Christoffer Quist Adamsen3f21c2b2023-02-28 09:37:22 +0100740 def rewrite_files(files):
741 add_applymapping = True
742 for file in files:
743 compiledump.clean_config(file, options)
744 remove_print_lines(file)
745 with open(file) as f:
746 lines = f.readlines()
747 with open(file, 'w') as f:
748 for line in lines:
749 if '-applymapping' not in line:
750 f.write(line + '\n')
751 if add_applymapping:
752 f.write("-applymapping " + mapping + '\n')
753 add_applymapping = False
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100754
755 args = AttrDict({
756 'dump': dump_test_for_app(app_dir, app),
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100757 'r8_jar': get_r8_jar(options, temp_dir, shrinker),
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200758 'ea': not options.disable_assertions,
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100759 'version': options.version,
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100760 'compiler': 'r8full' if is_full_r8(shrinker) else 'r8',
761 'debug_agent': options.debug_agent,
762 'nolib': not is_minified_r8(shrinker),
763 # The config file will have an -applymapping reference to an old map.
764 # Update it to point to mapping file build in the compilation of the app.
Christoffer Quist Adamsen3f21c2b2023-02-28 09:37:22 +0100765 'config_files_consumer': rewrite_files,
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100766 })
767
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100768 test_jar = os.path.join(
769 temp_dir, '{}_{}_{}_test_out.jar'.format(
770 app.name, shrinker, compilation_step_index))
771
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100772 with utils.TempDir() as compile_temp_dir:
Rico Wind33936d12021-04-07 08:04:14 +0200773 jdkhome = get_jdk_home(options, app)
774 compile_result = compiledump.run1(compile_temp_dir, args, [], jdkhome)
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100775 out_jar = os.path.join(compile_temp_dir, "out.jar")
776 if compile_result != 0 or not os.path.isfile(out_jar):
777 return None
778 shutil.move(out_jar, test_jar)
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100779
780 return test_jar
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100781
782
783def log_results_for_apps(result_per_shrinker_per_app, options):
784 print('')
785 app_errors = 0
786 for (app, result_per_shrinker) in result_per_shrinker_per_app:
787 app_errors += (1 if log_results_for_app(app, result_per_shrinker, options)
788 else 0)
789 return app_errors
790
791
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200792def log_results_for_app(app, result_per_shrinker, options, worker_id=None):
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100793 if options.print_dexsegments:
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200794 log_segments_for_app(app, result_per_shrinker, options, worker_id=worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100795 return False
796 else:
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200797 return log_comparison_results_for_app(app, result_per_shrinker, options, worker_id=worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100798
799
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200800def log_segments_for_app(app, result_per_shrinker, options, worker_id):
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100801 for shrinker in SHRINKERS:
802 if shrinker not in result_per_shrinker:
803 continue
804 for result in result_per_shrinker.get(shrinker):
805 benchmark_name = '{}-{}'.format(options.print_dexsegments, app.name)
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200806 utils.print_dexsegments(
807 benchmark_name, [result.get('output_jar')], worker_id=worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100808 duration = result.get('duration')
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200809 print_thread(
810 '%s-Total(RunTimeRaw): %s ms' % (benchmark_name, duration),
811 worker_id)
812 print_thread(
813 '%s-Total(CodeSize): %s' % (benchmark_name, result.get('dex_size')),
814 worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100815
816
817def percentage_diff_as_string(before, after):
818 if after < before:
819 return '-' + str(round((1.0 - after / before) * 100)) + '%'
820 else:
821 return '+' + str(round((after - before) / before * 100)) + '%'
822
823
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200824def log_comparison_results_for_app(app, result_per_shrinker, options, worker_id):
825 print_thread(app.name + ':', worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100826 app_error = False
827 if result_per_shrinker.get('status', 'success') != 'success':
828 error_message = result_per_shrinker.get('error_message')
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200829 print_thread(' skipped ({})'.format(error_message), worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100830 return
831
832 proguard_result = result_per_shrinker.get('pg', {})
833 proguard_dex_size = float(proguard_result.get('dex_size', -1))
834
835 for shrinker in SHRINKERS:
836 if shrinker not in result_per_shrinker:
837 continue
838 compilation_index = 1
839 for result in result_per_shrinker.get(shrinker):
840 build_status = result.get('build_status')
841 if build_status != 'success' and build_status is not None:
842 app_error = True
843 warn(' {}-#{}: {}'.format(shrinker, compilation_index, build_status))
844 continue
845
Rico Wind59593922021-03-03 09:12:36 +0100846 if options.golem:
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200847 print_thread(
848 '%s(RunTimeRaw): %s ms' % (app.name, result.get('duration')),
849 worker_id)
850 print_thread(
851 '%s(CodeSize): %s' % (app.name, result.get('dex_size')), worker_id)
Rico Wind59593922021-03-03 09:12:36 +0100852 continue
853
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200854 print_thread(' {}-#{}:'.format(shrinker, compilation_index), worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100855 dex_size = result.get('dex_size')
856 msg = ' dex size: {}'.format(dex_size)
Rudi Horn82e7d222020-11-17 11:22:39 +0000857 if options.print_runtimeraw:
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200858 print_thread(
859 ' run time raw: {} ms'.format(result.get('duration')), worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100860 if dex_size != proguard_dex_size and proguard_dex_size >= 0:
861 msg = '{} ({}, {})'.format(
862 msg, dex_size - proguard_dex_size,
863 percentage_diff_as_string(proguard_dex_size, dex_size))
864 success(msg) if dex_size < proguard_dex_size else warn(msg)
865 else:
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +0200866 print_thread(msg, worker_id)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100867
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100868 if options.monkey:
869 monkey_status = result.get('monkey_status')
870 if monkey_status != 'success':
871 app_error = True
872 warn(' monkey: {}'.format(monkey_status))
873 else:
874 success(' monkey: {}'.format(monkey_status))
875
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100876 if options.run_tests and 'instrumentation_test_status' in result:
877 test_status = result.get('instrumentation_test_status')
878 if test_status != 'success':
879 warn(' instrumentation_tests: {}'.format(test_status))
880 else:
881 success(' instrumentation_tests: {}'.format(test_status))
882
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100883 recompilation_status = result.get('recompilation_status', '')
884 if recompilation_status == 'failed':
885 app_error = True
886 warn(' recompilation {}-#{}: failed'.format(shrinker,
887 compilation_index))
888 continue
889
890 compilation_index += 1
891
892 return app_error
893
894
895def parse_options(argv):
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200896 result = argparse.ArgumentParser(description = 'Run/compile dump artifacts.')
897 result.add_argument('--app',
898 help='What app to run on',
899 choices=[app.name for app in APPS],
900 action='append')
901 result.add_argument('--app-collection', '--app_collection',
902 help='What app collection to run',
903 choices=[collection.name for collection in
904 APP_COLLECTIONS],
905 action='append')
906 result.add_argument('--app-logging-filter', '--app_logging_filter',
907 help='The apps for which to turn on logging',
908 action='append')
909 result.add_argument('--bot',
910 help='Running on bot, use third_party dependency.',
911 default=False,
912 action='store_true')
913 result.add_argument('--generate-golem-config', '--generate_golem_config',
914 help='Generate a new config for golem.',
915 default=False,
916 action='store_true')
917 result.add_argument('--debug-agent',
918 help='Enable Java debug agent and suspend compilation '
919 '(default disabled)',
920 default=False,
921 action='store_true')
922 result.add_argument('--disable-assertions', '--disable_assertions',
923 help='Disable assertions when compiling',
924 default=False,
925 action='store_true')
926 result.add_argument('--emulator-id', '--emulator_id',
927 help='Id of the emulator to use',
928 default='emulator-5554')
929 result.add_argument('--golem',
930 help='Running on golem, do not download',
931 default=False,
932 action='store_true')
933 result.add_argument('--hash',
934 help='The commit of R8 to use')
935 result.add_argument('--internal',
936 help='Run internal apps if set, otherwise run opensource',
937 default=False,
938 action='store_true')
939 result.add_argument('--keystore',
940 help='Path to app.keystore',
941 default=os.path.join(utils.TOOLS_DIR, 'debug.keystore'))
942 result.add_argument('--keystore-password', '--keystore_password',
943 help='Password for app.keystore',
944 default='android')
Christoffer Quist Adamsenf86fc0b2021-12-10 12:39:36 +0100945 result.add_argument('--minify',
946 help='Force enable/disable minification' +
947 ' (defaults to app proguard config)',
948 choices=['default', 'force-enable', 'force-disable'],
949 default='default')
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200950 result.add_argument('--monkey',
951 help='Whether to install and run app(s) with monkey',
952 default=False,
953 action='store_true')
954 result.add_argument('--monkey-events', '--monkey_events',
955 help='Number of events that the monkey should trigger',
956 default=250,
957 type=int)
958 result.add_argument('--no-build', '--no_build',
959 help='Run without building first (only when using ToT)',
960 default=False,
961 action='store_true')
962 result.add_argument('--no-logging', '--no_logging',
963 help='Disable logging except for errors',
964 default=False,
965 action='store_true')
Christoffer Quist Adamsenf86fc0b2021-12-10 12:39:36 +0100966 result.add_argument('--optimize',
967 help='Force enable/disable optimizations' +
968 ' (defaults to app proguard config)',
969 choices=['default', 'force-enable', 'force-disable'],
970 default='default')
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200971 result.add_argument('--print-times',
972 help='Print timing information from r8',
973 default=False,
974 action='store_true')
975 result.add_argument('--print-dexsegments',
976 metavar='BENCHMARKNAME',
977 help='Print the sizes of individual dex segments as ' +
978 '\'<BENCHMARKNAME>-<APP>-<segment>(CodeSize): '
979 '<bytes>\'')
980 result.add_argument('--print-runtimeraw',
981 metavar='BENCHMARKNAME',
982 help='Print the line \'<BENCHMARKNAME>(RunTimeRaw):' +
983 ' <elapsed> ms\' at the end where <elapsed> is' +
984 ' the elapsed time in milliseconds.')
985 result.add_argument('--quiet',
986 help='Disable verbose logging',
987 default=False,
988 action='store_true')
989 result.add_argument('--r8-compilation-steps', '--r8_compilation_steps',
990 help='Number of times R8 should be run on each app',
991 default=2,
992 type=int)
Christoffer Quist Adamsen2f48f3f2021-10-14 17:25:03 +0200993 result.add_argument('--r8-flags', '--r8_flags',
994 help='Additional option(s) for the compiler.')
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200995 result.add_argument('--run-tests', '--run_tests',
996 help='Whether to run instrumentation tests',
997 default=False,
998 action='store_true')
Christoffer Quist Adamsenf86fc0b2021-12-10 12:39:36 +0100999 result.add_argument('--shrink',
1000 help='Force enable/disable shrinking' +
1001 ' (defaults to app proguard config)',
1002 choices=['default', 'force-enable', 'force-disable'],
1003 default='default')
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +02001004 result.add_argument('--sign-apks', '--sign_apks',
1005 help='Whether the APKs should be signed',
1006 default=False,
1007 action='store_true')
1008 result.add_argument('--shrinker',
1009 help='The shrinkers to use (by default, all are run)',
1010 action='append')
Ian Zernyf5a57ec2021-11-25 14:02:07 +01001011 result.add_argument('--temp',
1012 help='A directory to use for temporaries and outputs.',
1013 default=None)
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +02001014 result.add_argument('--version',
1015 default='main',
1016 help='The version of R8 to use (e.g., 1.4.51)')
Christoffer Quist Adamsen53b30422023-08-24 11:01:02 +02001017 result.add_argument('--workers',
1018 help='Number of workers to use',
1019 default=1,
1020 type=int)
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +02001021 (options, args) = result.parse_known_args(argv)
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +01001022
1023 if options.app or options.app_collection:
1024 if not options.app:
1025 options.app = []
1026 if not options.app_collection:
1027 options.app_collection = []
1028 options.apps = [
1029 app
1030 for app in APPS
1031 if app.name in options.app
1032 or any(collection in options.app_collection
1033 for collection in app.collections)]
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001034 del options.app
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +01001035 del options.app_collection
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001036 else:
Morten Krogh-Jespersen86222742021-03-02 11:13:33 +01001037 options.apps = [app for app in APPS if app.internal == options.internal]
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +01001038
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001039 if options.app_logging_filter:
1040 for app_name in options.app_logging_filter:
1041 assert any(app.name == app_name for app in options.apps)
1042 if options.shrinker:
1043 for shrinker in options.shrinker:
Christoffer Quist Adamsena9ff1cf2021-01-13 08:49:48 +01001044 assert shrinker in SHRINKERS, (
1045 'Shrinker must be one of %s' % ', '.join(SHRINKERS))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001046 else:
1047 options.shrinker = [shrinker for shrinker in SHRINKERS]
1048
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +01001049 if options.hash or version_is_built_jar(options.version):
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001050 # No need to build R8 if a specific version should be used.
1051 options.no_build = True
1052 if 'r8-nolib' in options.shrinker:
1053 warn('Skipping shrinker r8-nolib because a specific version '
1054 + 'of r8 was specified')
1055 options.shrinker.remove('r8-nolib')
1056 if 'r8-nolib-full' in options.shrinker:
1057 warn('Skipping shrinker r8-nolib-full because a specific version '
1058 + 'of r8 was specified')
1059 options.shrinker.remove('r8-nolib-full')
1060 return (options, args)
1061
1062
Rico Wind59593922021-03-03 09:12:36 +01001063def print_indented(s, indent):
1064 print(' ' * indent + s)
1065
1066
1067def get_sha256(gz_file):
1068 with open(gz_file, 'rb') as f:
1069 bytes = f.read() # read entire file as bytes
1070 return hashlib.sha256(bytes).hexdigest();
1071
1072
1073def get_sha_from_file(sha_file):
1074 with open(sha_file, 'r') as f:
1075 return f.readlines()[0]
1076
1077
1078def print_golem_config(options):
1079 print('// AUTOGENERATED FILE from tools/run_on_app_dump.py in R8 repo')
Rico Windca91a952021-03-03 09:34:54 +01001080 print('part of r8_config;')
Rico Wind71ea2862021-03-03 10:17:59 +01001081 print('')
Ian Zernyd3af0992022-10-06 20:12:04 +02001082 print('final Suite dumpsSuite = Suite("OpenSourceAppDumps");')
Rico Wind59593922021-03-03 09:12:36 +01001083 print('')
1084 print('createOpenSourceAppBenchmarks() {')
Rico Wind1abf5482021-03-03 13:55:43 +01001085 print_indented('final cpus = ["Lenovo M90"];', 2)
Christoffer Quist Adamsen8e9f7982021-12-10 13:10:05 +01001086 print_indented('final targetsCompat = ["R8"];', 2)
1087 print_indented('final targetsFull = ["R8-full-minify-optimize-shrink"];', 2)
Rico Wind61a034f2021-03-16 09:37:11 +01001088 # Avoid calculating this for every app
1089 jdk_gz = jdk.GetJdkHome() + '.tar.gz'
Ian Zerny161ff742022-01-20 12:39:40 +01001090 add_golem_resource(2, jdk_gz, 'openjdk')
Rico Wind59593922021-03-03 09:12:36 +01001091 for app in options.apps:
1092 if app.folder and not app.internal:
1093 indentation = 2;
1094 print_indented('{', indentation)
1095 indentation = 4
Rico Wind641e79a2021-03-04 09:12:07 +01001096 print_indented('final name = "%s";' % app.name, indentation)
1097 print_indented('final benchmark =', indentation)
Rico Wind59593922021-03-03 09:12:36 +01001098 print_indented(
Ian Zernyc013b702022-03-08 16:26:27 +01001099 'StandardBenchmark(name, [Metric.RunTimeRaw, Metric.CodeSize]);',
Rico Wind59593922021-03-03 09:12:36 +01001100 indentation + 4)
Morten Krogh-Jespersen9e7951b2022-08-10 15:05:26 +02001101 if app.golem_duration != None:
1102 print_indented(
1103 'final timeout = const Duration(seconds: %s);' % app.golem_duration,
1104 indentation)
1105 print_indented(
1106 'ExecutionManagement.addTimeoutConstraint'
1107 '(timeout, benchmark: benchmark);', indentation)
Rico Wind59593922021-03-03 09:12:36 +01001108 app_gz = os.path.join(utils.OPENSOURCE_DUMPS_DIR, app.folder + '.tar.gz')
Rico Wind5102b912021-06-02 07:50:49 +02001109 name = 'appResource'
1110 add_golem_resource(indentation, app_gz, name)
Christoffer Quist Adamsen8e9f7982021-12-10 13:10:05 +01001111 print_golem_config_target('Compat', 'r8', app, indentation)
1112 print_golem_config_target(
1113 'Full',
1114 'r8-full',
1115 app,
1116 indentation,
1117 minify='force-enable',
1118 optimize='force-enable',
1119 shrink='force-enable')
Rico Wind59593922021-03-03 09:12:36 +01001120 print_indented('dumpsSuite.addBenchmark(name);', indentation)
1121 indentation = 2
1122 print_indented('}', indentation)
1123 print('}')
1124
Christoffer Quist Adamsen8e9f7982021-12-10 13:10:05 +01001125def print_golem_config_target(
1126 target, shrinker, app, indentation,
1127 minify='default', optimize='default', shrink='default'):
1128 options="options" + target
1129 print_indented(
1130 'final %s = benchmark.addTargets(noImplementation, targets%s);'
1131 % (options, target),
1132 indentation)
1133 print_indented('%s.cpus = cpus;' % options, indentation)
1134 print_indented('%s.isScript = true;' % options, indentation)
1135 print_indented('%s.fromRevision = 9700;' % options, indentation);
1136 print_indented('%s.mainFile = "tools/run_on_app_dump.py "' % options,
1137 indentation)
1138 print_indented('"--golem --quiet --shrinker %s --app %s "'
1139 % (shrinker, app.name),
1140 indentation + 4)
1141 print_indented('"--minify %s --optimize %s --shrink %s";'
1142 % (minify, optimize, shrink),
1143 indentation + 4)
1144 print_indented('%s.resources.add(appResource);' % options, indentation)
1145 print_indented('%s.resources.add(openjdk);' % options, indentation)
1146
Rico Wind61a034f2021-03-16 09:37:11 +01001147def add_golem_resource(indentation, gz, name, sha256=None):
1148 sha = gz + '.sha1'
1149 if not sha256:
1150 # Golem uses a sha256 of the file in the cache, and you need to specify that.
1151 download_sha(sha, False, quiet=True)
1152 sha256 = get_sha256(gz)
1153 sha = get_sha_from_file(sha)
1154 print_indented('final %s = BenchmarkResource("",' % name, indentation)
Ian Zernyc013b702022-03-08 16:26:27 +01001155 print_indented('type: BenchmarkResourceType.storage,', indentation + 4)
Rico Wind61a034f2021-03-16 09:37:11 +01001156 print_indented('uri: "gs://r8-deps/%s",' % sha, indentation + 4)
Rico Wind5102b912021-06-02 07:50:49 +02001157 # Make dart formatter happy.
1158 if indentation > 2:
1159 print_indented('hash:', indentation + 4)
1160 print_indented('"%s",' % sha256, indentation + 8)
1161 else:
1162 print_indented('hash: "%s",' % sha256, indentation + 4)
Rico Wind61a034f2021-03-16 09:37:11 +01001163 print_indented('extract: "gz");', indentation + 4);
Rico Wind61a034f2021-03-16 09:37:11 +01001164
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001165def main(argv):
1166 (options, args) = parse_options(argv)
1167
1168 if options.bot:
1169 options.no_logging = True
1170 options.shrinker = ['r8', 'r8-full']
1171 print(options.shrinker)
1172
1173 if options.golem:
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001174 options.disable_assertions = True
1175 options.no_build = True
1176 options.r8_compilation_steps = 1
1177 options.quiet = True
1178 options.no_logging = True
1179
Rico Wind59593922021-03-03 09:12:36 +01001180 if options.generate_golem_config:
1181 print_golem_config(options)
1182 return 0
1183
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001184 with utils.TempDir() as temp_dir:
Ian Zernyf5a57ec2021-11-25 14:02:07 +01001185 if options.temp:
1186 temp_dir = options.temp
Ian Zerny7b500ba2022-02-03 16:41:17 +01001187 os.makedirs(temp_dir, exist_ok=True)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001188 if options.hash:
1189 # Download r8-<hash>.jar from
1190 # https://storage.googleapis.com/r8-releases/raw/.
1191 target = 'r8-{}.jar'.format(options.hash)
1192 update_prebuilds_in_android.download_hash(
1193 temp_dir, 'com/android/tools/r8/' + options.hash, target)
1194 as_utils.MoveFile(
1195 os.path.join(temp_dir, target), os.path.join(temp_dir, 'r8lib.jar'),
1196 quiet=options.quiet)
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +01001197 elif version_is_built_jar(options.version):
1198 # Download r8-<version>.jar from
1199 # https://storage.googleapis.com/r8-releases/raw/.
1200 target = 'r8-{}.jar'.format(options.version)
1201 update_prebuilds_in_android.download_version(
1202 temp_dir, 'com/android/tools/r8/' + options.version, target)
1203 as_utils.MoveFile(
1204 os.path.join(temp_dir, target), os.path.join(temp_dir, 'r8lib.jar'),
1205 quiet=options.quiet)
Rico Wind1b52acf2021-03-21 12:36:55 +01001206 elif options.version == 'main':
Ian Zerny161ff742022-01-20 12:39:40 +01001207 if not options.no_build:
Rico Windfc5ad672021-11-15 13:14:36 +01001208 gradle.RunGradle(['R8Retrace', 'r8', '-Pno_internal'])
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001209 build_r8lib = False
1210 for shrinker in options.shrinker:
1211 if is_minified_r8(shrinker):
1212 build_r8lib = True
1213 if build_r8lib:
1214 gradle.RunGradle(['r8lib', '-Pno_internal'])
1215 # Make a copy of r8.jar and r8lib.jar such that they stay the same for
1216 # the entire execution of this script.
1217 if 'r8-nolib' in options.shrinker or 'r8-nolib-full' in options.shrinker:
1218 assert os.path.isfile(utils.R8_JAR), 'Cannot build without r8.jar'
1219 shutil.copyfile(utils.R8_JAR, os.path.join(temp_dir, 'r8.jar'))
1220 if 'r8' in options.shrinker or 'r8-full' in options.shrinker:
1221 assert os.path.isfile(utils.R8LIB_JAR), 'Cannot build without r8lib.jar'
1222 shutil.copyfile(utils.R8LIB_JAR, os.path.join(temp_dir, 'r8lib.jar'))
1223
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +02001224 jobs = []
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001225 result_per_shrinker_per_app = []
1226 for app in options.apps:
1227 if app.skip:
1228 continue
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +02001229 result = {}
1230 result_per_shrinker_per_app.append((app, result))
1231 jobs.append(create_job(app, options, result, temp_dir))
1232 thread_utils.run_in_parallel(
1233 jobs,
1234 number_of_workers=options.workers,
1235 stop_on_first_failure=False)
Morten Krogh-Jespersenf098b422020-11-11 13:53:52 +01001236 errors = log_results_for_apps(result_per_shrinker_per_app, options)
1237 if errors > 0:
1238 dest = 'gs://r8-test-results/r8-libs/' + str(int(time.time()))
1239 utils.upload_file_to_cloud_storage(os.path.join(temp_dir, 'r8lib.jar'), dest)
1240 print('R8lib saved to %s' % dest)
1241 return errors
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001242
Christoffer Quist Adamsenbe6661d2023-08-24 11:01:12 +02001243def create_job(app, options, result, temp_dir):
1244 return lambda worker_id: run_job(
1245 app, options, result, temp_dir, worker_id)
1246
1247def run_job(app, options, result, temp_dir, worker_id):
1248 job_temp_dir = os.path.join(temp_dir, str(worker_id or 0))
1249 os.makedirs(job_temp_dir, exist_ok=True)
1250 result.update(get_results_for_app(app, options, job_temp_dir, worker_id))
1251 return 0
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001252
1253def success(message):
1254 CGREEN = '\033[32m'
1255 CEND = '\033[0m'
1256 print(CGREEN + message + CEND)
1257
1258
1259def warn(message):
1260 CRED = '\033[91m'
1261 CEND = '\033[0m'
1262 print(CRED + message + CEND)
1263
1264
1265if __name__ == '__main__':
1266 sys.exit(main(sys.argv[1:]))