Configure Baseline Profile generation

The Baseline Profile Gradle plugin makes it easier to generate and maintain Baseline Profiles. It helps you do the following tasks:

This page explains how to use the Baseline Profile Gradle plugin to customize the generation of your Baseline Profiles.

Plugin requirements

Use a Gradle Managed Devices to generate Baseline Profiles

To use a Gradle Managed Device (GMD) to generate your Baseline Profile, add one in the build.gradle.kts configuration of the profile producer module—likely the :baselineprofile test module—as shown in the following example:

Kotlin

android {
   testOptions.managedDevices.devices {
       create<com.android.build.api.dsl.ManagedVirtualDevice>("pixel6Api31") {
           device = "Pixel 6"
           apiLevel = 31
           systemImageSource = "aosp"
       }
   }
}

Groovy

android {
   testOptions.managedDevices.devices {
       pixel6Api31(ManagedVirtualDevice) {
           device 'Pixel 6'
           apiLevel = 31
           systemImageSource 'aosp'
       }
   }
}

Use the GMD to generate Baseline Profiles by adding it to the Baseline Profile Gradle plugin configuration as follows, in the build.gradle.kts of the :baselineprofile test module:

Kotlin

baselineProfile {
    managedDevices += "pixel6Api31"
}

Groovy

baselineProfile {
    managedDevices = ['pixel6Api31']
}

When you use a GMD to generate Baseline Profiles, set useConnectedDevices to false, in your :baselineprofile test module:

Kotlin

baselineProfile {
    ...
    useConnectedDevices = false
}

Groovy

baselineProfile {
    ...
    useConnectedDevices false
}

Generate Baseline Profiles for different variants

You can generate Baseline Profiles per variant, per flavor, or as a single file to utilize for all variants. Control this behavior through the merge setting, as shown in the following example, in the build.gradle.kts of the application or library module.

Kotlin

baselineProfile {
    mergeIntoMain = true
}

Groovy

baselineProfile {
    mergeIntoMain true
}

To merge the generated profiles for all variants into a single profile, set mergeIntoMain to true. It isn't possible to generate per-variant Baseline Profiles when this setting is true, so there's a single Gradle task called generateBaselineProfile. The profile is output at src/main/generated/baselineProfiles.

To disable merging and have one profile per variant, set mergeIntoMain to false. In this case, multiple variant-specific Gradle tasks exist. For example, when there are two flavors—such as free and paid—and one release build type, the tasks are the following:

* `generateFreeReleaseBaselineProfile`
* `generatePaidReleaseBaselineProfile`
* `generateReleaseBaselineProfile`

To specify the merging behavior per variant, use the following code:

Kotlin

baselineProfile {
    variants {
        freeRelease {
            mergeIntoMain = true
        }
    }
}

Groovy

baselineProfile {
    variants {
        freeRelease {
            mergeIntoMain true
        }
    }
}

In the preceding example, the variants where the flag is set to true are all merged into src/main/generated/baselineProfiles, while the profiles for the variants where the flag is set to false are kept in the folder src/<variant>/generated/baselineProfiles.

By default, mergeIntoMain is set to true for libraries and false for apps.

Automatically generate Baseline Profiles when assembling a new release

You can configure Baseline Profiles to automatically generate with every release build, instead of manually using the task generateBaselineProfile. With automatic generation, the most updated profile is included in the release build.

To enable automatic generation for release builds, use the automaticGenerationDuringBuild flag:

Kotlin

baselineProfile {
    automaticGenerationDuringBuild = true
}

Groovy

baselineProfile {
    automaticGenerationDuringBuild true
}

Setting the automaticGenerationDuringBuild flag to true triggers the generation of a new Baseline Profile for each release assembly. This means that running an assemble release build task, such as ./gradlew:app:assembleRelease, also triggers :app:generateReleaseBaselineProfile, starts the Baseline Profile instrumentation tests, and builds the Baseline Profile build on which they run. While automatic generation helps users gain the best performance benefit, it also increases the build time because of the double build and instrumentation tests.

You can also specify this behavior per variant, as shown in the following example:

Kotlin

baselineProfile {
    variants {
        freeRelease {
            automaticGenerationDuringBuild = true
        }
    }
}

Groovy

baselineProfile {
    variants {
        freeRelease {
            automaticGenerationDuringBuild true
        }
    }
}

In the preceding example, the task generateFreeReleaseBaselineProfile runs when starting assembleFreeRelease. This helps when the user wants to have, for example, a release for distribution build that always generates the profile when building, and a releaseWithoutProfile build for internal testing.

Store Baseline Profiles into sources

You can store Baseline Profiles in the source directory through the saveInSrc flag in the build.gradle.kts of the application or library module:

  • true: the Baseline Profile is stored in src/<variant>/generated/baselineProfiles. This lets you commit the latest generated profile with your sources.
  • false: the Baseline Profile is stored in the intermediate files in the build directory. This way, when committing your code, you don't save the latest generated profile.

Kotlin

baselineProfile {
    saveInSrc = true
}

Groovy

baselineProfile {
    saveInSrc true
}

You can also specify this behavior per variant:

Kotlin

baselineProfile {
    variants {
        freeRelease {
            saveInSrc = true
        }
    }
}

Groovy

baselineProfile {
    variants {
        freeRelease {
            saveInSrc true
        }
    }
}

Filter profile rules

The Baseline Profile Gradle plugin lets you filter the Baseline Profile rules generated. This is particularly helpful for libraries, if you want to exclude profile rules for classes and methods that are part of other dependencies of the sample app or the library itself. The filters can include and exclude specific packages and classes. When you only specify excludes, only matching Baseline Profile rules are excluded and everything else is included.

The filters specification can be any of the following:

  • Package name ending with double wildcards to match the specified package and all subpackages. For example, com.example.** matches com.example.method and com.example.method.bar.
  • Package name ending with wildcard to match specified package only. For example, com.example.* matches com.example.method but doesn't match com.example.method.bar.
  • Class names to match a specific class—for example, com.example.MyClass.

The following examples show how to include and exclude specific packages:

Kotlin

baselineProfile {
    filter {
        include("com.somelibrary.widget.grid.**")
        exclude("com.somelibrary.widget.grid.debug.**")
        include("com.somelibrary.widget.list.**")
        exclude("com.somelibrary.widget.list.debug.**")
        include("com.somelibrary.widget.text.**")
        exclude("com.somelibrary.widget.text.debug.**")
    }
}

Groovy

baselineProfile {
    filter {
        include 'com.somelibrary.widget.grid.**'
        exclude 'com.somelibrary.widget.grid.debug.**'
        include 'com.somelibrary.widget.list.**'
        exclude 'com.somelibrary.widget.list.debug.**'
        include 'com.somelibrary.widget.text.**'
        exclude 'com.somelibrary.widget.text.debug.**'
    }
}

Customize the filter rules for different variants as follows:

Kotlin

// Non-specific filters applied to all the variants.
baselineProfile {
    filter { include("com.myapp.**") }
}

// Flavor-specific filters.
baselineProfile {
    variants {
        free {
            filter {
                include("com.myapp.free.**")
            }
        }
        paid {
            filter {
                include("com.myapp.paid.**")
            }
        }
    }
}

// Build-type-specific filters.
baselineProfile {
    variants {
        release {
            filter {
                include("com.myapp.**")
            }
        }
    }
}

// Variant-specific filters.
baselineProfile {
    variants {
        freeRelease {
            filter {
                include("com.myapp.**")
            }
        }
    }
}

Groovy

// Non-specific filters applied to all the variants.
baselineProfile {
    filter { include 'com.myapp.**' }
}

// Flavor-specific filters.
baselineProfile {
    variants {
        free {
            filter {
                include 'com.myapp.free.**'
            }
        }
        paid {
            filter {
                include 'com.myapp.paid.**'
            }
        }
    }
}

// Build-type specific filters.
baselineProfile {
    variants {
        release {
            filter {
                include 'com.myapp.**'
            }
        }
    }
}

// Variant-specific filters.
baselineProfile {
    variants {
        freeRelease {
            filter {
                include 'com.myapp.**'
            }
        }
    }
}

You can also filter rules using the filterPredicate argument in BaselineProfileRule.collect(), but we recommend using the Gradle plugin to filter because it provides a simpler way to filter subpackages and a single place to configure the entire module.

Customize benchmark and Baseline Profile build types

The Baseline Profile Gradle plugin creates additional build types to generate the profiles and to run benchmarks. These build types are prefixed with benchmark and nonMinified. For example, for the release build type, the plugin creates the benchmarkRelease and nonMinifiedRelease build types. These build types are automatically configured for the specific use case and don't generally need any customization. But there are some cases in which it might still be useful to apply some custom options, for example to apply a different signing config.

You can customize the automatically generated build types using a subset of build type properties; properties that aren't usable are overridden. The following example shows how to customize the additional build types and which properties are overridden:

Kotlin

android {
    buildTypes {
        release {
            ...
        }
        create("benchmarkRelease") {
            // Customize properties for the `benchmarkRelease` build type here.
            // For example, you can change the signing config (by default
            // it's the same as for the `release` build type).
            signingConfig = signingConfigs.getByName("benchmarkRelease")
        }
        create("nonMinifiedRelease") {
            // Customize properties for the `nonMinifiedRelease` build type here.
            signingConfig = signingConfigs.getByName("nonMinifiedRelease")

            // From Baseline Profile Gradle plugin 1.2.4 and higher, you can't
            // customize the following properties, which are always overridden to
            // avoid breaking Baseline Profile generation:
            //
            // isJniDebuggable = false
            // isDebuggable = false
            // isMinifyEnabled = false
            // isShrinkResources = false
            // isProfileable = true
            // enableAndroidTestCoverage = false
            // enableUnitTestCoverage = false
        }
    }
}

Groovy

android {
    buildTypes {
        release {
            ...
        }
        benchmarkRelease {
            // Customize properties for the `benchmarkRelease` build type here.
            // For example, you can change the signing config (by default it's the
            // same as for the `release` build type.)
            signingConfig = signingConfigs.benchmarkRelease
        }
        nonMinifiedRelease {
            // Customize properties for the `nonMinifiedRelease` build type here.
            signingConfig = signingConfigs.nonMinifiedRelease

            // From Baseline Profile Gradle plugin 1.2.4 and higher, you can't use
            // the following properties, which are always overridden to avoid breaking
            // Baseline Profile generation:
            //
            // isJniDebuggable = false
            // isDebuggable = false
            // isMinifyEnabled = false
            // isShrinkResources = false
            // isProfileable = true
            // enableAndroidTestCoverage = false
            // enableUnitTestCoverage = false       
        }
    }
}

Additional notes

When creating Baseline Profiles, here are some additional things to be aware of:

  • Compiled Baseline Profiles must be smaller than 1.5 MB. This doesn't apply to the text format in your source files, which are typically much larger prior to compilation. Verify the size of your binary Baseline Profile by locating it in the output artifact under assets/dexopt/baseline.prof for APK or BUNDLE-METADATA/com.android.tools.build.profiles/baseline.prof for AAB.

  • Broad rules that compile too much of the application can slow down startup due to increased disk access. If you're just starting with Baseline Profiles, don't worry about this. However, depending on your app and the size and number of journeys, adding a lot of journeys can result in suboptimal performance. Test the performance of your app by trying different profiles and verifying that the performance doesn't regress after the additions.

Codelabs

Dive into macrobenchmarking to measure performance.
Generate a custom Baseline Profile tailored to an Android app and verify its effectiveness.