[go: nahoru, domu]

Fixed and added sample to compare full profile vs library only

Test: ./gradlew :benchmark:benchmark-baseline-profile-gradle-plugin:test
Bug: 266049500
Change-Id: I227bebd9b6bb5d53593557b15b11ba22ae06e09a
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
index 3138193..24946de 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPlugin.kt
@@ -362,6 +362,7 @@
                 library = isLibraryModule(),
                 sourceDir = mergeTaskProvider.flatMap { it.baselineProfileDir },
                 outputDir = project.provider { srcOutputDir },
+                hasDependencies = baselineProfileConfiguration.allDependencies.isNotEmpty(),
                 isLastTask = true,
                 warnings = baselineProfileExtension.warnings
             )
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/MergeBaselineProfileTask.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/MergeBaselineProfileTask.kt
index 4179410..c886ed9 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/MergeBaselineProfileTask.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/consumer/task/MergeBaselineProfileTask.kt
@@ -76,7 +76,7 @@
             project: Project,
             variantName: String,
             mergeAwareTaskName: String,
-            hasDependencies: Boolean = false,
+            hasDependencies: Boolean,
             library: Boolean,
             sourceProfilesFileCollection: FileCollection,
             outputDir: Provider<Directory>,
@@ -123,6 +123,8 @@
                         .set(warnings.noBaselineProfileRulesGenerated)
                     task.printWarningNoStartupProfileRulesGenerated
                         .set(warnings.noStartupProfileRulesGenerated)
+                    task.printWarningVariantHasNoBaselineProfileDependency
+                        .set(warnings.variantHasNoBaselineProfileDependency)
                 }
         }
 
@@ -134,6 +136,7 @@
             sourceDir: Provider<Directory>,
             outputDir: Provider<Directory>,
             isLastTask: Boolean,
+            hasDependencies: Boolean,
             warnings: Warnings
         ): TaskProvider<MergeBaselineProfileTask> {
             return project
@@ -150,10 +153,13 @@
                     task.library.set(library)
                     task.variantName.set(variantName)
                     task.lastTask.set(isLastTask)
+                    task.hasDependencies.set(hasDependencies)
                     task.printWarningNoBaselineProfileRulesGenerated
                         .set(warnings.noBaselineProfileRulesGenerated)
                     task.printWarningNoStartupProfileRulesGenerated
                         .set(warnings.noStartupProfileRulesGenerated)
+                    task.printWarningVariantHasNoBaselineProfileDependency
+                        .set(warnings.variantHasNoBaselineProfileDependency)
                 }
         }
     }
@@ -187,19 +193,46 @@
     @get:Input
     abstract val printWarningNoStartupProfileRulesGenerated: Property<Boolean>
 
+    @get:Input
+    abstract val printWarningVariantHasNoBaselineProfileDependency: Property<Boolean>
+
     private val logger by lazy { BaselineProfilePluginLogger(this.getLogger()) }
 
+    private val variantHasDependencies by lazy {
+        hasDependencies.isPresent && hasDependencies.get()
+    }
+
     @TaskAction
     fun exec() {
 
-        if (hasDependencies.isPresent && !hasDependencies.get()) {
-            throw GradleException(
-                """
+        // This warning should be printed only if no dependency has been set for the processed
+        // variant.
+        if (lastTask.get() && !variantHasDependencies) {
+            logger.warn(
+                property = { printWarningVariantHasNoBaselineProfileDependency.get() },
+                propertyName = "variantHasNoBaselineProfileDependency",
+                message = """
                 The baseline profile consumer plugin is applied to this module but no dependency
-                has been set. Please review the configuration of build.gradle for this module
-                making sure that a `baselineProfile` dependency exists and points to a valid
-                `com.android.test` module that has the `androidx.baselineprofile` or
-                `androidx.baselineprofile.producer` plugin applied.
+                has been set for variant `${variantName.get()}`, so no baseline profile will be 
+                generated for it.
+
+                A dependency for all the variants can be added in the dependency block using
+                `baselineProfile` configuration:
+
+                dependencies {
+                    ...
+                    baselineProfile(project(":baselineprofile"))
+                }
+
+                Or for a specific variant in the baseline profile block:
+
+                baselineProfile {
+                    variants {
+                        freeRelease {
+                            from(project(":baselineprofile"))
+                        }
+                    }
+                }
                 """.trimIndent()
             )
         }
@@ -217,13 +250,15 @@
 
         // Read the profile rules from the file collection that contains the profile artifacts from
         // all the configurations for this variant and merge them in a single list.
-        val profileRules = baselineProfileFileCollection.files
+        val baselineProfileRules = baselineProfileFileCollection.files
             .readLines {
                 FILENAME_MATCHER_BASELINE_PROFILE in it.name ||
                     FILENAME_MATCHER_STARTUP_PROFILE in it.name
             }
 
-        if (variantName.isPresent && profileRules.isEmpty()) {
+        // This warning should be printed only if the variant has dependencies but there are no
+        // baseline profile rules.
+        if (lastTask.get() && variantHasDependencies && baselineProfileRules.isEmpty()) {
             logger.warn(
                 property = { printWarningNoBaselineProfileRulesGenerated.get() },
                 propertyName = "noBaselineProfileRulesGenerated",
@@ -242,7 +277,7 @@
         // - group by class and method (ignoring flag) and for each group keep only the first value
         // - apply the filters
         // - sort with comparator
-        val filteredBaselineProfileRules = profileRules
+        val filteredBaselineProfileRules = baselineProfileRules
             .sorted()
             .asSequence()
             .mapNotNull { ProfileRule.parse(it) }
@@ -267,9 +302,10 @@
             .sortedWith(ProfileRule.comparator)
 
         // Check if the filters filtered out all the rules.
-        if (profileRules.isNotEmpty() &&
+        if (baselineProfileRules.isNotEmpty() &&
             filteredBaselineProfileRules.isEmpty() &&
-            rules.isNotEmpty()) {
+            rules.isNotEmpty()
+        ) {
             throw GradleException(
                 """
                 The baseline profile consumer plugin is configured with filters that exclude all
@@ -294,7 +330,9 @@
         val startupRules = baselineProfileFileCollection.files
             .readLines { FILENAME_MATCHER_STARTUP_PROFILE in it.name }
 
-        if (variantName.isPresent && startupRules.isEmpty()) {
+        // This warning should be printed only if the variant has dependencies but there are no
+        // startup profile rules.
+        if (lastTask.get() && variantHasDependencies && startupRules.isEmpty()) {
             logger.warn(
                 property = { printWarningNoStartupProfileRulesGenerated.get() },
                 propertyName = "noBaselineProfileRulesGenerated",
diff --git a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/WarningsExtension.kt b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/WarningsExtension.kt
index 6caa86a..d9cd3d2 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/WarningsExtension.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/main/kotlin/androidx/baselineprofile/gradle/utils/WarningsExtension.kt
@@ -74,4 +74,10 @@
      * the generate baseline profile command.
      */
     var noStartupProfileRulesGenerated = true
+
+    /**
+     * Controls the warning printed when a variant has no baseline profile dependency set,
+     * either globally or a specific one.
+     */
+    var variantHasNoBaselineProfileDependency = true
 }
diff --git a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
index 589cad5d..aefa4be 100644
--- a/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
+++ b/benchmark/baseline-profile-gradle-plugin/src/test/kotlin/androidx/baselineprofile/gradle/consumer/BaselineProfileConsumerPluginTest.kt
@@ -386,18 +386,12 @@
             flavors = false,
             dependencyOnProducerProject = false
         )
-
-        gradleRunner
-            .withArguments("generateReleaseBaselineProfile", "--stacktrace")
-            .buildAndFail()
-            .output
-            .replace("\n", " ")
-            .also {
-                assertThat(it).contains(
-                    "The baseline profile consumer plugin is applied to " +
-                        "this module but no dependency has been set"
-                )
-            }
+        gradleRunner.build("generateReleaseBaselineProfile", "--stacktrace") {
+            assertThat(it.replace("\n", " ")).contains(
+                "The baseline profile consumer plugin is applied to this module but no " +
+                    "dependency has been set for variant `release`"
+            )
+        }
     }
 
     @Test
diff --git a/benchmark/integration-tests/baselineprofile-consumer/build.gradle b/benchmark/integration-tests/baselineprofile-consumer/build.gradle
index c98970f..e8760c8 100644
--- a/benchmark/integration-tests/baselineprofile-consumer/build.gradle
+++ b/benchmark/integration-tests/baselineprofile-consumer/build.gradle
@@ -33,12 +33,22 @@
 }
 
 android {
+    sourceSets {
+        // This is required because of release variant specific code used by hilt.
+        releaseLibrariesOnly {
+            java.srcDirs += "src/release/"
+        }
+    }
     buildTypes {
         release {
             minifyEnabled true
             shrinkResources true
             proguardFiles getDefaultProguardFile("proguard-android-optimize.txt")
         }
+        releaseLibrariesOnly {
+            initWith(release)
+            matchingFallbacks += "release"
+        }
     }
     namespace "androidx.benchmark.integration.baselineprofile.consumer"
 }
@@ -49,7 +59,6 @@
     implementation(libs.hiltAndroid)
     kapt(libs.hiltCompiler)
     implementation(project(":profileinstaller:profileinstaller"))
-    baselineProfile(project(":benchmark:integration-tests:baselineprofile-producer"))
 }
 
 baselineProfile {
@@ -58,6 +67,15 @@
     // trigger baseline profile generation and integration tests on device.
     saveInSrc = true
     automaticGenerationDuringBuild = false
+
+    variants {
+        release {
+            from(project(":benchmark:integration-tests:baselineprofile-producer"))
+        }
+        releaseLibrariesOnly {
+            // No dependency set
+        }
+    }
 }
 
 apply(from: "../baselineprofile-test-utils/utils.gradle")
diff --git a/benchmark/integration-tests/baselineprofile-producer/build.gradle b/benchmark/integration-tests/baselineprofile-producer/build.gradle
index 0f1243c..3a320b1 100644
--- a/benchmark/integration-tests/baselineprofile-producer/build.gradle
+++ b/benchmark/integration-tests/baselineprofile-producer/build.gradle
@@ -32,7 +32,7 @@
 
 android {
     defaultConfig {
-        minSdkVersion 23
+        minSdkVersion 24
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
     testOptions.managedDevices.devices {
@@ -42,6 +42,10 @@
             systemImageSource = "aosp"
         }
     }
+    buildTypes {
+        release { }
+        releaseLibrariesOnly { }
+    }
     targetProjectPath = ":benchmark:integration-tests:baselineprofile-consumer"
     namespace "androidx.benchmark.integration.baselineprofile.producer"
 }
diff --git a/benchmark/integration-tests/baselineprofile-producer/src/main/java/androidx/benchmark/integration/baselineprofile/producer/StartupBenchmarks.kt b/benchmark/integration-tests/baselineprofile-producer/src/main/java/androidx/benchmark/integration/baselineprofile/producer/StartupBenchmarks.kt
new file mode 100644
index 0000000..a1e44eb
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofile-producer/src/main/java/androidx/benchmark/integration/baselineprofile/producer/StartupBenchmarks.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.benchmark.integration.baselineprofile.producer
+
+import android.content.Intent
+import androidx.benchmark.macro.BaselineProfileMode
+import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.StartupMode
+import androidx.benchmark.macro.StartupTimingMetric
+import androidx.benchmark.macro.junit4.MacrobenchmarkRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+class StartupBenchmarks {
+
+    @get:Rule
+    val rule = MacrobenchmarkRule()
+
+    @Test
+    fun startupCompilationBaselineProfiles() =
+        benchmark(CompilationMode.Partial(BaselineProfileMode.Require))
+
+    private fun benchmark(compilationMode: CompilationMode) = rule.measureRepeated(
+        packageName = PACKAGE_NAME,
+        metrics = listOf(StartupTimingMetric()),
+        compilationMode = compilationMode,
+        startupMode = StartupMode.COLD,
+        iterations = 10,
+        setupBlock = { pressHome() },
+        measureBlock = { startActivityAndWait(Intent(ACTION)) }
+    )
+
+    companion object {
+        private const val PACKAGE_NAME =
+            "androidx.benchmark.integration.baselineprofile.consumer"
+        private const val ACTION =
+            "androidx.benchmark.integration.baselineprofile.consumer.EMPTY_ACTIVITY"
+    }
+}