Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

io22 extended What's new in app performance

io22 extended What's new in app performance

20220611 구글 스타트업 캠퍼스
2022 IO Extended Korea Android 에서
What's new in app performance 주제로 발표한 자료입니다.
https://www.youtube.com/watch?v=1TsQ0buZUas

Veronikapj

June 11, 2022
Tweet

More Decks by Veronikapj

Other Decks in Programming

Transcript

  1. Why? 30 % 2.4 % ࡈۄ૓ জ द੘ दр Ѩ࢝

    ૐо Source: goo.gle/3JCc453
  2. ੉Ѫ਷ ޖ঺ ੌөਃ? ٜযоӝী খࢲ “জ੄ द੘ਸ ୭੸ച ೞҊ, ߡߢѢܿਸ

    ઴੉ݴ ୭ઙ ࢎਊ੗ ࢿמਸ ѐࢶೡ ࣻ ੓ب۾ ೞח ೐۽೙ ӝ߈ ୭੸ച(PGO, Profile Guided Optimization)੄ ೠ ഋకੑפ׮.” https://forms.gle/MSzZ53RQ3jH6Qm758
  3. 1. Macrobenchmark 2. Baseline Profiles 3. Microbenchmark 4. Android Profiler

    ٜযоӝী খࢲ “জ੄ द੘ਸ ୭੸ച ೞҊ, ߡߢѢܿ ਸ ઴੉ݴ ୭ઙ ࢎਊ੗ ࢿמਸ ѐࢶೡ ࣻ ੓ب۾ ೞח ೐۽೙ ӝ߈ ୭੸ച (PGO, Profile Guided Optimization)੄ ೠ ഋకੑפ׮.”
  4. Baseline Profiles stable androidx.profileinstaller:profileinstaller:1.1.0 ޷ܻ ٜ݅য فח App profiles Startup

    दр хࣗ & Jank хࣗ https://www.youtube.com/watch?v=jTd82lcuHTU IO 22 What’s new in Jetpack
  5. জ ߂ ۄ੉࠳۞ܻীࢲ custom profile rule ઁҕ Startup ߂ jack

    performance ೱ࢚ ੋӝ ੓ח Jetpack librariesী profile ୶о Baseline Profiles https://www.youtube.com/watch?v=jTd82lcuHTU IO 22 What’s new in Jetpack
  6. h tt ps://github.com/android/sun fl ower Sunflower పझ౟ प೯ ߂ ৮ܐ

    -> ೐۽೙ ࢤࢿ ls /storage/emulated/0/Android/media/app.name Sample_startup-baseline-prof.txt ੉ܴਸ baseline-prof.txtਵ۽ ߸҃೧ࢲ app/src/main ߃ী ਤ஖ Baseline Profile
  7. ۄ੉࠳۞ܻ৬ গ೒ܻா੉࣌਷ ৔ೱਸ ӓ؀ചೞח ୭ࣗೠ੄ ೐۽೙ ӏ஗ਸ ੿੄ (Size <

    1.5 MB) 
 গ೒ܻா੉࣌੄ ցޖ ݆਷ ࠗ࠙ਸ ஹ౵ੌೞח ҟߧਤೠ ӏ஗਷ ٣झ௼ ঘࣁझ പࣻо טӝ ٸޙী द੘ ࣘبܳ וܻѱ ٜ݅ ࣻ ੓णפ׮. যڃ ӝળਵ۽ Baseline Pro fi leਸ ࢸ੿ೡ Ѫ ੋ૑ ߈٘द పझ౟೧ࢲ ੸ਊೞח Ѫ੉ જणפ׮. Q & A সؘ੉౟ ੸ਊ दী Ҋ۰೧ঠ ೡ Ѫ https://developer.android.com/studio/pro fi le/baselinepro fi les
  8. App Startup stable androidx.startup:startup-runtime:1.1.1 জ द੘ द ҳࢿਃࣗܳ ୡӝചೞח ߑߨ

    ઁҕ द੘ ࣽࢲ рࣗച, ୡӝച ࣽࢲ ݺद੸ਵ۽ ࢸ੿ https://developer.android.com/topic/libraries/app-startup
  9. জ द੘ ઺ ܻࣗझ ҃೤ ߑ૑(Avoid resource contention ) Ҋࢿמ

    ஹನք౟ ୡӝച(Performant component initialization) App Startup https://youtu.be/DYdHLqLVspY IO 22 What’s new in App performance
  10. class SyncRepoInitializer : Initializer<SyncRepo> { override fun create(context: Context): SyncRepo

    { return SyncRepo(WorkManager.getInstance(context)) } override fun dependencies() : List<Class<out Initializer<*>>> { return listOf(WorkManagerInitializer::class.java) } } https://youtu.be/DYdHLqLVspY IO 22 What’s new in App performance
  11. class SyncRepoInitializer : Initializer<SyncRepo> { override fun create(context: Context): SyncRepo

    { return SyncRepo(WorkManager.getInstance(context)) } override fun dependencies() : List<Class<out Initializer<*>>> { return listOf(WorkManagerInitializer::class.java) } } https://youtu.be/DYdHLqLVspY IO 22 What’s new in App performance
  12. <provider android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" android:exported="false" tools:node="merge"> <!-- This entry makes SyncRepoInitializer

    discoverable. --> <meta-data android:name="com.example.SyncRepoInitializer" android:value="androidx.startup" /> </provider> https://developer.android.com/topic/libraries/app-startup AndroidManifest.xml
  13. ӝࠄ ਊয ੿ܻ https://www.youtube.com/watch?v=0adLO2VRJtc IO 21 Macrobenchmark۽ ߡߢѢܿ ߂ झఋ౟স

    ஏ੿ 60Hz ചݶী झ௼܀, ੹ജ, গפݫ੉࣌ ١੄ ਑ ૒੐੉ ੓ਵݶ জীࢲ ࢜۽ Ҋஜ ࣘبী ݏ ѱ ୡ׼ 60೐ۨ੐ਸ ࢤࢿ Jank? জ੉ ചݶਸ ࢜۽ Ӓܻݶࢲ ߊࢤೞח ߡߢѢܿ੉ա ݥ୺ਸ ੄޷
  14. ӝࠄ ਊয ੿ܻ https://www.youtube.com/watch?v=0adLO2VRJtc IO 21 Macrobenchmark۽ ߡߢѢܿ ߂ झఋ౟স

    ஏ੿ 60Hz ചݶী झ௼܀, ੹ജ, গפݫ੉࣌ ١੄ ਑ ૒੐੉ ੓ਵݶ জীࢲ ࢜۽ Ҋஜ ࣘبী ݏ ѱ ୡ׼ 60೐ۨ੐ਸ ࢤࢿ Jank? জ੄ ೐ۨ੐ ࢤࢿ ࣘبо ցޖ ןযࢲ ࢤӣ
  15. ࠙ࢳ ੿ࠁী݅ ੄૑ೡ ࣻ হ਺ . ׮নೠ ૑಴о ੓૑݅ प

    ࢎਊ ૑಴ח ࡈܻ ঳ਸ ࣻ হ਺. Metrics from the field are not enough 01 Existing Benchmark library is limited 02 ࠛউ੿ೞѢա, प೯ೡ loopо ߸زغѢ ա दझమ੉ ࠂ੟ೞҊ ֢੉ૉо ݆Ѣա ৢ߄ܰѱ ࢸ੿ೞӝ য۰਎ ࣻ ੓਺. Stable Measurement is not easy 03 ٜযоӝী খࢲ “জ ࢿמ ѐࢶ੉ য۰ਕਃ” ӝઓ੄ Jetpack benchmarking ۄ੉ ࠳۞ܻח জ द੘੉ա Jank ܳ ஏ੿ೡ ࣻ হ਺ . MicroBenchmarkח ؀׮ࣻ ࢎਊ ࢎ۹ ী ੸ਊغ૑ ঋ਺. द੘ दр ؀न CPU ܳ ஏ੿ https://www.youtube.com/watch?v=0adLO2VRJtc IO 21 Macrobenchmark۽ ߡߢѢܿ ߂ झఋ౟স ஏ੿
  16. Macrobenchmark stable androidx.benchmark:benchmark-macro:1.1.0 ੿ഛೠ App Startup ஏ੿ Scrolling ࢿמ ஏ੿

    Locally & CI https://www.youtube.com/watch?v=jTd82lcuHTU IO 22 What’s new in Jetpack
  17. StartupBenchmarks.kt private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated( packageName = PACKAGE_NAME,

    metrics = listOf(StartupTimingMetric()), iterations = 5, compilationMode = compilationMode, startupMode = StartupMode.COLD, setupBlock = { pressHome() } ) { startActivityAndWait() // wait for the content called by reportFullyDrawn is visible val recyclerHasChild = By.hasChild(By.res(packageName, "garden_list")) device.wait(Until.hasObject(recyclerHasChild), 5_000) }
  18. StartupBenchmarks.kt private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated( packageName = PACKAGE_NAME,

    metrics = listOf(StartupTimingMetric()), iterations = 5, compilationMode = compilationMode, startupMode = StartupMode.COLD, setupBlock = { pressHome() } ) { startActivityAndWait() // wait for the content called by reportFullyDrawn is visible val recyclerHasChild = By.hasChild(By.res(packageName, "garden_list")) device.wait(Until.hasObject(recyclerHasChild), 5_000) }
  19. StartupBenchmarks.kt private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated( packageName = PACKAGE_NAME,

    metrics = listOf(StartupTimingMetric()), iterations = 5, compilationMode = compilationMode, startupMode = StartupMode.COLD, setupBlock = { pressHome() } ) { startActivityAndWait() // wait for the content called by reportFullyDrawn is visible val recyclerHasChild = By.hasChild(By.res(packageName, "garden_list")) device.wait(Until.hasObject(recyclerHasChild), 5_000) } Metric StartupTimingMetric জ द੘ दр ஏ੿ FrameTimingMetric п ೐ۨ੐ ఋ੉߁ ੿ࠁ
  20. StartupBenchmarks.kt private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated( packageName = PACKAGE_NAME,

    metrics = listOf(StartupTimingMetric()), iterations = 5, compilationMode = compilationMode, startupMode = StartupMode.COLD, setupBlock = { pressHome() } ) { startActivityAndWait() // wait for the content called by reportFullyDrawn is visible val recyclerHasChild = By.hasChild(By.res(packageName, "garden_list")) device.wait(Until.hasObject(recyclerHasChild), 5_000) }
  21. StartupBenchmarks.kt @Test fun startupCompilationNone() = startup(CompilationMode.None()) @Test fun startupCompilationPartial() =

    startup(CompilationMode.Partial()) @Test fun startupCompilationWarmup() = startup(CompilationMode.Partial(BaselineProfileMode.Disable, 2))
  22. StartupBenchmarks.kt @Test fun startupCompilationNone() = startup(CompilationMode.None()) @Test fun startupCompilationPartial() =

    startup(CompilationMode.Partial()) @Test fun startupCompilationWarmup() = startup(CompilationMode.Partial(BaselineProfileMode.Disable, 2))
  23. CompilationMode.kt @Test fun startupCompilationPartial() = startup(CompilationMode.Partial()) @RequiresApi(24) class Partial @JvmOverloads

    constructor( val baselineProfileMode: BaselineProfileMode = BaselineProfileMode.Require, / . . . / ) : CompilationMode() { ... }
  24. @Test fun startupCompilationNone() = startup(CompilationMode.None()) @Test fun startupCompilationPartial() = startup(CompilationMode.Partial())

    @Test fun startupCompilationWarmup() = startup(CompilationMode.Partial(BaselineProfileMode.Disable, 2)) StartupBenchmarks.kt Compilation Mode None জ੉ ࢎ੹ ஹ౵ੌ غ૑ ঋ਺ (Worst Case) Full п জ੉ ৮੹൤ ࢎ੹ ஹ౵ੌ ؽ. (Ideal Case) Partial о੢ അप੸ੋ জ ࢸ஖ ജ҃
  25. StartupBenchmarks.kt private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated( packageName = PACKAGE_NAME,

    metrics = listOf(StartupTimingMetric()), iterations = 5, compilationMode = compilationMode, startupMode = StartupMode.COLD, setupBlock = { pressHome() } ) { startActivityAndWait() // wait for the content called by reportFullyDrawn is visible val recyclerHasChild = By.hasChild(By.res(packageName, "garden_list")) device.wait(Until.hasObject(recyclerHasChild), 5_000) }
  26. StartupBenchmarks.kt private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated( packageName = PACKAGE_NAME,

    metrics = listOf(StartupTimingMetric()), iterations = 5, compilationMode = compilationMode, startupMode = StartupMode.COLD, setupBlock = { pressHome() } ) { startActivityAndWait() // wait for the content called by reportFullyDrawn is visible val recyclerHasChild = By.hasChild(By.res(packageName, "garden_list")) device.wait(Until.hasObject(recyclerHasChild), 5_000) } Startup Mode Hot ݫݽܻী ੓ח Ѧ۽ Activity ׮द द੘ Warm ӝઓ ೐۽ࣁझ ղীࢲ Activityܳ ࢤࢿ द੘ Cold प೯ ઺੉ ইצ ೐۽ࣁझীࢲ द੘ ੹୓ ೐۽ࣁझ ୡӝച
  27. h tt ps://github.com/android/sun fl ower StartupBenchmarks_startupCompilationWarmup timeToFullDisplayMs min 185.4, median

    210.2, max 222.5 timeToInitialDisplayMs min 172.1, median 196.0, max 204.3 Traces: Iteration 0 1 2 3 4 StartupBenchmarks_startupCompilationPartial timeToFullDisplayMs min 197.5, median 208.5, max 265.6 timeToInitialDisplayMs min 185.8, median 196.1, max 246.4 Traces: Iteration 0 1 2 3 4 StartupBenchmarks_startupCompilationNone timeToFullDisplayMs min 296.1, median 302.1, max 317.3 timeToInitialDisplayMs min 280.6, median 284.4, max 296.9 Traces: Iteration 0 1 2 3 4 StartupTimingMetric Sunflower
  28. timeToInitialDisplayMs timeToFullDisplayMs Launch intent ࣻनೠ റ first frame ਸ Ӓܻחؘ

    ө૑੄ दр Launch intent ࣻनೠ റ android.app.Activity.reportFullyDrawn ө૑੄ दр StartupTimingMetric https://developer.android.com/studio/pro fi le/macrobenchmark-metrics
  29. PlantListBenchmarks.kt private fun openPlantList(compilationMode: CompilationMode) = benchmarkRule.measureRepeated( packageName = PACKAGE_NAME,

    metrics = listOf(FrameTimingMetric()), compilationMode = compilationMode, iterations = 5, startupMode = StartupMode.COLD, setupBlock = { pressHome() // Start the default activity, but don't measure the frames yet startActivityAndWait() } ) { goToPlantListTab() }
  30. frameOverrunMs frameDurationCpuMs Frame੉ ӝળࠁ׮ וܽ ੿ب CPUীࢲ ೐ۨ੐ਸ ࢤࢿೞחؘ Ѧܽ

    दр (UI thread, RenderThread ನೣ) FrameTimingMetric https://developer.android.com/studio/pro fi le/macrobenchmark-metrics + : Drop ػ Frame, Jank - : Deadlineࠁ׮ ঴݃ա ࡅܲ૑ Android 12+
  31. h tt ps://github.com/android/sun fl ower Sunflower FrameTimingMetric PlantListBenchmarks_plantListCompilationPartial frameDurationCpuMs P50

    6.5, P90 26.5, P95 50.3, P99 60.7 Traces: Iteration 0 1 2 3 4 PlantListBenchmarks_plantListCompilationFull frameDurationCpuMs P50 9.5, P90 32.7, P95 51.6, P99 63.2 Traces: Iteration 0 1 2 3 4 Timed out waiting for process (com.google.samples.apps.sunflower.macrobenchmark) to appear on lge- lm_v500n-LMV500N68592ec6. PlantListBenchmarks_openPlantList frameDurationCpuMs P50 22.2, P90 50.1, P95 82.1, P99 100.4 Traces: Iteration 0 1 2 3 4 LM-V500M(Android 11)
  32. h tt ps://github.com/android/sun fl ower Sunflower FrameTimingMetric PlantListBenchmarks_plantListCompilationFull frameDurationCpuMs P50

    16.3, P90 31.8, P95 35.8, P99 69.4 frameOverrunMs P50 1.9, P90 17.5, P95 20.5, P99 38.4 Traces: Iteration 0 1 2 3 4 PlantListBenchmarks_openPlantList frameDurationCpuMs P50 29.4, P90 56.5, P95 161.2, P99 178.6 frameOverrunMs P50 16.8, P90 41.8, P95 59.0, P99 181.8 Traces: Iteration 0 1 2 3 4 Google Pixel 3a(Android 12)
  33. పझ౟ ജ҃ ( ௏٘ա ٣߄੉झ झಖ ژח ীޯۨ੉ఠ )ী ٮۄ

    ׮ܲ ࣻ஖о աৢ ࣻ ੓ח ࠗ ࠙ੑפ׮. ٮۄࢲ ׮নೠ ജ҃ীࢲ ࣻ஖ܳ ࠺Ү೧ࠄ റী п੗੄ ӝળਸ ੿ೞҊ ѐࢶ ನੋ౟ ܳ ੟ইաоח ؘী ࢎਊೞݶ જਸ Ѫ эणפ׮. Q & A সؘ੉౟ ࣻ஖ܳ ࠅ ٸ.. https://developer.android.com/studio/pro fi le/baselinepro fi les
  34. API 23ө૑ ૑ਗ TraceSectionMetricਸ ࢎਊ೧ࢲ custom trace-based timing ஏ੿ ୶о

    AudioUnderrunMetricਵ۽ য়٣য় ӝ߈ х૑ ೲਊ ઱ ࢎਊ ҃۽(Critical workflows)ী ؀ೠ ೐۽೙ਸ ࢤࢿ - BaselineProfileRule ୶о Macrobenchmark https://www.youtube.com/watch?v=jTd82lcuHTU IO 22 What’s new in Jetpack
  35. https://developer.android.com/studio/pro fi le/jankstats class JankLoggingActivity : AppCompatActivity() { private lateinit

    var jankStats: JankStats override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... // metrics state holder can be retrieved regardless of JankStats initialization val metricsStateHolder = PerformanceMetricsState.getForHierarchy(binding.root) // initialize JankStats for current window jankStats = JankStats.createAndTrack( window, Dispatchers.Default.asExecutor(), jankFrameListener, ) // add activity name as state metricsStateHolder.state?.addState("Activity", javaClass.simpleName) // ... }JankLoggingActivity.kt
  36. class JankAggregatorActivity : AppCompatActivity() { private lateinit var jankStatsAggregator: JankStatsAggregator

    override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... // Metrics state holder can be retrieved regardless of JankStats initialization. val metricsStateHolder = PerformanceMetricsState.getForHierarchy(binding.root) // Initialize JankStats with an aggregator for the current window. jankStatsAggregator = JankStatsAggregator( window, Dispatchers.Default.asExecutor(), jankReportListener ) // Add the Activity name as state. metricsStateHolder.state?.addState("Activity", javaClass.simpleName) }JankAggregatorActivity.kt https://developer.android.com/studio/pro fi le/jankstats
  37. https://developer.android.com/studio/pro fi le/jankstats override fun onResume() { super.onResume() jankStatsAggregator.jankStats.isTrackingEnabled =

    true } override fun onPause() { super.onPause() // Before disabling tracking, issue the report with (optionally) specified reason. jankStatsAggregator.issueJankReport("Activity paused") jankStatsAggregator.jankStats.isTrackingEnabled = false }JankAggregatorActivity.kt
  38. https://developer.android.com/studio/pro fi le/jankstats *** Jank Report (Activity paused), totalFrames =

    170, jankFrames = 26 FrameData( frameStartNanos=257993674283620, // frame द੘ दр frameDurationUiNanos=77057961, //frame ૑ࣘ दр frameDurationCpuNanos=80083690, isJank=true, // Jank = അ੤ refresh rate ࠁ׮ ۪؊݂ೞח ؘ ف ߓо Ѧܻח frame states=[RecyclerView: Settling, Activity: JankAggregatorActivity] ) JankStatsAggregator ীࢲ ా೤ ੿ࠁ ઁҕ
  39. API ۨ߰ 16ө૑ ഐജ оמ ղࠗ ോܻझ౮ਸ ࢎਊೞৈ ࢿמ ޙઁ

    ध߹ ࢎਊ੗ ࢚క ߂ ੘সী ؀ೠ ࣘࢿ ؘ੉ఠী UI ஶఫझ౟ ઁҕ ܻझցܳ ా೧ ݽٚ ೐ۨ੐ী ؀ೠ Ѿҗ ࠁҊ JankStats https://www.youtube.com/watch?v=jTd82lcuHTU IO 22 What’s new in Jetpack
  40. Tracing stable androidx.tracing:tracing:1.1.0 System trace bufferী trace event ӝ۾ ٣ߡӒо

    ইצ ࠽٘ীࢲ ੿ഛೠ ੉߮౟ ୶੸ https://www.youtube.com/watch?v=jTd82lcuHTU IO 22 What’s new in Jetpack
  41. import androidx.tracing.trace; fun loadIcon() = trace(“Loading Icon”) { //... }

    https://www.youtube.com/watch?v=0adLO2VRJtc IO 21 Macrobenchmark۽ ߡߢѢܿ ߂ झఋ౟স ஏ੿
  42. Thank you! IO 22 What’s new in Jetpack IO 22

    What’s new in App Performanc e IO 21 Measuring Jank and Startup with Macrobenchmark Resources veronikapj GDG Korea Android PilJu BAE developer.android.com