blob: 30205f91ca5a9320d7428a002c6823ae04542ccb [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
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +01006import adb
7import apk_masseur
Christoffer Quist Adamsenf79f1a22021-01-12 16:24:34 +01008import as_utils
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01009import compiledump
10import gradle
Rico Wind59593922021-03-03 09:12:36 +010011import hashlib
Rico Wind61a034f2021-03-16 09:37:11 +010012import jdk
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +020013import argparse
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010014import os
15import shutil
16import sys
17import time
Morten Krogh-Jespersen47764032020-11-11 15:09:39 +010018import update_prebuilds_in_android
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010019import utils
20import zipfile
21
22from datetime import datetime
23
24SHRINKERS = ['r8', 'r8-full', 'r8-nolib', 'r8-nolib-full']
25
26class AttrDict(dict):
27 def __getattr__(self, name):
28 return self.get(name, None)
29
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010030# To generate the files for a new app, navigate to the app source folder and
31# run:
32# ./gradlew clean :app:assembleRelease -Dcom.android.tools.r8.dumpinputtodirectory=<path>
33# and store the dump and the apk.
34# If the app has instrumented tests, adding `testBuildType "release"` and
35# running:
36# ./gradlew assembleAndroidTest -Dcom.android.tools.r8.dumpinputtodirectory=<path>
37# will also generate dumps and apk for tests.
38
39class App(object):
40 def __init__(self, fields):
41 defaults = {
42 'id': None,
43 'name': None,
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +010044 'collections': [],
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010045 'dump_app': None,
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +010046 'apk_app': None,
Morten Krogh-Jespersen571cfe72020-11-09 23:44:03 +010047 'dump_test': None,
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +010048 'apk_test': None,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010049 'skip': False,
50 'url': None, # url is not used but nice to have for updating apps
51 'revision': None,
52 'folder': None,
53 'skip_recompilation': False,
Morten Krogh-Jespersen43f3cea2020-11-12 17:09:51 +010054 'compiler_properties': [],
Morten Krogh-Jespersen86222742021-03-02 11:13:33 +010055 'internal': False,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010056 }
57 # This below does not work in python3
58 defaults.update(fields.items())
59 self.__dict__ = defaults
60
61
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +010062class AppCollection(object):
63 def __init__(self, fields):
64 defaults = {
65 'name': None
66 }
67 # This below does not work in python3
68 defaults.update(fields.items())
69 self.__dict__ = defaults
70
71
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +010072APPS = [
73 App({
Morten Krogh-Jespersen0f85fa52020-11-04 13:40:43 +010074 'id': 'com.numix.calculator',
75 'name': 'Calculator',
76 'dump_app': 'dump_app.zip',
77 'apk_app': 'app-release.apk',
78 # Compiling tests fail: Library class android.content.res.XmlResourceParser
79 # implements program class org.xmlpull.v1.XmlPullParser. Nothing to really
80 # do about that.
81 'id_test': 'com.numix.calculator.test',
82 'dump_test': 'dump_test.zip',
83 'apk_test': 'app-release-androidTest.apk',
84 'url': 'https://github.com/numixproject/android-suite/tree/master/Calculator',
85 'revision': 'f58e1b53f7278c9b675d5855842c6d8a44cccb1f',
86 'folder': 'android-suite-calculator',
87 }),
88 App({
Morten Krogh-Jespersen3f0d72f2020-11-04 15:49:17 +010089 'id': 'dev.dworks.apps.anexplorer.pro',
90 'name': 'AnExplorer',
91 'dump_app': 'dump_app.zip',
92 'apk_app': 'AnExplorer-googleMobileProRelease-4.0.3.apk',
93 'url': 'https://github.com/christofferqa/AnExplorer',
94 'revision': '365927477b8eab4052a1882d5e358057ae3dee4d',
95 'folder': 'anexplorer',
96 }),
97 App({
Morten Krogh-Jespersen09e2fda2020-11-04 16:43:25 +010098 'id': 'de.danoeh.antennapod',
99 'name': 'AntennaPod',
100 'dump_app': 'dump_app.zip',
101 'apk_app': 'app-free-release.apk',
102 # TODO(b/172452102): Tests and monkey do not work
103 'id_test': 'de.danoeh.antennapod.test',
104 'dump_test': 'dump_test.zip',
105 'apk_test': 'app-free-release-androidTest.apk',
106 'url': 'https://github.com/christofferqa/AntennaPod.git',
107 'revision': '77e94f4783a16abe9cc5b78dc2d2b2b1867d8c06',
108 'folder': 'antennapod',
Morten Krogh-Jespersen09e2fda2020-11-04 16:43:25 +0100109 }),
110 App({
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100111 'id': 'com.example.applymapping',
112 'name': 'applymapping',
113 'dump_app': 'dump_app.zip',
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100114 'apk_app': 'app-release.apk',
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100115 'id_test': 'com.example.applymapping.test',
116 'dump_test': 'dump_test.zip',
117 'apk_test': 'app-release-androidTest.apk',
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100118 'url': 'https://github.com/mkj-gram/applymapping',
119 'revision': 'e3ae14b8c16fa4718e5dea8f7ad00937701b3c48',
120 'folder': 'applymapping',
Morten Krogh-Jespersen90912fd2020-11-05 09:21:16 +0100121 }),
122 App({
Morten Krogh-Jespersena98a4222020-11-05 10:50:10 +0100123 'id': 'com.chanapps.four.activity',
124 'name': 'chanu',
125 'dump_app': 'dump_app.zip',
126 'apk_app': 'app-release.apk',
127 'url': 'https://github.com/mkj-gram/chanu.git',
128 'revision': '6e53458f167b6d78398da60c20fd0da01a232617',
129 'folder': 'chanu',
Morten Krogh-Jespersen43f3cea2020-11-12 17:09:51 +0100130 # The app depends on a class file that has access flags interface but
131 # not abstract
132 'compiler_properties': ['-Dcom.android.tools.r8.allowInvalidCfAccessFlags=true']
Morten Krogh-Jespersena98a4222020-11-05 10:50:10 +0100133 }),
Morten Krogh-Jespersend06ff012020-11-05 10:50:21 +0100134 # TODO(b/172539375): Monkey runner fails on recompilation.
135 App({
136 'id': 'com.google.firebase.example.fireeats',
137 'name': 'FriendlyEats',
138 'dump_app': 'dump_app.zip',
139 'apk_app': 'app-release-unsigned.apk',
140 'url': 'https://github.com/firebase/friendlyeats-android',
141 'revision': '7c6dd016fc31ea5ecb948d5166b8479efc3775cc',
142 'folder': 'friendlyeats',
143 }),
Morten Krogh-Jespersena98a4222020-11-05 10:50:10 +0100144 App({
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100145 'id': 'com.google.samples.apps.sunflower',
146 'name': 'Sunflower',
147 'dump_app': 'dump_app.zip',
148 'apk_app': 'app-debug.apk',
149 # TODO(b/172549283): Compiling tests fails
Morten Krogh-Jespersend0389c02020-11-09 23:42:51 +0100150 'id_test': 'com.google.samples.apps.sunflower.test',
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100151 'dump_test': 'dump_test.zip',
152 'apk_test': 'app-debug-androidTest.apk',
153 'url': 'https://github.com/android/sunflower',
154 'revision': '0c4c88fdad2a74791199dffd1a6559559b1dbd4a',
155 'folder': 'sunflower',
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100156 }),
Morten Krogh-Jespersenac9de3f2020-11-05 17:07:26 +0100157 # TODO(b/172565385): Monkey runner fails on recompilation
158 App({
159 'id': 'com.google.samples.apps.iosched',
160 'name': 'iosched',
161 'dump_app': 'dump_app.zip',
162 'apk_app': 'mobile-release.apk',
163 'url': 'https://github.com/christofferqa/iosched.git',
164 'revision': '581cbbe2253711775dbccb753cdb53e7e506cb02',
165 'folder': 'iosched',
166 }),
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100167 App({
Morten Krogh-Jespersend0389c02020-11-09 23:42:51 +0100168 'id': 'fr.neamar.kiss',
169 'name': 'KISS',
170 'dump_app': 'dump_app.zip',
171 'apk_app': 'app-release.apk',
172 # TODO(b/172569220): Running tests fails due to missing keep rules
173 'id_test': 'fr.neamar.kiss.test',
174 'dump_test': 'dump_test.zip',
175 'apk_test': 'app-release-androidTest.apk',
176 'url': 'https://github.com/Neamar/KISS',
177 'revision': '8ccffaadaf0d0b8fc4418ed2b4281a0935d3d971',
178 'folder': 'kiss',
179 }),
Morten Krogh-Jespersenaaacd722020-11-09 23:43:24 +0100180 # TODO(b/172577344): Monkey runner not working.
181 App({
182 'id': 'io.github.hidroh.materialistic',
183 'name': 'materialistic',
184 'dump_app': 'dump_app.zip',
185 'apk_app': 'app-release.apk',
186 'url': 'https://github.com/christofferqa/materialistic.git',
187 'revision': '2b2b2ee25ce9e672d5aab1dc90a354af1522b1d9',
188 'folder': 'materialistic',
189 }),
Morten Krogh-Jespersend0389c02020-11-09 23:42:51 +0100190 App({
Morten Krogh-Jespersen571cfe72020-11-09 23:44:03 +0100191 'id': 'com.avjindersinghsekhon.minimaltodo',
192 'name': 'MinimalTodo',
193 'dump_app': 'dump_app.zip',
194 'apk_app': 'app-release.apk',
195 'url': 'https://github.com/christofferqa/Minimal-Todo',
196 'revision': '9d8c73746762cd376b718858ec1e8783ca07ba7c',
197 'folder': 'minimal-todo',
198 }),
199 App({
Morten Krogh-Jespersen3e3781f2020-11-09 23:44:33 +0100200 'id': 'net.nurik.roman.muzei',
201 'name': 'muzei',
202 'dump_app': 'dump_app.zip',
203 'apk_app': 'muzei-release.apk',
204 'url': 'https://github.com/romannurik/muzei',
205 'revision': '9eac6e98aebeaf0ae40bdcd85f16dd2886551138',
206 'folder': 'muzei',
207 }),
Morten Krogh-Jespersenf8e77032020-11-09 23:44:58 +0100208 # TODO(b/172806281): Monkey runner does not work.
209 App({
210 'id': 'org.schabi.newpipe',
211 'name': 'NewPipe',
212 'dump_app': 'dump_app.zip',
213 'apk_app': 'app-release-unsigned.apk',
214 'url': 'https://github.com/TeamNewPipe/NewPipe',
215 'revision': 'f4435f90313281beece70c544032f784418d85fa',
216 'folder': 'newpipe',
Morten Krogh-Jespersenf8e77032020-11-09 23:44:58 +0100217 }),
Morten Krogh-Jespersendf700642020-11-09 23:45:25 +0100218 # TODO(b/172806808): Monkey runner does not work.
219 App({
220 'id': 'io.rover.app.debug',
221 'name': 'Rover',
222 'dump_app': 'dump_app.zip',
223 'apk_app': 'example-app-release-unsigned.apk',
224 'url': 'https://github.com/RoverPlatform/rover-android',
225 'revision': '94342117097770ea3ca2c6df6ab496a1a55c3ce7',
226 'folder': 'rover-android',
227 }),
Morten Krogh-Jespersen2f1be952020-11-09 23:45:48 +0100228 # TODO(b/172808159): Monkey runner does not work
229 App({
230 'id': 'com.google.android.apps.santatracker',
231 'name': 'SantaTracker',
232 'dump_app': 'dump_app.zip',
233 'apk_app': 'santa-tracker-release.apk',
234 'url': 'https://github.com/christofferqa/santa-tracker-android',
235 'revision': '8dee74be7d9ee33c69465a07088c53087d24a6dd',
236 'folder': 'santa-tracker',
237 }),
238 App({
Morten Krogh-Jespersen88cc0772020-11-09 23:46:13 +0100239 'id': 'org.thoughtcrime.securesms',
240 'name': 'Signal',
241 'dump_app': 'dump_app.zip',
242 'apk_app': 'Signal-Android-play-prod-universal-release-4.76.2.apk',
243 # TODO(b/172812839): Instrumentation test fails.
244 'id_test': 'org.thoughtcrime.securesms.test',
245 'dump_test': 'dump_test.zip',
246 'apk_test': 'Signal-Android-play-prod-release-androidTest.apk',
247 'url': 'https://github.com/signalapp/Signal-Android',
248 'revision': '91ca19f294362ccee2c2b43c247eba228e2b30a1',
249 'folder': 'signal-android',
250 }),
Morten Krogh-Jespersen733bcff2020-11-09 23:46:43 +0100251 # TODO(b/172815827): Monkey runner does not work
252 App({
253 'id': 'com.simplemobiletools.calendar.pro',
254 'name': 'Simple-Calendar',
255 'dump_app': 'dump_app.zip',
256 'apk_app': 'calendar-release.apk',
257 'url': 'https://github.com/SimpleMobileTools/Simple-Calendar',
258 'revision': '906209874d0a091c7fce5a57972472f272d6b068',
259 'folder': 'simple-calendar',
260 }),
Morten Krogh-Jespersen8a564d32020-11-09 23:47:07 +0100261 # TODO(b/172815534): Monkey runner does not work
262 App({
263 'id': 'com.simplemobiletools.camera.pro',
264 'name': 'Simple-Camera',
265 'dump_app': 'dump_app.zip',
266 'apk_app': 'camera-release.apk',
267 'url': 'https://github.com/SimpleMobileTools/Simple-Camera',
268 'revision': 'ebf9820c51e960912b3238287e30a131244fdee6',
269 'folder': 'simple-camera',
270 }),
Morten Krogh-Jespersen88cc0772020-11-09 23:46:13 +0100271 App({
Morten Krogh-Jespersen805e31a2020-11-09 23:47:32 +0100272 'id': 'com.simplemobiletools.filemanager.pro',
273 'name': 'Simple-File-Manager',
274 'dump_app': 'dump_app.zip',
275 'apk_app': 'file-manager-release.apk',
276 'url': 'https://github.com/SimpleMobileTools/Simple-File-Manager',
277 'revision': '2b7fa68ea251222cc40cf6d62ad1de260a6f54d9',
278 'folder': 'simple-file-manager',
279 }),
280 App({
Morten Krogh-Jespersendc29e992020-11-09 23:48:01 +0100281 'id': 'com.simplemobiletools.gallery.pro',
282 'name': 'Simple-Gallery',
283 'dump_app': 'dump_app.zip',
284 'apk_app': 'gallery-326-foss-release.apk',
285 'url': 'https://github.com/SimpleMobileTools/Simple-Gallery',
286 'revision': '564e56b20d33b28d0018c8087ec705beeb60785e',
287 'folder': 'simple-gallery',
Morten Krogh-Jespersendc29e992020-11-09 23:48:01 +0100288 }),
289 App({
Morten Krogh-Jespersen4a9657a2020-11-09 23:48:21 +0100290 'id': 'com.example.sqldelight.hockey',
291 'name': 'SQLDelight',
292 'dump_app': 'dump_app.zip',
293 'apk_app': 'android-release.apk',
294 'url': 'https://github.com/christofferqa/sqldelight',
295 'revision': '2e67a1126b6df05e4119d1e3a432fde51d76cdc8',
296 'folder': 'sqldelight',
297 }),
Morten Krogh-Jespersenf12a57e2020-11-09 23:48:53 +0100298 # TODO(b/172824096): Monkey runner does not work.
299 App({
300 'id': 'eu.kanade.tachiyomi',
301 'name': 'Tachiyomi',
302 'dump_app': 'dump_app.zip',
303 'apk_app': 'app-dev-release.apk',
304 'url': 'https://github.com/inorichi/tachiyomi',
305 'revision': '8aa6486bf76ab9a61a5494bee284b1a5e9180bf3',
306 'folder': 'tachiyomi',
307 }),
Morten Krogh-Jespersen58974522020-11-10 00:20:46 +0100308 # TODO(b/172862042): Monkey runner does not work.
309 App({
310 'id': 'app.tivi',
311 'name': 'Tivi',
312 'dump_app': 'dump_app.zip',
313 'apk_app': 'app-release.apk',
314 'url': 'https://github.com/chrisbanes/tivi',
Morten Krogh-Jespersen44e2f892020-12-17 09:18:35 +0100315 'revision': '5c6d9ed338885c59b1fc64050d92d056417bb4de',
Morten Krogh-Jespersen58974522020-11-10 00:20:46 +0100316 'folder': 'tivi',
Morten Krogh-Jespersen58974522020-11-10 00:20:46 +0100317 }),
Morten Krogh-Jespersen4a9657a2020-11-09 23:48:21 +0100318 App({
Morten Krogh-Jespersen9033d1a2020-11-09 23:49:23 +0100319 'id': 'com.keylesspalace.tusky',
320 'name': 'Tusky',
321 'dump_app': 'dump_app.zip',
322 'apk_app': 'app-blue-release.apk',
323 'url': 'https://github.com/tuskyapp/Tusky',
324 'revision': '814a9b8f9bacf8d26f712b06a0313a3534a2be95',
325 'folder': 'tusky',
Morten Krogh-Jespersen9033d1a2020-11-09 23:49:23 +0100326 }),
327 App({
Morten Krogh-Jespersen90912fd2020-11-05 09:21:16 +0100328 'id': 'org.wikipedia',
329 'name': 'Wikipedia',
330 'dump_app': 'dump_app.zip',
331 'apk_app': 'app-prod-release.apk',
332 'url': 'https://github.com/wikimedia/apps-android-wikipedia',
333 'revision': '0fa7cad843c66313be8e25790ef084cf1a1fa67e',
334 'folder': 'wikipedia',
335 }),
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100336 # TODO(b/173167253): Check if monkey testing works.
337 App({
338 'id': 'androidx.compose.samples.crane',
339 'name': 'compose-crane',
340 'collections': ['compose-samples'],
341 'dump_app': 'dump_app.zip',
342 'apk_app': 'app-release-unsigned.apk',
343 'url': 'https://github.com/android/compose-samples',
344 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
345 'folder': 'android/compose-samples/crane',
346 }),
347 # TODO(b/173167253): Check if monkey testing works.
348 App({
349 'id': 'com.example.jetcaster',
350 'name': 'compose-jetcaster',
351 'collections': ['compose-samples'],
352 'dump_app': 'dump_app.zip',
353 'apk_app': 'app-release-unsigned.apk',
354 'url': 'https://github.com/android/compose-samples',
355 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
356 'folder': 'android/compose-samples/jetcaster',
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100357 }),
358 # TODO(b/173167253): Check if monkey testing works.
359 App({
360 'id': 'com.example.compose.jetchat',
361 'name': 'compose-jetchat',
362 'collections': ['compose-samples'],
363 'dump_app': 'dump_app.zip',
364 'apk_app': 'app-release-unsigned.apk',
365 'url': 'https://github.com/android/compose-samples',
366 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
367 'folder': 'android/compose-samples/jetchat',
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100368 }),
369 # TODO(b/173167253): Check if monkey testing works.
370 App({
371 'id': 'com.example.jetnews',
372 'name': 'compose-jetnews',
373 'collections': ['compose-samples'],
374 'dump_app': 'dump_app.zip',
375 'apk_app': 'app-release-unsigned.apk',
376 'url': 'https://github.com/android/compose-samples',
377 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
378 'folder': 'android/compose-samples/jetnews',
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100379 }),
380 # TODO(b/173167253): Check if monkey testing works.
381 App({
382 'id': 'com.example.jetsnack',
383 'name': 'compose-jetsnack',
384 'collections': ['compose-samples'],
385 'dump_app': 'dump_app.zip',
386 'apk_app': 'app-release-unsigned.apk',
387 'url': 'https://github.com/android/compose-samples',
388 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
389 'folder': 'android/compose-samples/jetsnack',
390 }),
391 # TODO(b/173167253): Check if monkey testing works.
392 App({
393 'id': 'com.example.compose.jetsurvey',
394 'name': 'compose-jetsurvey',
395 'collections': ['compose-samples'],
396 'dump_app': 'dump_app.zip',
397 'apk_app': 'app-release-unsigned.apk',
398 'url': 'https://github.com/android/compose-samples',
399 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
400 'folder': 'android/compose-samples/jetsurvey',
401 }),
402 # TODO(b/173167253): Check if monkey testing works.
403 App({
404 'id': 'com.example.owl',
405 'name': 'compose-owl',
406 'collections': ['compose-samples'],
407 'dump_app': 'dump_app.zip',
408 'apk_app': 'app-release-unsigned.apk',
409 'url': 'https://github.com/android/compose-samples',
410 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
411 'folder': 'android/compose-samples/owl',
412 }),
413 # TODO(b/173167253): Check if monkey testing works.
414 App({
415 'id': 'com.example.compose.rally',
416 'name': 'compose-rally',
417 'collections': ['compose-samples'],
418 'dump_app': 'dump_app.zip',
419 'apk_app': 'app-release-unsigned.apk',
420 'url': 'https://github.com/android/compose-samples',
421 'revision': '779cf9e187b8ee2c6b620b2abb4524719b3f10f8',
422 'folder': 'android/compose-samples/rally',
423 }),
Morten Krogh-Jespersen86222742021-03-02 11:13:33 +0100424 App({
425 'id': 'youtube_15_33',
426 'name': 'youtube_15_33',
427 'dump_app': 'dump.zip',
428 'apk_app': 'YouTubeRelease_unsigned.apk',
429 'folder': 'youtube_15_33',
430 'internal': True,
431 # TODO(b/181629268): Fix recompilation
432 'skip_recompilation': True,
433 })
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100434]
435
436
437APP_COLLECTIONS = [
438 AppCollection({
439 'name': 'compose-samples',
440 })
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100441]
442
Morten Krogh-Jespersenf8e77032020-11-09 23:44:58 +0100443
Morten Krogh-Jespersendfeb0e32020-11-04 14:55:55 +0100444def remove_print_lines(file):
445 with open(file) as f:
446 lines = f.readlines()
447 with open(file, 'w') as f:
448 for line in lines:
449 if '-printconfiguration' not in line:
450 f.write(line)
451
452
Rico Wind61a034f2021-03-16 09:37:11 +0100453def download_sha(app_sha, internal, quiet=False):
Morten Krogh-Jespersen86222742021-03-02 11:13:33 +0100454 if internal:
455 utils.DownloadFromX20(app_sha)
456 else:
Rico Wind59593922021-03-03 09:12:36 +0100457 utils.DownloadFromGoogleCloudStorage(app_sha, quiet=quiet)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100458
459
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100460def is_logging_enabled_for(app, options):
461 if options.no_logging:
462 return False
463 if options.app_logging_filter and app.name not in options.app_logging_filter:
464 return False
465 return True
466
467
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100468def is_minified_r8(shrinker):
469 return '-nolib' not in shrinker
470
471
472def is_full_r8(shrinker):
Morten Krogh-Jespersen270d0932020-11-11 11:05:57 +0100473 return '-full' in shrinker
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100474
475
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100476def version_is_built_jar(version):
Rico Wind1b52acf2021-03-21 12:36:55 +0100477 return version != 'main' and version != 'source'
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100478
479
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100480def compute_size_of_dex_files_in_package(path):
481 dex_size = 0
482 z = zipfile.ZipFile(path, 'r')
483 for filename in z.namelist():
484 if filename.endswith('.dex'):
485 dex_size += z.getinfo(filename).file_size
486 return dex_size
487
488
489def dump_for_app(app_dir, app):
490 return os.path.join(app_dir, app.dump_app)
491
492
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100493def dump_test_for_app(app_dir, app):
494 return os.path.join(app_dir, app.dump_test)
495
496
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100497def get_r8_jar(options, temp_dir, shrinker):
498 if (options.version == 'source'):
499 return None
500 return os.path.join(
501 temp_dir, 'r8lib.jar' if is_minified_r8(shrinker) else 'r8.jar')
502
503
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100504def get_results_for_app(app, options, temp_dir):
505 app_folder = app.folder if app.folder else app.name + "_" + app.revision
Rico Windb2ae4c62021-06-01 15:09:56 +0200506 # Golem extraction will extract to the basename under the benchmarks dir.
507 app_location = os.path.basename(app_folder) if options.golem else app_folder
Rico Winde32a9c72021-03-16 09:00:06 +0100508 opensource_basedir = (os.path.join('benchmarks', app.name) if options.golem
509 else utils.OPENSOURCE_DUMPS_DIR)
Rico Windb2ae4c62021-06-01 15:09:56 +0200510 app_dir = (os.path.join(utils.INTERNAL_DUMPS_DIR, app_location) if app.internal
511 else os.path.join(opensource_basedir, app_location))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100512 if not os.path.exists(app_dir) and not options.golem:
513 # Download the app from google storage.
Rico Wind61a034f2021-03-16 09:37:11 +0100514 download_sha(app_dir + ".tar.gz.sha1", app.internal)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100515
516 # Ensure that the dumps are in place
517 assert os.path.isfile(dump_for_app(app_dir, app)), "Could not find dump " \
518 "for app " + app.name
519
520 result = {}
521 result['status'] = 'success'
522 result_per_shrinker = build_app_with_shrinkers(
523 app, options, temp_dir, app_dir)
Christoffer Quist Adamsena9ff1cf2021-01-13 08:49:48 +0100524 for shrinker, shrinker_result in result_per_shrinker.items():
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100525 result[shrinker] = shrinker_result
526 return result
527
528
529def build_app_with_shrinkers(app, options, temp_dir, app_dir):
530 result_per_shrinker = {}
531 for shrinker in options.shrinker:
532 results = []
533 build_app_and_run_with_shrinker(
534 app, options, temp_dir, app_dir, shrinker, results)
535 result_per_shrinker[shrinker] = results
536 if len(options.apps) > 1:
537 print('')
538 log_results_for_app(app, result_per_shrinker, options)
539 print('')
540
541 return result_per_shrinker
542
543
544def is_last_build(index, compilation_steps):
545 return index == compilation_steps - 1
546
547
548def build_app_and_run_with_shrinker(app, options, temp_dir, app_dir, shrinker,
549 results):
550 print('[{}] Building {} with {}'.format(
551 datetime.now().strftime("%H:%M:%S"),
552 app.name,
553 shrinker))
554 print('To compile locally: '
Morten Krogh-Jespersenf098b422020-11-11 13:53:52 +0100555 'tools/run_on_app_dump.py --shrinker {} --r8-compilation-steps {} '
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100556 '--app {}'.format(
557 shrinker,
558 options.r8_compilation_steps,
559 app.name))
560 print('HINT: use --shrinker r8-nolib --no-build if you have a local R8.jar')
561 recomp_jar = None
562 status = 'success'
Morten Krogh-Jespersenee89b3a2020-11-13 11:59:43 +0100563 if options.r8_compilation_steps < 1:
564 return
565 compilation_steps = 1 if app.skip_recompilation else options.r8_compilation_steps
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100566 for compilation_step in range(0, compilation_steps):
567 if status != 'success':
568 break
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100569 print('Compiling {} of {}'.format(compilation_step + 1, compilation_steps))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100570 result = {}
571 try:
572 start = time.time()
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100573 (app_jar, mapping, new_recomp_jar) = \
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100574 build_app_with_shrinker(
575 app, options, temp_dir, app_dir, shrinker, compilation_step,
576 compilation_steps, recomp_jar)
577 end = time.time()
578 dex_size = compute_size_of_dex_files_in_package(app_jar)
579 result['build_status'] = 'success'
580 result['recompilation_status'] = 'success'
581 result['output_jar'] = app_jar
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100582 result['output_mapping'] = mapping
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100583 result['dex_size'] = dex_size
584 result['duration'] = int((end - start) * 1000) # Wall time
585 if (new_recomp_jar is None
586 and not is_last_build(compilation_step, compilation_steps)):
587 result['recompilation_status'] = 'failed'
588 warn('Failed to build {} with {}'.format(app.name, shrinker))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100589 recomp_jar = new_recomp_jar
590 except Exception as e:
591 warn('Failed to build {} with {}'.format(app.name, shrinker))
592 if e:
593 print('Error: ' + str(e))
594 result['build_status'] = 'failed'
595 status = 'failed'
596
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100597 original_app_apk = os.path.join(app_dir, app.apk_app)
598 app_apk_destination = os.path.join(
599 temp_dir,"{}_{}.apk".format(app.id, compilation_step))
600
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100601 if result.get('build_status') == 'success' and options.monkey:
602 # Make a copy of the given APK, move the newly generated dex files into the
603 # copied APK, and then sign the APK.
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100604 apk_masseur.masseur(
605 original_app_apk, dex=app_jar, resources='META-INF/services/*',
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100606 out=app_apk_destination,
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100607 quiet=options.quiet, logging=is_logging_enabled_for(app, options),
608 keystore=options.keystore)
609
610 result['monkey_status'] = 'success' if adb.run_monkey(
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100611 app.id, options.emulator_id, app_apk_destination, options.monkey_events,
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100612 options.quiet, is_logging_enabled_for(app, options)) else 'failed'
613
Morten Krogh-Jespersen571cfe72020-11-09 23:44:03 +0100614 if (result.get('build_status') == 'success'
615 and options.run_tests and app.dump_test):
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100616 if not os.path.isfile(app_apk_destination):
617 apk_masseur.masseur(
618 original_app_apk, dex=app_jar, resources='META-INF/services/*',
619 out=app_apk_destination,
620 quiet=options.quiet, logging=is_logging_enabled_for(app, options),
621 keystore=options.keystore)
622
623 # Compile the tests with the mapping file.
624 test_jar = build_test_with_shrinker(
625 app, options, temp_dir, app_dir,shrinker, compilation_step,
626 result['output_mapping'])
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100627 if not test_jar:
628 result['instrumentation_test_status'] = 'compilation_failed'
629 else:
630 original_test_apk = os.path.join(app_dir, app.apk_test)
631 test_apk_destination = os.path.join(
632 temp_dir,"{}_{}.test.apk".format(app.id_test, compilation_step))
633 apk_masseur.masseur(
634 original_test_apk, dex=test_jar, resources='META-INF/services/*',
635 out=test_apk_destination,
636 quiet=options.quiet, logging=is_logging_enabled_for(app, options),
637 keystore=options.keystore)
638 result['instrumentation_test_status'] = 'success' if adb.run_instrumented(
639 app.id, app.id_test, options.emulator_id, app_apk_destination,
640 test_apk_destination, options.quiet,
641 is_logging_enabled_for(app, options)) else 'failed'
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100642
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100643 results.append(result)
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100644 if result.get('recompilation_status') != 'success':
645 break
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100646
Rico Wind33936d12021-04-07 08:04:14 +0200647def get_jdk_home(options, app):
Rico Winda74174d2021-04-07 09:10:35 +0200648 if options.golem:
Rico Wind33936d12021-04-07 08:04:14 +0200649 return os.path.join('benchmarks', app.name, 'linux')
650 return None
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100651
652def build_app_with_shrinker(app, options, temp_dir, app_dir, shrinker,
653 compilation_step_index, compilation_steps,
654 prev_recomp_jar):
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100655 args = AttrDict({
656 'dump': dump_for_app(app_dir, app),
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100657 'r8_jar': get_r8_jar(options, temp_dir, shrinker),
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100658 'ea': False if options.disable_assertions else True,
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100659 'version': options.version,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100660 'compiler': 'r8full' if is_full_r8(shrinker) else 'r8',
661 'debug_agent': options.debug_agent,
662 'program_jar': prev_recomp_jar,
Morten Krogh-Jespersendfeb0e32020-11-04 14:55:55 +0100663 'nolib': not is_minified_r8(shrinker),
664 'config_file_consumer': remove_print_lines,
Morten Krogh-Jespersen43f3cea2020-11-12 17:09:51 +0100665 'properties': app.compiler_properties,
Morten Krogh-Jespersend86a81b2020-11-13 12:33:26 +0100666 'disable_desugared_lib': False,
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200667 'print_times': options.print_times,
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100668 })
669
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100670 app_jar = os.path.join(
671 temp_dir, '{}_{}_{}_dex_out.jar'.format(
672 app.name, shrinker, compilation_step_index))
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100673 app_mapping = os.path.join(
674 temp_dir, '{}_{}_{}_dex_out.jar.map'.format(
675 app.name, shrinker, compilation_step_index))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100676 recomp_jar = None
Rico Wind33936d12021-04-07 08:04:14 +0200677 jdkhome = get_jdk_home(options, app)
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100678 with utils.TempDir() as compile_temp_dir:
Rico Wind33936d12021-04-07 08:04:14 +0200679 compile_result = compiledump.run1(compile_temp_dir, args, [], jdkhome)
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100680 out_jar = os.path.join(compile_temp_dir, "out.jar")
681 out_mapping = os.path.join(compile_temp_dir, "out.jar.map")
682
683 if compile_result != 0 or not os.path.isfile(out_jar):
684 assert False, 'Compilation of {} failed'.format(dump_for_app(app_dir, app))
685 shutil.move(out_jar, app_jar)
686 shutil.move(out_mapping, app_mapping)
687
688 if compilation_step_index < compilation_steps - 1:
689 args['classfile'] = True
690 args['min_api'] = "10000"
Morten Krogh-Jespersend86a81b2020-11-13 12:33:26 +0100691 args['disable_desugared_lib'] = True
Rico Wind33936d12021-04-07 08:04:14 +0200692 compile_result = compiledump.run1(compile_temp_dir, args, [], jdkhome)
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100693 if compile_result == 0:
694 recomp_jar = os.path.join(
695 temp_dir, '{}_{}_{}_cf_out.jar'.format(
696 app.name, shrinker, compilation_step_index))
697 shutil.move(out_jar, recomp_jar)
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100698
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100699 return (app_jar, app_mapping, recomp_jar)
700
Morten Krogh-Jespersen162b3452020-11-05 13:07:10 +0100701
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100702def build_test_with_shrinker(app, options, temp_dir, app_dir, shrinker,
703 compilation_step_index, mapping):
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100704
705 def rewrite_file(file):
Morten Krogh-Jespersendfeb0e32020-11-04 14:55:55 +0100706 remove_print_lines(file)
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100707 with open(file) as f:
708 lines = f.readlines()
709 with open(file, 'w') as f:
710 for line in lines:
711 if '-applymapping' not in line:
712 f.write(line + '\n')
713 f.write("-applymapping " + mapping + '\n')
714
715 args = AttrDict({
716 'dump': dump_test_for_app(app_dir, app),
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100717 'r8_jar': get_r8_jar(options, temp_dir, shrinker),
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100718 'ea': False if options.disable_assertions else True,
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100719 'version': options.version,
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100720 'compiler': 'r8full' if is_full_r8(shrinker) else 'r8',
721 'debug_agent': options.debug_agent,
722 'nolib': not is_minified_r8(shrinker),
723 # The config file will have an -applymapping reference to an old map.
724 # Update it to point to mapping file build in the compilation of the app.
725 'config_file_consumer': rewrite_file
726 })
727
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100728 test_jar = os.path.join(
729 temp_dir, '{}_{}_{}_test_out.jar'.format(
730 app.name, shrinker, compilation_step_index))
731
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100732 with utils.TempDir() as compile_temp_dir:
Rico Wind33936d12021-04-07 08:04:14 +0200733 jdkhome = get_jdk_home(options, app)
734 compile_result = compiledump.run1(compile_temp_dir, args, [], jdkhome)
Morten Krogh-Jespersenc9d23462020-11-12 15:36:57 +0100735 out_jar = os.path.join(compile_temp_dir, "out.jar")
736 if compile_result != 0 or not os.path.isfile(out_jar):
737 return None
738 shutil.move(out_jar, test_jar)
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100739
740 return test_jar
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100741
742
743def log_results_for_apps(result_per_shrinker_per_app, options):
744 print('')
745 app_errors = 0
746 for (app, result_per_shrinker) in result_per_shrinker_per_app:
747 app_errors += (1 if log_results_for_app(app, result_per_shrinker, options)
748 else 0)
749 return app_errors
750
751
752def log_results_for_app(app, result_per_shrinker, options):
753 if options.print_dexsegments:
754 log_segments_for_app(app, result_per_shrinker, options)
755 return False
756 else:
757 return log_comparison_results_for_app(app, result_per_shrinker, options)
758
759
760def log_segments_for_app(app, result_per_shrinker, options):
761 for shrinker in SHRINKERS:
762 if shrinker not in result_per_shrinker:
763 continue
764 for result in result_per_shrinker.get(shrinker):
765 benchmark_name = '{}-{}'.format(options.print_dexsegments, app.name)
766 utils.print_dexsegments(benchmark_name, [result.get('output_jar')])
767 duration = result.get('duration')
768 print('%s-Total(RunTimeRaw): %s ms' % (benchmark_name, duration))
769 print('%s-Total(CodeSize): %s' % (benchmark_name, result.get('dex_size')))
770
771
772def percentage_diff_as_string(before, after):
773 if after < before:
774 return '-' + str(round((1.0 - after / before) * 100)) + '%'
775 else:
776 return '+' + str(round((after - before) / before * 100)) + '%'
777
778
779def log_comparison_results_for_app(app, result_per_shrinker, options):
780 print(app.name + ':')
781 app_error = False
782 if result_per_shrinker.get('status', 'success') != 'success':
783 error_message = result_per_shrinker.get('error_message')
784 print(' skipped ({})'.format(error_message))
785 return
786
787 proguard_result = result_per_shrinker.get('pg', {})
788 proguard_dex_size = float(proguard_result.get('dex_size', -1))
789
790 for shrinker in SHRINKERS:
791 if shrinker not in result_per_shrinker:
792 continue
793 compilation_index = 1
794 for result in result_per_shrinker.get(shrinker):
795 build_status = result.get('build_status')
796 if build_status != 'success' and build_status is not None:
797 app_error = True
798 warn(' {}-#{}: {}'.format(shrinker, compilation_index, build_status))
799 continue
800
Rico Wind59593922021-03-03 09:12:36 +0100801 if options.golem:
802 print('%s(RunTimeRaw): %s ms' % (app.name, result.get('duration')))
803 print('%s(CodeSize): %s' % (app.name, result.get('dex_size')))
804 continue
805
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100806 print(' {}-#{}:'.format(shrinker, compilation_index))
807 dex_size = result.get('dex_size')
808 msg = ' dex size: {}'.format(dex_size)
Rudi Horn82e7d222020-11-17 11:22:39 +0000809 if options.print_runtimeraw:
810 print(' run time raw: {} ms'.format(result.get('duration')))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100811 if dex_size != proguard_dex_size and proguard_dex_size >= 0:
812 msg = '{} ({}, {})'.format(
813 msg, dex_size - proguard_dex_size,
814 percentage_diff_as_string(proguard_dex_size, dex_size))
815 success(msg) if dex_size < proguard_dex_size else warn(msg)
816 else:
817 print(msg)
818
Morten Krogh-Jespersencd55f812020-11-04 09:13:31 +0100819 if options.monkey:
820 monkey_status = result.get('monkey_status')
821 if monkey_status != 'success':
822 app_error = True
823 warn(' monkey: {}'.format(monkey_status))
824 else:
825 success(' monkey: {}'.format(monkey_status))
826
Morten Krogh-Jespersen51a16352020-11-04 09:31:15 +0100827 if options.run_tests and 'instrumentation_test_status' in result:
828 test_status = result.get('instrumentation_test_status')
829 if test_status != 'success':
830 warn(' instrumentation_tests: {}'.format(test_status))
831 else:
832 success(' instrumentation_tests: {}'.format(test_status))
833
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100834 recompilation_status = result.get('recompilation_status', '')
835 if recompilation_status == 'failed':
836 app_error = True
837 warn(' recompilation {}-#{}: failed'.format(shrinker,
838 compilation_index))
839 continue
840
841 compilation_index += 1
842
843 return app_error
844
845
846def parse_options(argv):
Morten Krogh-Jespersen6c702402021-06-21 12:29:48 +0200847 result = argparse.ArgumentParser(description = 'Run/compile dump artifacts.')
848 result.add_argument('--app',
849 help='What app to run on',
850 choices=[app.name for app in APPS],
851 action='append')
852 result.add_argument('--app-collection', '--app_collection',
853 help='What app collection to run',
854 choices=[collection.name for collection in
855 APP_COLLECTIONS],
856 action='append')
857 result.add_argument('--app-logging-filter', '--app_logging_filter',
858 help='The apps for which to turn on logging',
859 action='append')
860 result.add_argument('--bot',
861 help='Running on bot, use third_party dependency.',
862 default=False,
863 action='store_true')
864 result.add_argument('--generate-golem-config', '--generate_golem_config',
865 help='Generate a new config for golem.',
866 default=False,
867 action='store_true')
868 result.add_argument('--debug-agent',
869 help='Enable Java debug agent and suspend compilation '
870 '(default disabled)',
871 default=False,
872 action='store_true')
873 result.add_argument('--disable-assertions', '--disable_assertions',
874 help='Disable assertions when compiling',
875 default=False,
876 action='store_true')
877 result.add_argument('--emulator-id', '--emulator_id',
878 help='Id of the emulator to use',
879 default='emulator-5554')
880 result.add_argument('--golem',
881 help='Running on golem, do not download',
882 default=False,
883 action='store_true')
884 result.add_argument('--hash',
885 help='The commit of R8 to use')
886 result.add_argument('--internal',
887 help='Run internal apps if set, otherwise run opensource',
888 default=False,
889 action='store_true')
890 result.add_argument('--keystore',
891 help='Path to app.keystore',
892 default=os.path.join(utils.TOOLS_DIR, 'debug.keystore'))
893 result.add_argument('--keystore-password', '--keystore_password',
894 help='Password for app.keystore',
895 default='android')
896 result.add_argument('--monkey',
897 help='Whether to install and run app(s) with monkey',
898 default=False,
899 action='store_true')
900 result.add_argument('--monkey-events', '--monkey_events',
901 help='Number of events that the monkey should trigger',
902 default=250,
903 type=int)
904 result.add_argument('--no-build', '--no_build',
905 help='Run without building first (only when using ToT)',
906 default=False,
907 action='store_true')
908 result.add_argument('--no-logging', '--no_logging',
909 help='Disable logging except for errors',
910 default=False,
911 action='store_true')
912 result.add_argument('--print-times',
913 help='Print timing information from r8',
914 default=False,
915 action='store_true')
916 result.add_argument('--print-dexsegments',
917 metavar='BENCHMARKNAME',
918 help='Print the sizes of individual dex segments as ' +
919 '\'<BENCHMARKNAME>-<APP>-<segment>(CodeSize): '
920 '<bytes>\'')
921 result.add_argument('--print-runtimeraw',
922 metavar='BENCHMARKNAME',
923 help='Print the line \'<BENCHMARKNAME>(RunTimeRaw):' +
924 ' <elapsed> ms\' at the end where <elapsed> is' +
925 ' the elapsed time in milliseconds.')
926 result.add_argument('--quiet',
927 help='Disable verbose logging',
928 default=False,
929 action='store_true')
930 result.add_argument('--r8-compilation-steps', '--r8_compilation_steps',
931 help='Number of times R8 should be run on each app',
932 default=2,
933 type=int)
934 result.add_argument('--run-tests', '--run_tests',
935 help='Whether to run instrumentation tests',
936 default=False,
937 action='store_true')
938 result.add_argument('--sign-apks', '--sign_apks',
939 help='Whether the APKs should be signed',
940 default=False,
941 action='store_true')
942 result.add_argument('--shrinker',
943 help='The shrinkers to use (by default, all are run)',
944 action='append')
945 result.add_argument('--version',
946 default='main',
947 help='The version of R8 to use (e.g., 1.4.51)')
948 (options, args) = result.parse_known_args(argv)
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100949
950 if options.app or options.app_collection:
951 if not options.app:
952 options.app = []
953 if not options.app_collection:
954 options.app_collection = []
955 options.apps = [
956 app
957 for app in APPS
958 if app.name in options.app
959 or any(collection in options.app_collection
960 for collection in app.collections)]
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100961 del options.app
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100962 del options.app_collection
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100963 else:
Morten Krogh-Jespersen86222742021-03-02 11:13:33 +0100964 options.apps = [app for app in APPS if app.internal == options.internal]
Christoffer Quist Adamsen53e29472020-11-13 10:53:06 +0100965
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100966 if options.app_logging_filter:
967 for app_name in options.app_logging_filter:
968 assert any(app.name == app_name for app in options.apps)
969 if options.shrinker:
970 for shrinker in options.shrinker:
Christoffer Quist Adamsena9ff1cf2021-01-13 08:49:48 +0100971 assert shrinker in SHRINKERS, (
972 'Shrinker must be one of %s' % ', '.join(SHRINKERS))
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100973 else:
974 options.shrinker = [shrinker for shrinker in SHRINKERS]
975
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +0100976 if options.hash or version_is_built_jar(options.version):
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +0100977 # No need to build R8 if a specific version should be used.
978 options.no_build = True
979 if 'r8-nolib' in options.shrinker:
980 warn('Skipping shrinker r8-nolib because a specific version '
981 + 'of r8 was specified')
982 options.shrinker.remove('r8-nolib')
983 if 'r8-nolib-full' in options.shrinker:
984 warn('Skipping shrinker r8-nolib-full because a specific version '
985 + 'of r8 was specified')
986 options.shrinker.remove('r8-nolib-full')
987 return (options, args)
988
989
Rico Wind59593922021-03-03 09:12:36 +0100990def print_indented(s, indent):
991 print(' ' * indent + s)
992
993
994def get_sha256(gz_file):
995 with open(gz_file, 'rb') as f:
996 bytes = f.read() # read entire file as bytes
997 return hashlib.sha256(bytes).hexdigest();
998
999
1000def get_sha_from_file(sha_file):
1001 with open(sha_file, 'r') as f:
1002 return f.readlines()[0]
1003
1004
1005def print_golem_config(options):
1006 print('// AUTOGENERATED FILE from tools/run_on_app_dump.py in R8 repo')
Rico Windca91a952021-03-03 09:34:54 +01001007 print('part of r8_config;')
Rico Wind71ea2862021-03-03 10:17:59 +01001008 print('')
Rico Wind59593922021-03-03 09:12:36 +01001009 print('final Suite dumpsSuite = new Suite("OpenSourceAppDumps");')
1010 print('')
1011 print('createOpenSourceAppBenchmarks() {')
Rico Wind1abf5482021-03-03 13:55:43 +01001012 print_indented('final cpus = ["Lenovo M90"];', 2)
Rico Wind61a034f2021-03-16 09:37:11 +01001013 # Avoid calculating this for every app
1014 jdk_gz = jdk.GetJdkHome() + '.tar.gz'
1015 download_sha(jdk_gz + '.sha1', False, quiet=True)
1016 jdk_sha256 = get_sha256(jdk_gz)
Rico Wind5102b912021-06-02 07:50:49 +02001017 add_golem_resource(2, jdk_gz, 'openjdk', sha256=jdk_sha256)
Rico Wind59593922021-03-03 09:12:36 +01001018 for app in options.apps:
1019 if app.folder and not app.internal:
1020 indentation = 2;
1021 print_indented('{', indentation)
1022 indentation = 4
Rico Wind641e79a2021-03-04 09:12:07 +01001023 print_indented('final name = "%s";' % app.name, indentation)
1024 print_indented('final benchmark =', indentation)
Rico Wind59593922021-03-03 09:12:36 +01001025 print_indented(
1026 'new StandardBenchmark(name, [Metric.RunTimeRaw, Metric.CodeSize]);',
1027 indentation + 4)
1028 print_indented(
Rico Wind641e79a2021-03-04 09:12:07 +01001029 'final options = benchmark.addTargets(noImplementation, ["R8"]);',
Rico Wind59593922021-03-03 09:12:36 +01001030 indentation)
1031 print_indented('options.cpus = cpus;', indentation)
1032 print_indented('options.isScript = true;', indentation)
Rico Windca91a952021-03-03 09:34:54 +01001033 print_indented('options.fromRevision = 9700;', indentation);
Rico Wind5102b912021-06-02 07:50:49 +02001034 print_indented('options.mainFile = "tools/run_on_app_dump.py "',
1035 indentation)
1036 print_indented('"--golem --quiet --shrinker r8 --app %s";' % app.name,
1037 indentation + 4)
Rico Wind61a034f2021-03-16 09:37:11 +01001038
Rico Wind59593922021-03-03 09:12:36 +01001039 app_gz = os.path.join(utils.OPENSOURCE_DUMPS_DIR, app.folder + '.tar.gz')
Rico Wind5102b912021-06-02 07:50:49 +02001040 name = 'appResource'
1041 add_golem_resource(indentation, app_gz, name)
1042 print_indented('options.resources.add(appResource);', indentation)
1043 print_indented('options.resources.add(openjdk);', indentation)
Rico Wind59593922021-03-03 09:12:36 +01001044 print_indented('dumpsSuite.addBenchmark(name);', indentation)
1045 indentation = 2
1046 print_indented('}', indentation)
1047 print('}')
1048
Rico Wind61a034f2021-03-16 09:37:11 +01001049def add_golem_resource(indentation, gz, name, sha256=None):
1050 sha = gz + '.sha1'
1051 if not sha256:
1052 # Golem uses a sha256 of the file in the cache, and you need to specify that.
1053 download_sha(sha, False, quiet=True)
1054 sha256 = get_sha256(gz)
1055 sha = get_sha_from_file(sha)
1056 print_indented('final %s = BenchmarkResource("",' % name, indentation)
1057 print_indented('type: BenchmarkResourceType.Storage,', indentation + 4)
1058 print_indented('uri: "gs://r8-deps/%s",' % sha, indentation + 4)
Rico Wind5102b912021-06-02 07:50:49 +02001059 # Make dart formatter happy.
1060 if indentation > 2:
1061 print_indented('hash:', indentation + 4)
1062 print_indented('"%s",' % sha256, indentation + 8)
1063 else:
1064 print_indented('hash: "%s",' % sha256, indentation + 4)
Rico Wind61a034f2021-03-16 09:37:11 +01001065 print_indented('extract: "gz");', indentation + 4);
Rico Wind61a034f2021-03-16 09:37:11 +01001066
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001067def main(argv):
1068 (options, args) = parse_options(argv)
1069
1070 if options.bot:
1071 options.no_logging = True
1072 options.shrinker = ['r8', 'r8-full']
1073 print(options.shrinker)
1074
1075 if options.golem:
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001076 options.disable_assertions = True
1077 options.no_build = True
1078 options.r8_compilation_steps = 1
1079 options.quiet = True
1080 options.no_logging = True
1081
Rico Wind59593922021-03-03 09:12:36 +01001082 if options.generate_golem_config:
1083 print_golem_config(options)
1084 return 0
1085
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001086 with utils.TempDir() as temp_dir:
1087 if options.hash:
1088 # Download r8-<hash>.jar from
1089 # https://storage.googleapis.com/r8-releases/raw/.
1090 target = 'r8-{}.jar'.format(options.hash)
1091 update_prebuilds_in_android.download_hash(
1092 temp_dir, 'com/android/tools/r8/' + options.hash, target)
1093 as_utils.MoveFile(
1094 os.path.join(temp_dir, target), os.path.join(temp_dir, 'r8lib.jar'),
1095 quiet=options.quiet)
Morten Krogh-Jespersen51db2b02020-11-11 12:49:26 +01001096 elif version_is_built_jar(options.version):
1097 # Download r8-<version>.jar from
1098 # https://storage.googleapis.com/r8-releases/raw/.
1099 target = 'r8-{}.jar'.format(options.version)
1100 update_prebuilds_in_android.download_version(
1101 temp_dir, 'com/android/tools/r8/' + options.version, target)
1102 as_utils.MoveFile(
1103 os.path.join(temp_dir, target), os.path.join(temp_dir, 'r8lib.jar'),
1104 quiet=options.quiet)
Rico Wind1b52acf2021-03-21 12:36:55 +01001105 elif options.version == 'main':
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001106 if not (options.no_build or options.golem):
1107 gradle.RunGradle(['r8', '-Pno_internal'])
1108 build_r8lib = False
1109 for shrinker in options.shrinker:
1110 if is_minified_r8(shrinker):
1111 build_r8lib = True
1112 if build_r8lib:
1113 gradle.RunGradle(['r8lib', '-Pno_internal'])
1114 # Make a copy of r8.jar and r8lib.jar such that they stay the same for
1115 # the entire execution of this script.
1116 if 'r8-nolib' in options.shrinker or 'r8-nolib-full' in options.shrinker:
1117 assert os.path.isfile(utils.R8_JAR), 'Cannot build without r8.jar'
1118 shutil.copyfile(utils.R8_JAR, os.path.join(temp_dir, 'r8.jar'))
1119 if 'r8' in options.shrinker or 'r8-full' in options.shrinker:
1120 assert os.path.isfile(utils.R8LIB_JAR), 'Cannot build without r8lib.jar'
1121 shutil.copyfile(utils.R8LIB_JAR, os.path.join(temp_dir, 'r8lib.jar'))
1122
1123 result_per_shrinker_per_app = []
1124 for app in options.apps:
1125 if app.skip:
1126 continue
1127 result_per_shrinker_per_app.append(
1128 (app, get_results_for_app(app, options, temp_dir)))
Morten Krogh-Jespersenf098b422020-11-11 13:53:52 +01001129 errors = log_results_for_apps(result_per_shrinker_per_app, options)
1130 if errors > 0:
1131 dest = 'gs://r8-test-results/r8-libs/' + str(int(time.time()))
1132 utils.upload_file_to_cloud_storage(os.path.join(temp_dir, 'r8lib.jar'), dest)
1133 print('R8lib saved to %s' % dest)
1134 return errors
Morten Krogh-Jespersen45d7a7b2020-11-02 08:31:09 +01001135
1136
1137def success(message):
1138 CGREEN = '\033[32m'
1139 CEND = '\033[0m'
1140 print(CGREEN + message + CEND)
1141
1142
1143def warn(message):
1144 CRED = '\033[91m'
1145 CEND = '\033[0m'
1146 print(CRED + message + CEND)
1147
1148
1149if __name__ == '__main__':
1150 sys.exit(main(sys.argv[1:]))