Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CI: performance impact measurements #2171

Merged
merged 70 commits into from
Sep 17, 2022
Merged

CI: performance impact measurements #2171

merged 70 commits into from
Sep 17, 2022

Conversation

vaind
Copy link
Collaborator

@vaind vaind commented Jul 13, 2022

Approach and scope of this PR

See my notes below on Macrobenchmark - after facing issues trying to get it to work on SauceLabs, I have pivoted towards Appium as it can be used to run both iOS and Android, and should also be usable for our other SDKs: Flutter, Unity, React-Native)

  • two simple apps (created with Android Studio -> New Project -> Basic Activity, without any more changes), the only difference being Sentry added in one of them.
  • build the apks for both apps (this can later be used for another check described in team-mobile#5
  • use Appium (through its Java SDK) on SauceLabs to launch both apps multiple times and measure the difference between them and also check sizes
  • add simple absolute-value tests (not comparing to values from the main branch yet)
  • print results in CI - the current output looks like this ("filtered" = outliers removed using the interquartile range):
[0-0] App io.sentry.java.tests.perf.appplain  launch times (original) | mean: 937.82 ms | stddev: 45.45 | values: [1038,891,901,946,918,907,911,922,945,1070,952,946,922,902,969,932,939,883,919,941,900,891,960,928,900,1015,1024,998,968,958,946,967,1010,921,965,904,1061,920,957,912,910,882,905,922,919,888,933,899,894,880]
[0-0] App io.sentry.java.tests.perf.appplain  launch times (filtered) | mean: 932.50 ms | stddev: 37.99 | values: [880,882,883,888,891,891,894,899,900,900,901,902,904,905,907,910,911,912,918,919,919,920,921,922,922,922,928,932,933,939,941,945,946,946,946,952,957,958,960,965,967,968,969,998,1010,1015,1024,1038]
[0-0] App io.sentry.java.tests.perf.appsentry launch times (original) | mean: 1004.14 ms | stddev: 24.21 | values: [1030,1017,948,1000,1034,966,1039,979,1008,995,1024,939,966,1010,1029,1018,1000,1027,993,993,975,1060,982,1030,1036,1016,1008,1023,1012,1034,987,1000,996,1012,1029,1032,1003,996,1013,984,985,1017,1001,976,992,1031,995,975,993,999]
[0-0] App io.sentry.java.tests.perf.appsentry launch times (filtered) | mean: 1005.47 ms | stddev: 22.57 | values: [948,966,966,975,975,976,979,982,984,985,987,992,993,993,993,995,995,996,996,999,1000,1000,1000,1001,1003,1008,1008,1010,1012,1012,1013,1016,1017,1017,1018,1023,1024,1027,1029,1029,1030,1030,1031,1032,1034,1034,1036,1039,1060]
[0-0] App io.sentry.java.tests.perf.appsentry takes approximately  72 ms more time to start than app io.sentry.java.tests.perf.appplain
[0-0] App io.sentry.java.tests.perf.appplain  size is 1.64MB
[0-0] App io.sentry.java.tests.perf.appsentry size is 3.56MB
[0-0] App io.sentry.java.tests.perf.appsentry is 1.92MB larger than app io.sentry.java.tests.perf.appplain

Next steps

  • post comment to PR - CI: performance impact measurements #2171 (comment)
  • test apk size difference
  • collect the stats somewhere (maybe even Sentry transactions) so that later we can also fail if the time grows significantly
  • adapt the Appium project to support iOS (minor changes) and likely move to a separate repo/action

Notes on Macrobenchmark

I have first tried using jetpack macrobenchmark by deploying the app from getsentry/sentry-android-gradle-plugin#317 to SauceLabs - the only option that seemed like it could work was using the espresso configuration for SauceLabs - it didn't though work though, the error was as follows, regardless of the config I tried (current state in https://github.com/vaind/sentry-android-gradle-plugin/commits/perf/benchmark-app-startup-time - if anyone wants to give it a try).

ERROR: Benchmark Target is Debuggable
Target package io.sentry.samples.instrumentation
is running with debuggable=true, which drastically reduces
runtime performance in order to support debugging features. Run
benchmarks with debuggable=false. Debuggable affects execution speed
in ways that mean benchmark improvements might not carry over to a
real user's experience (or even regress release performance).

While you can suppress these errors (turning them into warnings)
PLEASE NOTE THAT EACH SUPPRESSED ERROR COMPROMISES ACCURACY

// Sample suppression, in a benchmark module's build.gradle:
android {
defaultConfig {
testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE"
}
}
at androidx.benchmark.ConfigurationErrorKt.checkAndGetSuppressionState(ConfigurationError.kt:124)
at androidx.benchmark.macro.MacrobenchmarkKt.checkErrors(Macrobenchmark.kt:95)
at androidx.benchmark.macro.MacrobenchmarkKt.macrobenchmark(Macrobenchmark.kt:126)
at androidx.benchmark.macro.MacrobenchmarkKt.macrobenchmarkWithStartupMode(Macrobenchmark.kt:301)
at androidx.benchmark.macro.junit4.MacrobenchmarkRule.measureRepeated(MacrobenchmarkRule.kt:106)
at io.sentry.samples.instrumentation.benchmark.ExampleStartupBenchmark.startup(ExampleStartupBenchmark.kt:33)

#skip-changelog

@codecov-commenter
Copy link

codecov-commenter commented Jul 14, 2022

Codecov Report

Base: 80.62% // Head: 80.62% // No change to project coverage 👍

Coverage data is based on head (a43974f) compared to base (de74337).
Patch has no changes to coverable lines.

Additional details and impacted files
@@            Coverage Diff            @@
##               main    #2171   +/-   ##
=========================================
  Coverage     80.62%   80.62%           
  Complexity     3358     3358           
=========================================
  Files           240      240           
  Lines         12337    12337           
  Branches       1639     1639           
=========================================
  Hits           9947     9947           
  Misses         1783     1783           
  Partials        607      607           

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@philipphofmann
Copy link
Member

I think it would be nice to use the official Android lib recommended by Google for benchmarking the app start time.
@romtsn, as you are one of our Gradle experts, could you maybe look at why the Jetpack Macrobenchmark lib used the debug config as pointed out by @vaind?
If it doesn't work out, we can use a different approach as suggested by you @vaind, of course.

@vaind
Copy link
Collaborator Author

vaind commented Jul 18, 2022

I think it would be nice to use the official Android lib recommended by Google for benchmarking the app start time. @romtsn, as you are one of our Gradle experts, could you maybe look at why the Jetpack Macrobenchmark lib used the debug config as pointed out by @vaind? If it doesn't work out, we can use a different approach as suggested by you @vaind, of course.

FYI there was also some discussion on Discord: https://discord.com/channels/621778831602221064/621783562739384331/996842523446222909

@vaind
Copy link
Collaborator Author

vaind commented Jul 19, 2022

Any hints how to fix the CI build failure?

FAILURE: Build failed with an exception.
Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
* What went wrong:
Could not determine the dependencies of task ':performance-tests:test-app-sentry:compileDebugJavaWithJavac'.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
See https://docs.gradle.org/7.4.2/userguide/command_line_interface.html#sec:command_line_warnings
6 actionable tasks: 6 up-to-date
> Could not resolve all task dependencies for configuration ':performance-tests:test-app-sentry:debugCompileClasspath'.
   > Could not resolve project :sentry-android.
     Required by:
         project :performance-tests:test-app-sentry
      > No matching variant of project :sentry-android was found. The consumer was configured to find an API of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.2.0' but:
          - Variant 'releaseApiElements' capability io.sentry:sentry-android:6.2.1 declares an API of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.2.0':
              - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug'
          - Variant 'releaseRuntimeElements' capability io.sentry:sentry-android:6.2.1 declares a runtime of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.2.0':
              - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug'
              ```

@romtsn
Copy link
Member

romtsn commented Jul 19, 2022

Any hints how to fix the CI build failure?

FAILURE: Build failed with an exception.
Deprecated Gradle features were used in this build, making it incompatible with Gradle 8.0.
* What went wrong:
Could not determine the dependencies of task ':performance-tests:test-app-sentry:compileDebugJavaWithJavac'.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
See https://docs.gradle.org/7.4.2/userguide/command_line_interface.html#sec:command_line_warnings
6 actionable tasks: 6 up-to-date
> Could not resolve all task dependencies for configuration ':performance-tests:test-app-sentry:debugCompileClasspath'.
   > Could not resolve project :sentry-android.
     Required by:
         project :performance-tests:test-app-sentry
      > No matching variant of project :sentry-android was found. The consumer was configured to find an API of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.2.0' but:
          - Variant 'releaseApiElements' capability io.sentry:sentry-android:6.2.1 declares an API of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.2.0':
              - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug'
          - Variant 'releaseRuntimeElements' capability io.sentry:sentry-android:6.2.1 declares a runtime of a component, preferably optimized for Android, as well as attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.2.0':
              - Incompatible because this component declares a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'release' and the consumer needed a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'debug'
              ```

It's likely because you also need to exclude them for bom and distribution, like we did with sentry-test-support:

dependencies {
constraints {
project.rootProject.subprojects
.filter {
!it.name.startsWith("sentry-samples") &&
it.name != project.name &&
it.name != "sentry-test-support"
}
.forEach {
api(it)
}
}
}

and

if (!this.name.contains("sample") && !this.name.contains("integration-tests") && this.name != "sentry-test-support") {

@romtsn
Copy link
Member

romtsn commented Jul 19, 2022

@vaind sorry man, I haven't got time to look at the PR, so I will leave this to @marandaneto as I'm on parental leave starting from tomorrow. Good luck!

@vaind
Copy link
Collaborator Author

vaind commented Jul 20, 2022

@vaind sorry man, I haven't got time to look at the PR, so I will leave this to @marandaneto as I'm on parental leave starting from tomorrow. Good luck!

thanks and enjoy the time with your kid/s

@vaind vaind marked this pull request as ready for review August 17, 2022 14:57
@vaind vaind requested review from adinauer and romtsn as code owners August 17, 2022 14:57
philipphofmann pushed a commit to getsentry/sentry-cocoa that referenced this pull request Aug 31, 2022
See the overall issue at getsentry/team-mobile#5 and the sibling PR at sentry-java for the approach & some more details: getsentry/sentry-java#2171
@github-actions
Copy link
Contributor

github-actions bot commented Sep 8, 2022

Performance metrics 🚀

Plain With Sentry Diff
Startup time (ms) 370.61 399.90 29.29
Size (bytes) 1825823 2445266 619443

@getsentry getsentry deleted a comment from github-actions bot Sep 9, 2022
@marandaneto
Copy link
Contributor

@vaind I left a comment, is there anything pending or ready to merge?

}
}

dependencies {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Sentry Android Core lib has the dependencies of:

    // lifecycle processor, session tracking
    implementation(Config.Libs.lifecycleProcess)
    implementation(Config.Libs.lifecycleCommonJava8)
    implementation(Config.Libs.androidxCore)

But most if not all Apps also have them as well, what if we add those dependencies in the plain test so they are not counted for the diff in size?

Copy link
Collaborator Author

@vaind vaind Sep 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, personally I'm not sure about that - you'd know better. Maybe we can try in a followup PR what's the difference?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good, so we unblock this PR.

@vaind
Copy link
Collaborator Author

vaind commented Sep 17, 2022

@vaind I left a comment, is there anything pending or ready to merge?

Good to go from my POV

Copy link
Contributor

@marandaneto marandaneto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @vaind

@marandaneto marandaneto merged commit 429f878 into main Sep 17, 2022
@marandaneto marandaneto deleted the ci/perf-tests branch September 17, 2022 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Measure Sentry.init impact on app startup time
8 participants