Merge pull request #754 from android/tm/metrics-one-folder

Compose compiler metrics saved into one folder
pull/889/head
Don Turner 11 months ago committed by GitHub
commit 246200f163
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -154,8 +154,8 @@ Run the following command to get and analyse compose compiler metrics:
./gradlew assembleRelease -PenableComposeCompilerMetrics=true -PenableComposeCompilerReports=true ./gradlew assembleRelease -PenableComposeCompilerMetrics=true -PenableComposeCompilerReports=true
``` ```
The reports files will be added to build/compose-reports in each module. The metrics files will be The reports files will be added to [build/compose-reports](build/compose-reports). The metrics files will also be
added to build/compose-metrics in each module. added to [build/compose-metrics](build/compose-metrics).
For more information on Compose compiler metrics, see [this blog post](https://medium.com/androiddevelopers/jetpack-compose-stability-explained-79c10db270c8). For more information on Compose compiler metrics, see [this blog post](https://medium.com/androiddevelopers/jetpack-compose-stability-explained-79c10db270c8).

@ -16,10 +16,13 @@
package com.google.samples.apps.nowinandroid package com.google.samples.apps.nowinandroid
import androidx.test.uiautomator.BySelector
import androidx.test.uiautomator.Direction import androidx.test.uiautomator.Direction
import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiObject2 import androidx.test.uiautomator.UiObject2
import androidx.test.uiautomator.Until
import com.google.samples.apps.nowinandroid.benchmarks.BuildConfig import com.google.samples.apps.nowinandroid.benchmarks.BuildConfig
import java.io.ByteArrayOutputStream
/** /**
* Convenience parameter to use proper package name with regards to build type and build flavor. * Convenience parameter to use proper package name with regards to build type and build flavor.
@ -38,3 +41,24 @@ fun UiDevice.flingElementDownUp(element: UiObject2) {
waitForIdle() waitForIdle()
element.fling(Direction.UP) element.fling(Direction.UP)
} }
/**
* Waits until an object with [selector] if visible on screen and returns the object.
* If the element is not available in [timeout], throws [AssertionError]
*/
fun UiDevice.waitAndFindObject(selector: BySelector, timeout: Long): UiObject2 {
if (!wait(Until.hasObject(selector), timeout)) {
throw AssertionError("Element not found on screen in ${timeout}ms (selector=$selector)")
}
return findObject(selector)
}
/**
* Helper to dump window hierarchy into a string.
*/
fun UiDevice.dumpWindowHierarchy(): String {
val buffer = ByteArrayOutputStream()
dumpWindowHierarchy(buffer)
return buffer.toString()
}

@ -18,6 +18,7 @@ package com.google.samples.apps.nowinandroid.baselineprofile
import androidx.benchmark.macro.junit4.BaselineProfileRule import androidx.benchmark.macro.junit4.BaselineProfileRule
import com.google.samples.apps.nowinandroid.PACKAGE_NAME import com.google.samples.apps.nowinandroid.PACKAGE_NAME
import com.google.samples.apps.nowinandroid.allowNotifications
import com.google.samples.apps.nowinandroid.bookmarks.goToBookmarksScreen import com.google.samples.apps.nowinandroid.bookmarks.goToBookmarksScreen
import com.google.samples.apps.nowinandroid.foryou.forYouScrollFeedDownUp import com.google.samples.apps.nowinandroid.foryou.forYouScrollFeedDownUp
import com.google.samples.apps.nowinandroid.foryou.forYouSelectTopics import com.google.samples.apps.nowinandroid.foryou.forYouSelectTopics
@ -39,7 +40,7 @@ class BaselineProfileGenerator {
// This block defines the app's critical user journey. Here we are interested in // This block defines the app's critical user journey. Here we are interested in
// optimizing for app startup. But you can also navigate and scroll // optimizing for app startup. But you can also navigate and scroll
// through your most important UI. // through your most important UI.
allowNotifications()
pressHome() pressHome()
startActivityAndWait() startActivityAndWait()

@ -21,13 +21,14 @@ import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until import androidx.test.uiautomator.Until
import androidx.test.uiautomator.untilHasChildren import androidx.test.uiautomator.untilHasChildren
import com.google.samples.apps.nowinandroid.flingElementDownUp import com.google.samples.apps.nowinandroid.flingElementDownUp
import com.google.samples.apps.nowinandroid.waitAndFindObject
fun MacrobenchmarkScope.forYouWaitForContent() { fun MacrobenchmarkScope.forYouWaitForContent() {
// Wait until content is loaded by checking if topics are loaded // Wait until content is loaded by checking if topics are loaded
device.wait(Until.gone(By.res("loadingWheel")), 5_000) device.wait(Until.gone(By.res("loadingWheel")), 5_000)
// Sometimes, the loading wheel is gone, but the content is not loaded yet // Sometimes, the loading wheel is gone, but the content is not loaded yet
// So we'll wait here for topics to be sure // So we'll wait here for topics to be sure
val obj = device.findObject(By.res("forYou:topicSelection")) val obj = device.waitAndFindObject(By.res("forYou:topicSelection"), 10_000)
// Timeout here is quite big, because sometimes data loading takes a long time! // Timeout here is quite big, because sometimes data loading takes a long time!
obj.wait(untilHasChildren(), 60_000) obj.wait(untilHasChildren(), 60_000)
} }

@ -43,7 +43,7 @@ class ScrollForYouFeedBenchmark {
metrics = listOf(FrameTimingMetric()), metrics = listOf(FrameTimingMetric()),
compilationMode = compilationMode, compilationMode = compilationMode,
iterations = 10, iterations = 10,
startupMode = StartupMode.COLD, startupMode = StartupMode.WARM,
setupBlock = { setupBlock = {
// Start the app // Start the app
pressHome() pressHome()

@ -19,10 +19,7 @@ package com.google.samples.apps.nowinandroid.startup
import androidx.benchmark.macro.BaselineProfileMode.Disable import androidx.benchmark.macro.BaselineProfileMode.Disable
import androidx.benchmark.macro.BaselineProfileMode.Require import androidx.benchmark.macro.BaselineProfileMode.Require
import androidx.benchmark.macro.CompilationMode import androidx.benchmark.macro.CompilationMode
import androidx.benchmark.macro.StartupMode
import androidx.benchmark.macro.StartupMode.COLD import androidx.benchmark.macro.StartupMode.COLD
import androidx.benchmark.macro.StartupMode.HOT
import androidx.benchmark.macro.StartupMode.WARM
import androidx.benchmark.macro.StartupTimingMetric import androidx.benchmark.macro.StartupTimingMetric
import androidx.benchmark.macro.junit4.MacrobenchmarkRule import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner
@ -34,31 +31,12 @@ import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
/** /**
* Enables app startups from various states of baseline profile or [CompilationMode]s.
* Run this benchmark from Studio to see startup measurements, and captured system traces * Run this benchmark from Studio to see startup measurements, and captured system traces
* for investigating your app's performance from a cold state. * for investigating your app's performance from a cold state.
*/ */
@RunWith(AndroidJUnit4ClassRunner::class) @RunWith(AndroidJUnit4ClassRunner::class)
class ColdStartupBenchmark : AbstractStartupBenchmark(COLD) class StartupBenchmark {
/**
* Run this benchmark from Studio to see startup measurements, and captured system traces
* for investigating your app's performance from a warm state.
*/
@RunWith(AndroidJUnit4ClassRunner::class)
class WarmStartupBenchmark : AbstractStartupBenchmark(WARM)
/**
* Run this benchmark from Studio to see startup measurements, and captured system traces
* for investigating your app's performance from a hot state.
*/
@RunWith(AndroidJUnit4ClassRunner::class)
class HotStartupBenchmark : AbstractStartupBenchmark(HOT)
/**
* Base class for benchmarks with different startup modes.
* Enables app startups from various states of baseline profile or [CompilationMode]s.
*/
abstract class AbstractStartupBenchmark(private val startupMode: StartupMode) {
@get:Rule @get:Rule
val benchmarkRule = MacrobenchmarkRule() val benchmarkRule = MacrobenchmarkRule()
@ -81,9 +59,10 @@ abstract class AbstractStartupBenchmark(private val startupMode: StartupMode) {
metrics = listOf(StartupTimingMetric()), metrics = listOf(StartupTimingMetric()),
compilationMode = compilationMode, compilationMode = compilationMode,
iterations = 10, iterations = 10,
startupMode = startupMode, startupMode = COLD,
setupBlock = { setupBlock = {
pressHome() pressHome()
allowNotifications()
}, },
) { ) {
startActivityAndWait() startActivityAndWait()

@ -21,7 +21,6 @@ import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.withType import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.io.File
/** /**
* Configure Compose-specific options * Configure Compose-specific options
@ -55,9 +54,11 @@ internal fun Project.configureAndroidCompose(
private fun Project.buildComposeMetricsParameters(): List<String> { private fun Project.buildComposeMetricsParameters(): List<String> {
val metricParameters = mutableListOf<String>() val metricParameters = mutableListOf<String>()
val enableMetricsProvider = project.providers.gradleProperty("enableComposeCompilerMetrics") val enableMetricsProvider = project.providers.gradleProperty("enableComposeCompilerMetrics")
val relativePath = projectDir.relativeTo(rootDir)
val enableMetrics = (enableMetricsProvider.orNull == "true") val enableMetrics = (enableMetricsProvider.orNull == "true")
if (enableMetrics) { if (enableMetrics) {
val metricsFolder = File(project.buildDir, "compose-metrics") val metricsFolder = rootProject.buildDir.resolve("compose-metrics").resolve(relativePath)
metricParameters.add("-P") metricParameters.add("-P")
metricParameters.add( metricParameters.add(
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + metricsFolder.absolutePath "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + metricsFolder.absolutePath
@ -67,7 +68,7 @@ private fun Project.buildComposeMetricsParameters(): List<String> {
val enableReportsProvider = project.providers.gradleProperty("enableComposeCompilerReports") val enableReportsProvider = project.providers.gradleProperty("enableComposeCompilerReports")
val enableReports = (enableReportsProvider.orNull == "true") val enableReports = (enableReportsProvider.orNull == "true")
if (enableReports) { if (enableReports) {
val reportsFolder = File(project.buildDir, "compose-reports") val reportsFolder = rootProject.buildDir.resolve("compose-reports").resolve(relativePath)
metricParameters.add("-P") metricParameters.add("-P")
metricParameters.add( metricParameters.add(
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + reportsFolder.absolutePath "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + reportsFolder.absolutePath

Loading…
Cancel
Save