-
Notifications
You must be signed in to change notification settings - Fork 329
Bug 1807324 - Add macrobenchmarks for startup metrics #842
Bug 1807324 - Add macrobenchmarks for startup metrics #842
Conversation
a1d7fa5
to
d84b4c1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple small drive-by comments. I am very excited by this though, thanks for bringing it in! Would love to see follow-ups around scrolling the home screen and the tabs tray. Is there a plan to add this to our pipelines as well?
fenix/benchmark/src/main/java/org/mozilla/fenix/benchmark/utils/MacroBenchmarkRule.kt
Outdated
Show resolved
Hide resolved
<profileable | ||
android:shell="true" | ||
tools:targetApi="29" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without looking too deeply, I'm curious whether adding this to our normal manifest could have any impact on production performance and if so whether there is there an easy way to create a "copy" app that we could use under test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question, looking into the docs, the profileable tag makes the non debuggable builds profileable on 29+, it doesn't look like it has any impact on the performance since it's designed to benchmark release builds for more accurate perf metrics.
fenix/benchmark/src/main/java/org/mozilla/fenix/benchmark/utils/Constants.kt
Show resolved
Hide resolved
So, macrobenchmark is mostly used for something that happens once in a while (I.e start up). So this test shouldn't include that in my opinion since we want a clear view of start up. However, we do have microbenchmarks that do just that! I have a patch ready to land that I never landed since there was issues with dependencies a few months ago that seems resolved now. I think if we landed that we would have a good understanding of the entire Home Screen :) |
d7f94fd
to
0314845
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had just a couple more things I wanted to touch on before approving, but this is looking good and I was able to verify the workflow locally.
Running using gradle ./gradlew benchmark:connectedBenchmarkAndroidTest has an issue while installing the apk for the correct ABI. Is that something we've observed before?
I was able to resolve this by adding autosignReleaseWithDebugKey
to my local.properties. Let me know if that helps!
fenix/benchmark/build.gradle
Outdated
debuggable = true | ||
if (gradle.hasProperty("localProperties.autosignReleaseWithDebugKey")) { | ||
signingConfig signingConfigs.debug | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious about 2 things here:
- Does this module need to be debuggable for the profiling to work correctly? Just a little surprising given the emphasis on using release builds, but I didn't actually try the setup wizard
- I think this
signingConfig
property will be added by thereleaseTemplate
closure used in the top-level build file. Is it necessary to have it in both places?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Good question, on my Samsung A50 (android 11) the metrics can't be read/extracted when this is set to false. On Pixel 5 & 7 (android 13) it works regardless of this setting, so I set it true. The samples seem to do the same.
- This is the
benchmark/build.gradle
, the closure is defined inapp/build.gradle
, so that won't work right? Although i'm not sure if this condition is even required. This is something I'd like to get feedback on, based on how we sign apks on CI and how we would like to sign the benchmark apk as well.
/** | ||
* This fixes the dependency resolution issue with Glean Native. The glean gradle plugin does this | ||
* and that's applied to the app module. Since there are no other uses of the glean plugin in the | ||
* benchmark module, we do this manually here. | ||
*/ | ||
configurations.all { | ||
resolutionStrategy.capabilitiesResolution.withCapability("org.mozilla.telemetry:glean-native") { | ||
def toBeSelected = candidates.find { it.id instanceof ModuleComponentIdentifier && it.id.module.contains('geckoview') } | ||
if (toBeSelected != null) { | ||
select(toBeSelected) | ||
} | ||
because 'use GeckoView Glean instead of standalone Glean' | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really understand what's happening here, would you mind explaining it to me?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a build error because of glean dependency resolution conflict as it was coming from geckoview as well. The glean plugin applied on app
module handles this case, along with other functionality. Since benchmark
module doesn't need all the glean gradle plugin's functionalities, we added this to fix the dependency resolution conflict issue. Does that help understand better? 😅 This was an issue that took some time to figure out. Jan Erik was a big here here!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Writing it out helps me remember better, so this is for myself really!
In a regular GeckoView build we have Glean baked in because there is a client within Gecko already so we really want to use that. So when build dependency resolution happens, we want to tell gradle "choose this one, don't worry":
graph TD
A[GeckoView + Glean] --> B[Fenix APK]
C[Rust Components] --> B
In a GeckoView Lite build, which third party consumers may use because they don't want Mozilla telemetry in it, they could still use a separate compiled component for Glean but that would mean there is a large amount of duplication in there, or they have to figure out how to deliver telemetry to and fro from the engine to this separate component (which the path we didn't take because it's quite a bit more complicated):
graph TD
A[GeckoView] --> B[Fenix APK]
C[Rust Components] --> B
D["Glean Component (optional)"] --> B
Oh cool! I would be interested in reading through that patch as well. @rahulsainani another thing to consider for follow-ups: IIRC, we have historically treated time-to-interactivity as a more valuable metric than time-to-display since that captures a more realistic picture of a user experience. I believe this patch only measures the latter, so it would be great to either add that metric to these existing tests or create new ones to measure that separately. I would also be interested in understanding better the results between the startup different flows. These results show a pretty massive difference between hot and cold startup, though I don't know what kind of values to expect. My results on a Pixel 4a, Android 13:
|
This comment was marked as resolved.
This comment was marked as resolved.
0314845
to
610c40d
Compare
@MatthewTighe Good to see it working in your local env 👌 Yes, you're right that this PR only adds Time to initial display (TTID). There's still value in measure TTID as lots happen till that time and it can give a good signal about app performance. I'd like to add tests to get time-to-interactivity aka Time to Full Display (TTFD). For that We can also benchmark other macro flows like Login/Changing language and capture The numbers look consistent to me comparing to Google Play Vitals. Cold Startup is what we're interested in, when the app is not in memory. Hot is when the app is in memory but the activity is in background, all it does it bring it to the foreground. |
Somehow that's not working on my machine, the local.properties flag is needed to run from AS also, so I had it enabled. But it's good to know that it works for you 😄 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good from my perspective, so adding an approval in case it unblocks you. It does sound like maybe you were looking for additional feedback about our CI systems which I am not confident in answering, but it seems like those may be resolved in follow-ups.
Thanks @MatthewTighe for taking the time to review and dig into macrobenchmarks 🙌 |
e97874f
to
2e81c59
Compare
For this unrelated CI failure, please rebase to the latest
|
d470cb9
to
1211794
Compare
Thanks for looking into it and fixing it @jonalmeida 🙌 |
330d90b
to
d930990
Compare
Although this PR doesn't change anything in the main app, after discussing with @csadilek I ran the local perf tests on main and this branch: Sharing some test numbers below: main branch
benchmarks branch (this)
nightly-play (2023-03-03)
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Left one nit about a doc, but that's not blocking being a nit. 🚀
fenix/benchmark/build.gradle
Outdated
buildTypes { | ||
// This benchmark buildType is used for benchmarking, and should function like your | ||
// release build (for example, with minification on). It's signed with a debug key | ||
// for easy local/CI testing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// for easy local/CI testing. | |
// for easy local testing. |
Signing with a debug key is only something that a developer has setup locally. Taskcluster does have a throwaway signing key for CI builds, but I don't think this is the same as the debug one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're looking to iterate this to run on CI builds then we'd need to change this line. For now, it might be prudent to correct docs? I'll leave that up to you to consider.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes the idea would be to run it on CI builds, with the next steps.
Just mentioning, this build.gradle
is for the benchmark
module that generates it's own apk that performs the test on the fenix apk. Not sure if taskcluster already have a signing key for that? I'll remove it for now and we can add this again as/if we run it on CI 👍
/** | ||
* This fixes the dependency resolution issue with Glean Native. The glean gradle plugin does this | ||
* and that's applied to the app module. Since there are no other uses of the glean plugin in the | ||
* benchmark module, we do this manually here. | ||
*/ | ||
configurations.all { | ||
resolutionStrategy.capabilitiesResolution.withCapability("org.mozilla.telemetry:glean-native") { | ||
def toBeSelected = candidates.find { it.id instanceof ModuleComponentIdentifier && it.id.module.contains('geckoview') } | ||
if (toBeSelected != null) { | ||
select(toBeSelected) | ||
} | ||
because 'use GeckoView Glean instead of standalone Glean' | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Writing it out helps me remember better, so this is for myself really!
In a regular GeckoView build we have Glean baked in because there is a client within Gecko already so we really want to use that. So when build dependency resolution happens, we want to tell gradle "choose this one, don't worry":
graph TD
A[GeckoView + Glean] --> B[Fenix APK]
C[Rust Components] --> B
In a GeckoView Lite build, which third party consumers may use because they don't want Mozilla telemetry in it, they could still use a separate compiled component for Glean but that would mean there is a large amount of duplication in there, or they have to figure out how to deliver telemetry to and fro from the engine to this separate component (which the path we didn't take because it's quite a bit more complicated):
graph TD
A[GeckoView] --> B[Fenix APK]
C[Rust Components] --> B
D["Glean Component (optional)"] --> B
d930990
to
e09b5d4
Compare
e09b5d4
to
2638432
Compare
Chatted with @rahulsainani. At the moment, the Mergify merge queue doesn't work anymore because of Mergifyio/mergify#5075. I'm merging this PR manually while we figure out a way to put the merge queue back in a working state. |
Permanent fix will be tracked in https://bugzilla.mozilla.org/show_bug.cgi?id=1822491 |
What
This PR adds introduces jetpack macrobenchmark library to measure startup metrics with different startup modes - Cold, Warm & Hot.
How
– Add dependencies and create
benchmark
module– Fight with Glean and fix dependency conflict
– Add
startupBenchmark
to capture startup metrics.– Run using AndroidStudio just like any other test or using gradle
./gradlew benchmark:connectedBenchmarkAndroid Test
How the results look?
Possible Next Steps
– Run this on CI so we can measure consistently and graph the metrics
– Identify critical app flows and integrate
FrameMetrics
andTraceMetrics
for them– Since this is a prerequisite to add BaselineProfiles, generate and add baseline profiles to improve possibly improve app startup performance, especially for the first week of the new version release (when cloud profiles have not been loaded on the device).
Issues
– Running using gradle
./gradlew benchmark:connectedBenchmarkAndroidTest
has an issue while installing the apk for the correct ABI. Is that something we've observed before?Pull Request checklist
After merge
GitHub Automation
https://bugzilla.mozilla.org/show_bug.cgi?id=1807324