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"
+ }
+}