|
|
DescriptionExtend the multidex logic to only kick in for the main browser application.
For each Application instances that falls into the Multidex path,
there is a regression in startup time as it must bootstrap the
classloader to be able to access the additional sources.
During a normal run of Chrome on Android, there are three Application
instances created (Main Browser, Renderer, and GPU).
The renderer process is an isolated process, which was being skipped
with the existing check in this file.
The problem is with the GPU process. We had the assumption that all
non-isolated processes would only be hit once by the Multidex startup
regression, but it turns out that any Application in a different
process is hit by the same slowdown. This means that the first time
the page attempts to paint anything, you see a hang as the GPU process
is attempting to initialize.
This results in a bunch of tests (mainly on K builds on slow devices)
to start flaking as they timeout trying to load the first non
about:blank page.
This change extends the existing check for isolated process to also
skip initializing multi dex for anything running in a separate
process. As a result, anything running in a different process will
need to ensure all code is included in the main dex or force the
additional dex files to be loaded (not as of yet needed), but we
no longer see the slow down on basic operations in Chrome.
BUG=560600
Committed: https://crrev.com/ae7c11660f7b39f2d5c4dc28baf404a45aa0fc2d
Cr-Commit-Position: refs/heads/master@{#361738}
Patch Set 1 #
Total comments: 2
Patch Set 2 : Check for privileged_process explicitly #Patch Set 3 : Switch to using manifest xml #
Total comments: 6
Patch Set 4 : Address review comments #
Messages
Total messages: 24 (8 generated)
tedchoc@chromium.org changed reviewers: + nyquist@chromium.org
PTAL cc yfriedman@ to be amazed/disgusted by the glory
Thanks for putting this hack in the multidex code instead of as a generic tool for others to use... One question though, could you expand the CL description a bit given the... interestingness of the CL...? These questions would be helpful to answer in the description for future readers: - Why do we need to do this? (tests are horrifyingly slow and flake/timeout...) - What happened before? (multidex kicked in...) - How does this change make it better? - Why is the code put in ChromiumMultiDex instead of as a utility in //base/android? https://codereview.chromium.org/1469803007/diff/1/base/android/java/templates... File base/android/java/templates/ChromiumMultiDex.template (right): https://codereview.chromium.org/1469803007/diff/1/base/android/java/templates... base/android/java/templates/ChromiumMultiDex.template:69: try { Nit: Could you extract most of this block out to a private static getCurrentProcessName() (except the return check...)? https://codereview.chromium.org/1469803007/diff/1/base/android/java/templates... base/android/java/templates/ChromiumMultiDex.template:82: return currentProcessName != null && !currentProcessName.contains(":"); Could you add a comment explaining the significance of a colon being part of the process name?
Description was changed from ========== Extend the multidex logic to only kick in for the main browser application. BUG=560600 ========== to ========== Extend the multidex logic to only kick in for the main browser application. For each Application instances that falls into the Multidex path, there is a regression in startup time as it must bootstrap the classloader to be able to access the additional sources. During a normal run of Chrome on Android, there are three Application instances created (Main Browser, Renderer, and GPU). The renderer process is an isolated process, which was being skipped with the existing check in this file. The problem is with the GPU process. We had the assumption that all non-isolated processes would only be hit once by the Multidex startup regression, but it turns out that any Application in a different process is hit by the same slowdown. This means that the first time the page attempts to paint anything, you see a hang as the GPU process is attempting to initialize. This results in a bunch of tests (mainly on K builds on slow devices) to start flaking as they timeout trying to load the first non about:blank page. This change extends the existing check for isolated process to also skip initializing multi dex for anything running in a separate process. As a result, anything running in a different process will need to ensure all code is included in the main dex or force the additional dex files to be loaded (not as of yet needed), but we no longer see the slow down on basic operations in Chrome. BUG=560600 ==========
On 2015/11/25 00:12:52, nyquist wrote: > Thanks for putting this hack in the multidex code instead of as a generic tool > for others to use... > > One question though, could you expand the CL description a bit given the... > interestingness of the CL...? > > These questions would be helpful to answer in the description for future > readers: > - Why do we need to do this? (tests are horrifyingly slow and flake/timeout...) > - What happened before? (multidex kicked in...) > - How does this change make it better? > - Why is the code put in ChromiumMultiDex instead of as a utility in > //base/android? > Expanded the comment. Sadly, I think this change isn't sufficient. We have things that run in separate processes that we need to make sure load all of the dex files. I think I'll need to twiddle with this a bit more. I still want to avoid it for the gpu process as loading a page is the common behavior pattern, but I might have to make this grosser for other places (i.e. the BrowserRestartActivity) > https://codereview.chromium.org/1469803007/diff/1/base/android/java/templates... > File base/android/java/templates/ChromiumMultiDex.template (right): > > https://codereview.chromium.org/1469803007/diff/1/base/android/java/templates... > base/android/java/templates/ChromiumMultiDex.template:69: try { > Nit: Could you extract most of this block out to a private static > getCurrentProcessName() (except the return check...)? > > https://codereview.chromium.org/1469803007/diff/1/base/android/java/templates... > base/android/java/templates/ChromiumMultiDex.template:82: return > currentProcessName != null && !currentProcessName.contains(":"); > Could you add a comment explaining the significance of a colon being part of the > process name?
Updated to check for privileged processes explicitly. This is a gross check to be in base, but I think the "easiest" way to unhose the bots that are currently timing out. Thoughts? Pitchforks?
yfriedman@chromium.org changed reviewers: + yfriedman@chromium.org
Can't really think of a good answer. If you're already getting the process name, you could have a requirement that it reads meta data in the manifest. So basically you'd have something like: <meta-data android:name="<process_name>.load_multidex" android:value="1"> In the absence of it, that process won't do it. I can't really think of another way of doing it given that you only have the app context but I think that could work
On 2015/11/25 01:48:10, Yaron wrote: > Can't really think of a good answer. If you're already getting the process name, > you could have a requirement that it reads meta data in the manifest. So > basically you'd have something like: > > <meta-data android:name="<process_name>.load_multidex" android:value="1"> > > In the absence of it, that process won't do it. I can't really think of another > way of doing it given that you only have the app context but I think that could > work Hmm...that would be somewhat sad to have to set meta data at the application level in addition to defining the <activity> or whatever. And after doing the initial experiment, I think a blacklist for multidex is probably the approach I'd use. So really the change would be to update the privileges service definition to be: {% for i in range(num_privileged_services) %} <meta-data android:name="privileged_process{{ i }}.ignore_multidex" android:value="1" /> .... existing definition <service android:name="org.chromium.content.app.PrivilegedProcessService{{ i }}" android:process=":privileged_process{{ i }}" android:permission="{{ manifest_package }}.permission.CHILD_SERVICE" android:isolatedProcess="false" android:exported="false" /> {% endfor %} I don't really care either way as I hope this to be a short term solution until we figure out why the processes that aren't isolated are behaving badly.
On 2015/11/25 02:36:56, Ted C wrote: > On 2015/11/25 01:48:10, Yaron wrote: > > Can't really think of a good answer. If you're already getting the process > name, > > you could have a requirement that it reads meta data in the manifest. So > > basically you'd have something like: > > > > <meta-data android:name="<process_name>.load_multidex" android:value="1"> > > > > In the absence of it, that process won't do it. I can't really think of > another > > way of doing it given that you only have the app context but I think that > could > > work > > Hmm...that would be somewhat sad to have to set meta data at the application > level in addition to defining the <activity> or whatever. > > And after doing the initial experiment, I think a blacklist for multidex is > probably > the approach I'd use. > > So really the change would be to update the privileges service definition to be: > > {% for i in range(num_privileged_services) %} > <meta-data android:name="privileged_process{{ i }}.ignore_multidex" > android:value="1" /> > > .... existing definition > <service > android:name="org.chromium.content.app.PrivilegedProcessService{{ i }}" > android:process=":privileged_process{{ i }}" > android:permission="{{ manifest_package }}.permission.CHILD_SERVICE" > android:isolatedProcess="false" > android:exported="false" /> > {% endfor %} > > I don't really care either way as I hope this to be a short term solution until > we figure out why the processes that aren't isolated are behaving badly. The multidex support library uses the multidex.version shared preferences file to store the timestamp, the CRC of the APK, and the number of dexes. It uses the timestamp and the CRC to check whether or not it needs to extract the secondary dexes. However, the privileged processes (despite the name) don't have permission to read that shared preferences file, so they always think they need to extract the secondary dexes. This is the logcat from a run with a fresh installation with a few tweaks to ChromiumMultiDex: $ adb logcat -c && adb logcat -v threadtime | grep multidex -i 11-25 05:03:34.229 10018 10018 I cr_base_multidex: timestamp: -1 11-25 05:03:34.229 10018 10018 I cr_base_multidex: crc: -1 11-25 05:03:34.229 10018 10018 I cr_base_multidex: dex.number: 1 11-25 05:03:34.229 10018 10018 I cr_base_multidex: dataDir: /data/data/org.chromium.chrome 11-25 05:03:34.229 10018 10018 I cr_base_multidex: shared preferences file: /data/data/org.chromium.chrome/shared_prefs/multidex.version.xml 11-25 05:03:34.229 10018 10018 I cr_base_multidex: readable: false 11-25 05:03:34.229 10018 10018 I MultiDex: VM with version 1.6.0 does not have multidex support 11-25 05:03:34.229 10018 10018 I MultiDex: install 11-25 05:03:34.229 10018 10018 I MultiDex: MultiDexExtractor.load(/data/app/org.chromium.chrome-1.apk, false) 11-25 05:03:34.239 10018 10018 I MultiDex: Detected that extraction must be performed. 11-25 05:03:34.289 10018 10018 I MultiDex: Extraction is needed for file /data/data/org.chromium.chrome/code_cache/secondary-dexes/org.chromium.chrome-1.apk.classes2.zip 11-25 05:03:34.289 10018 10018 I MultiDex: Extracting /data/data/org.chromium.chrome/code_cache/secondary-dexes/org.chromium.chrome-1.apk.classes-734512617.zip 11-25 05:03:35.559 10018 10018 I MultiDex: Renaming to /data/data/org.chromium.chrome/code_cache/secondary-dexes/org.chromium.chrome-1.apk.classes2.zip 11-25 05:03:35.559 10018 10018 I MultiDex: Extraction success - length /data/data/org.chromium.chrome/code_cache/secondary-dexes/org.chromium.chrome-1.apk.classes2.zip: 2298991 11-25 05:03:35.559 10018 10018 I MultiDex: load found 1 secondary dex files 11-25 05:03:36.639 10018 10018 I MultiDex: install done 11-25 05:03:36.639 10018 10018 I cr_base_multidex: Completed multidex installation. 11-25 05:03:36.639 10018 10018 I cr_base_multidex: timestamp: 1448427726000 11-25 05:03:36.639 10018 10018 I cr_base_multidex: crc: 750363190 11-25 05:03:36.649 10018 10018 I cr_base_multidex: dex.number: 2 11-25 05:03:36.649 10018 10018 I cr_base_multidex: dataDir: /data/data/org.chromium.chrome 11-25 05:03:36.649 10018 10018 I cr_base_multidex: shared preferences file: /data/data/org.chromium.chrome/shared_prefs/multidex.version.xml 11-25 05:03:36.649 10018 10018 I cr_base_multidex: readable: true 11-25 05:03:36.649 10018 10018 I MultiDex: install 11-25 05:03:36.649 10018 10018 I cr_base_multidex: Completed multidex installation. 11-25 05:03:37.329 10065 10065 I cr_base_multidex: Skipping multidex installation: inside isolated process. 11-25 05:03:37.599 10102 10102 I cr_base_multidex: timestamp: -1 11-25 05:03:37.599 10102 10102 I cr_base_multidex: crc: -1 11-25 05:03:37.599 10102 10102 I cr_base_multidex: dex.number: 1 11-25 05:03:37.599 10102 10102 I cr_base_multidex: dataDir: /data/data/org.chromium.chrome 11-25 05:03:37.599 10102 10102 I cr_base_multidex: shared preferences file: /data/data/org.chromium.chrome/shared_prefs/multidex.version.xml 11-25 05:03:37.599 10102 10102 I cr_base_multidex: readable: false 11-25 05:03:37.609 10102 10102 I MultiDex: VM with version 1.6.0 does not have multidex support 11-25 05:03:37.609 10102 10102 I MultiDex: install 11-25 05:03:37.609 10102 10102 I MultiDex: MultiDexExtractor.load(/data/app/org.chromium.chrome-1.apk, false) 11-25 05:03:37.609 10102 10102 I MultiDex: Detected that extraction must be performed. 11-25 05:03:37.699 10102 10102 I MultiDex: Extraction is needed for file /data/data/org.chromium.chrome/code_cache/secondary-dexes/org.chromium.chrome-1.apk.classes2.zip 11-25 05:03:37.699 10102 10102 I MultiDex: Extracting /data/data/org.chromium.chrome/code_cache/secondary-dexes/org.chromium.chrome-1.apk.classes-734512617.zip 11-25 05:03:39.109 10102 10102 I MultiDex: Renaming to /data/data/org.chromium.chrome/code_cache/secondary-dexes/org.chromium.chrome-1.apk.classes2.zip 11-25 05:03:39.109 10102 10102 I MultiDex: Extraction success - length /data/data/org.chromium.chrome/code_cache/secondary-dexes/org.chromium.chrome-1.apk.classes2.zip: 2298991 11-25 05:03:39.109 10102 10102 I MultiDex: load found 1 secondary dex files 11-25 05:03:40.249 10102 10102 I MultiDex: install done 11-25 05:03:40.249 10102 10102 I cr_base_multidex: Completed multidex installation. 10018, the browser process, extracts the secondary dex. 10065, the renderer process, is isolated and skips multidex installation entirely. 10102, the privileged process, doesn't have permission to read the shared preferences but does have permission to read and extract the secondary dex. I'm looking a little into why a service process wouldn't be able to open a shared preferences file, but I haven't found anything yet.
Just uploaded a version that uses the manifest meta-data approach. How does that look?
jbudorick@chromium.org changed reviewers: + jbudorick@chromium.org
https://codereview.chromium.org/1469803007/diff/40001/base/android/java/templ... File base/android/java/templates/ChromiumMultiDex.template (right): https://codereview.chromium.org/1469803007/diff/40001/base/android/java/templ... base/android/java/templates/ChromiumMultiDex.template:51: && !shouldInstallMultiDex(context)) { One other thing to consider: we could potentially only skip multidex extraction rather than skipping installation entirely. This would involve reflecting into the multidex support library, but it would let privileged processes use code from secondary dexes without having to pay the extraction penalty every time.
https://codereview.chromium.org/1469803007/diff/40001/base/android/java/templ... File base/android/java/templates/ChromiumMultiDex.template (right): https://codereview.chromium.org/1469803007/diff/40001/base/android/java/templ... base/android/java/templates/ChromiumMultiDex.template:51: && !shouldInstallMultiDex(context)) { On 2015/11/25 18:13:35, jbudorick wrote: > One other thing to consider: we could potentially only skip multidex extraction > rather than skipping installation entirely. This would involve reflecting into > the multidex support library, but it would let privileged processes use code > from secondary dexes without having to pay the extraction penalty every time. Maybe, but right now it doesn't seem we need anything from the secondary dexes, so this seems like even more complication for stuff that is unneeded.
lgtm https://codereview.chromium.org/1469803007/diff/40001/base/android/java/templ... File base/android/java/templates/ChromiumMultiDex.template (right): https://codereview.chromium.org/1469803007/diff/40001/base/android/java/templ... base/android/java/templates/ChromiumMultiDex.template:29: private static final String IGNORE_MULTIDEX_KEY = ".ignore_multidex"; Could you add a comment here referring to the value in the manifest?
lgtm https://codereview.chromium.org/1469803007/diff/40001/chrome/android/java/And... File chrome/android/java/AndroidManifest.xml (right): https://codereview.chromium.org/1469803007/diff/40001/chrome/android/java/And... chrome/android/java/AndroidManifest.xml:608: <meta-data android:name="{{ manifest_package }}{{ privileged_process_name }}.ignore_multidex" nit: omit this for release builds (ok as follow-up)
https://codereview.chromium.org/1469803007/diff/40001/base/android/java/templ... File base/android/java/templates/ChromiumMultiDex.template (right): https://codereview.chromium.org/1469803007/diff/40001/base/android/java/templ... base/android/java/templates/ChromiumMultiDex.template:29: private static final String IGNORE_MULTIDEX_KEY = ".ignore_multidex"; On 2015/11/25 18:57:20, nyquist wrote: > Could you add a comment here referring to the value in the manifest? Done. https://codereview.chromium.org/1469803007/diff/40001/chrome/android/java/And... File chrome/android/java/AndroidManifest.xml (right): https://codereview.chromium.org/1469803007/diff/40001/chrome/android/java/And... chrome/android/java/AndroidManifest.xml:608: <meta-data android:name="{{ manifest_package }}{{ privileged_process_name }}.ignore_multidex" On 2015/11/25 19:02:59, Yaron wrote: > nit: omit this for release builds (ok as follow-up) Added a TODO, this looks like it will require adding a new jinja variable as build type is not exposed as of yet. So a follow up will be better.
The CQ bit was checked by tedchoc@chromium.org
The patchset sent to the CQ was uploaded after l-g-t-m from nyquist@chromium.org, yfriedman@chromium.org Link to the patchset: https://codereview.chromium.org/1469803007/#ps60001 (title: "Address review comments")
CQ is trying da patch. Follow status at https://chromium-cq-status.appspot.com/patch-status/1469803007/60001 View timeline at https://chromium-cq-status.appspot.com/patch-timeline/1469803007/60001
Message was sent while issue was closed.
Description was changed from ========== Extend the multidex logic to only kick in for the main browser application. For each Application instances that falls into the Multidex path, there is a regression in startup time as it must bootstrap the classloader to be able to access the additional sources. During a normal run of Chrome on Android, there are three Application instances created (Main Browser, Renderer, and GPU). The renderer process is an isolated process, which was being skipped with the existing check in this file. The problem is with the GPU process. We had the assumption that all non-isolated processes would only be hit once by the Multidex startup regression, but it turns out that any Application in a different process is hit by the same slowdown. This means that the first time the page attempts to paint anything, you see a hang as the GPU process is attempting to initialize. This results in a bunch of tests (mainly on K builds on slow devices) to start flaking as they timeout trying to load the first non about:blank page. This change extends the existing check for isolated process to also skip initializing multi dex for anything running in a separate process. As a result, anything running in a different process will need to ensure all code is included in the main dex or force the additional dex files to be loaded (not as of yet needed), but we no longer see the slow down on basic operations in Chrome. BUG=560600 ========== to ========== Extend the multidex logic to only kick in for the main browser application. For each Application instances that falls into the Multidex path, there is a regression in startup time as it must bootstrap the classloader to be able to access the additional sources. During a normal run of Chrome on Android, there are three Application instances created (Main Browser, Renderer, and GPU). The renderer process is an isolated process, which was being skipped with the existing check in this file. The problem is with the GPU process. We had the assumption that all non-isolated processes would only be hit once by the Multidex startup regression, but it turns out that any Application in a different process is hit by the same slowdown. This means that the first time the page attempts to paint anything, you see a hang as the GPU process is attempting to initialize. This results in a bunch of tests (mainly on K builds on slow devices) to start flaking as they timeout trying to load the first non about:blank page. This change extends the existing check for isolated process to also skip initializing multi dex for anything running in a separate process. As a result, anything running in a different process will need to ensure all code is included in the main dex or force the additional dex files to be loaded (not as of yet needed), but we no longer see the slow down on basic operations in Chrome. BUG=560600 ==========
Message was sent while issue was closed.
Committed patchset #4 (id:60001)
Message was sent while issue was closed.
Description was changed from ========== Extend the multidex logic to only kick in for the main browser application. For each Application instances that falls into the Multidex path, there is a regression in startup time as it must bootstrap the classloader to be able to access the additional sources. During a normal run of Chrome on Android, there are three Application instances created (Main Browser, Renderer, and GPU). The renderer process is an isolated process, which was being skipped with the existing check in this file. The problem is with the GPU process. We had the assumption that all non-isolated processes would only be hit once by the Multidex startup regression, but it turns out that any Application in a different process is hit by the same slowdown. This means that the first time the page attempts to paint anything, you see a hang as the GPU process is attempting to initialize. This results in a bunch of tests (mainly on K builds on slow devices) to start flaking as they timeout trying to load the first non about:blank page. This change extends the existing check for isolated process to also skip initializing multi dex for anything running in a separate process. As a result, anything running in a different process will need to ensure all code is included in the main dex or force the additional dex files to be loaded (not as of yet needed), but we no longer see the slow down on basic operations in Chrome. BUG=560600 ========== to ========== Extend the multidex logic to only kick in for the main browser application. For each Application instances that falls into the Multidex path, there is a regression in startup time as it must bootstrap the classloader to be able to access the additional sources. During a normal run of Chrome on Android, there are three Application instances created (Main Browser, Renderer, and GPU). The renderer process is an isolated process, which was being skipped with the existing check in this file. The problem is with the GPU process. We had the assumption that all non-isolated processes would only be hit once by the Multidex startup regression, but it turns out that any Application in a different process is hit by the same slowdown. This means that the first time the page attempts to paint anything, you see a hang as the GPU process is attempting to initialize. This results in a bunch of tests (mainly on K builds on slow devices) to start flaking as they timeout trying to load the first non about:blank page. This change extends the existing check for isolated process to also skip initializing multi dex for anything running in a separate process. As a result, anything running in a different process will need to ensure all code is included in the main dex or force the additional dex files to be loaded (not as of yet needed), but we no longer see the slow down on basic operations in Chrome. BUG=560600 Committed: https://crrev.com/ae7c11660f7b39f2d5c4dc28baf404a45aa0fc2d Cr-Commit-Position: refs/heads/master@{#361738} ==========
Message was sent while issue was closed.
Patchset 4 (id:??) landed as https://crrev.com/ae7c11660f7b39f2d5c4dc28baf404a45aa0fc2d Cr-Commit-Position: refs/heads/master@{#361738} |