编写微基准

Macrobenchmark 库适用于测试应用的较大用例,包括应用启动和复杂的界面操作,例如滚动 RecyclerView 或运行动画。如果您希望测试较小的代码区域,请参阅 Microbenchmark 库

该库会将基准化分析结果的更多详细信息输出到 Android Studio 控制台和 JSON 文件。此外,它还提供跟踪文件,您可以在 Android Studio 中加载和分析这些文件。

在持续集成 (CI) 环境中使用 Macrobenchmark 库,如在持续集成环境中运行基准所述。

您可以使用 Macrobenchmark 生成基准配置文件。请按照以下指南设置 Marcobenchmark 库,然后创建基准配置文件

项目设置

我们建议您将 Macrobenchmark 与最新版本的 Android Studio 搭配使用,因为该版本的 Android Studio 中提供了可与 Macrobenchmark 集成的新功能。

设置 Macrobenchmark 模块

宏基准需要一个独立于应用代码的 com.android.test 模块来负责运行衡量应用的测试。

在 Android Studio 中,我们提供了一个模板来简化 Macrobenchmark 模块设置。基准化分析模块模板会自动在项目中创建一个模块(包含一个示例启动基准),用于衡量通过应用模块构建的应用。

如需使用模块模板创建新模块,请执行以下操作:

  1. 在 Android Studio 的 Project 面板中右键点击您的项目或模块,然后依次点击 New > Module

  2. Templates 窗格中选择 Benchmark

  3. 您可以自定义目标应用(要进行基准测试的应用),以及新的 Macrobenchmark 模块的软件包和模块名称。

  4. 点击 Finish

基准模块模板

设置应用

若要对应用(称为该宏基准的目标)进行基准测试,该应用必须 profileable,这样系统才能读取详细的跟踪信息,而不会影响性能。模块向导会自动将 <profileable> 标记添加到应用的 AndroidManifest.xml 文件中。

尽可能将进行基准测试的应用配置为接近发布版本(或正式版)。将其设置为不可调试,最好开启“缩减大小”功能,以提高性能。通常,您可以通过创建发布变体的副本来实现此目的,该副本会执行同样的操作,但使用调试密钥在本地签名。或者,您也可以使用 initWith 指示 Gradle 为您执行此操作:

Groovy

buildTypes {
    release {
        minifyEnabled true
        shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }

    benchmark {
        initWith buildTypes.release
        signingConfig signingConfigs.debug
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'benchmark-rules.pro'
    }
}

Kotlin

buildTypes {
    getByName("release") {
        isMinifyEnabled = true
        isShrinkResources = true
        proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"))
    }

    create("benchmark") {
        initWith(getByName("release"))
        signingConfig = signingConfigs.getByName("debug")
    }
}

执行 Gradle 同步,打开左侧的 Build Variants 面板,然后选择应用和 Macrobenchmark 模块的要进行基准测试的变体。这可确保运行基准的操作将会构建并测试应用的正确变体:

选择要进行基准测试的变体

(可选)设置多模块应用

如果您的应用有多个 Gradle 模块,您需要确保 build 脚本知道要编译哪个 build 变体。如果缺少这项设置,新添加的 benchmark buildType 会导致构建失败,并提供以下错误消息:

> Could not resolve project :shared.
     Required by:
         project :app
      > No matching variant of project :shared was found.
      ...

您可以通过将 matchingFallbacks 属性添加到 :macrobenchmark:app 模块的 benchmark buildType 中来解决此问题。其余 Gradle 模块可以具有与之前相同的配置。

Groovy

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
}

Kotlin

create("benchmark") {
    initWith(getByName("release"))
    signingConfig = signingConfigs.getByName("debug")

    matchingFallbacks += listOf('release')
}

在项目中选择 build 变体时,请为 :app:macrobenchmark 模块选择 benchmark,为应用中的任何其他模块选择 release,如下图所示:

选择了 release 和 benchmark buildType 的多模块项目的基准变体

如需了解详情,请查看变体感知型依赖项管理

(可选)设置产品变种

如果您的应用中设置了多个产品变种,则需要配置 :macrobenchmark 模块,使其了解要构建应用的哪个产品变种并对其进行基准测试。如果不进行此配置,您可能会收到与使用多个 Gradle 模块时类似的构建错误:

Could not determine the dependencies of task ':macrobenchmark:connectedBenchmarkAndroidTest'.
> Could not determine the dependencies of null.
   > Could not resolve all task dependencies for configuration ':macrobenchmark:benchmarkTestedApks'.
      > Could not resolve project :app.
        Required by:
            project :macrobenchmark
         > The consumer was configured to find a runtime of a component, as well as attribute 'com.android.build.api.attributes.BuildTypeAttr' with value 'benchmark', attribute 'com.android.build.api.attributes.AgpVersionAttr' with value '7.3.0'. However we cannot choose between the following variants of project :app:
             - demoBenchmarkRuntimeElements
             - productionBenchmarkRuntimeElements
           All of them match the consumer attributes:
           ...

在本指南中,我们将在 :app 模块中使用以下两个产品变种:demoproduction,如以下代码段所示:

Groovy

flavorDimensions 'environment'
productFlavors {
    demo {
        dimension 'environment'
        // ...
    }

    production {
        dimension 'environment'
        // ...
    }
}

Kotlin

flavorDimensions += "environment"
productFlavors {
    create("demo") {
        dimension = "environment"
        // ...
    }
    create("production") {
        dimension = "environment"
        // ...
    }
}

您可以通过以下两种方式配置具有多个产品变种的基准测试:

使用“missingDimensionStrategy

:macrobenchmark 模块的 defaultConfig 中指定 missingDimensionStrategy 会指示构建系统回退到相应变种维度。如果模块中找不到要使用的维度,您需要指定相应维度。以下示例中使用 production 变种作为默认维度:

Groovy

defaultConfig {
    missingDimensionStrategy "environment", "production"
}

Kotlin

defaultConfig {
    missingDimensionStrategy("environment", "production")
}

这样一来,:macrobenchmark 就能只构建指定的产品变种并对其进行基准测试;如果您知道只有一个产品变种具有要进行基准测试的正确配置,这会很有用。

:macrobenchmark 模块中定义产品变种

如果您想构建其他产品变种并对其进行基准测试,需要在 :macrobenchmark 模块中定义它们。请以与 :app 模块中类似的方式进行指定,但仅将 productFlavors 分配给 dimension,而无需进行其他设置:

Groovy

flavorDimensions 'environment'
productFlavors {
    demo {
        dimension 'environment'
    }

    production {
        dimension 'environment'
    }
}

Kotlin

flavorDimensions += "environment"
productFlavors {
    create("demo") {
        dimension = "environment"
    }
    create("production") {
        dimension = "environment"
    }
}

定义并同步项目后,从 Build Variants 窗格中选择所需的构建变体:

显示选择了 productionBenchmark 和 release 的具有产品变种的项目的基准变体

如需了解详情,请参阅解决与变体匹配相关的构建错误

创建 Macrobenchmark 类

基准测试通过 Macrobenchmark 库中的 MacrobenchmarkRule JUnit4 规则 API 提供。它包含 measureRepeated 方法,可让您指定各种有关如何运行目标应用并对其进行基准测试的条件。

您至少需要指定目标应用的 packageName、您要衡量的 metrics 以及基准应该运行的 iterations 次数。

Kotlin

@LargeTest
@RunWith(AndroidJUnit4::class)
class SampleStartupBenchmark {
    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()

    @Test
    fun startup() = benchmarkRule.measureRepeated(
        packageName = TARGET_PACKAGE,
        metrics = listOf(StartupTimingMetric()),
        iterations = 5,
        setupBlock = {
            // Press home button before each run to ensure the starting activity isn't visible.
            pressHome()
        }
    ) {
        // starts default launch activity
        startActivityAndWait()
    }
}

Java

@LargeTest
@RunWith(AndroidJUnit4.class)
public class SampleStartupBenchmark {
    @Rule
    public MacrobenchmarkRule benchmarkRule = new MacrobenchmarkRule();

    @Test
    public void startup() {
        benchmarkRule.measureRepeated(
            /* packageName */ TARGET_PACKAGE,
            /* metrics */ Arrays.asList(new StartupTimingMetric()),
            /* iterations */ 5,
            /* measureBlock */ scope -> {
                // starts default launch activity
                scope.startActivityAndWait();
                return Unit.INSTANCE;
            }
        );
    }
}

如需有关如何自定义基准的所有选项,请参阅自定义基准部分。

运行基准

在 Android Studio 中运行测试,以衡量应用在设备上的性能。您可以像使用测试类或方法旁边的边线操作运行任何其他 @Test 一样运行基准,如下图所示。

使用测试类旁边的边线操作运行微基准

您也可以执行 connectedCheck 命令,从命令行运行 Gradle 模块中的所有基准:

./gradlew :macrobenchmark:connectedCheck

或者,运行单个测试:

./gradlew :macrobenchmark:connectedCheck -P android.testInstrumentationRunnerArguments.class=com.example.macrobenchmark.startup.SampleStartupBenchmark#startup

如需了解如何在持续集成环境中运行和监控基准,请参阅在持续集成环境中运行基准部分。

基准结果

基准运行成功后,指标会直接显示在 Android Studio 中,还会以 JSON 文件形式输出以供集成环境使用。每次衡量的迭代过程均会捕获单独的系统跟踪文件。点击 Test Results 窗格中的其中一个链接,可以打开这些结果跟踪文件,如下图所示。

Macrobenchmark 启动结果

跟踪文件加载完成后,Android Studio 会提示您选择要分析的进程。系统会预先填充目标应用进程:

Studio 跟踪进程选择界面

跟踪文件加载完成后,Studio 将在 CPU 性能剖析器工具中显示结果:

Studio 跟踪界面

JSON 报告和所有性能分析轨迹也会从设备自动复制到主机。这些数据将写入主机上的以下位置:

project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/

手动访问跟踪文件

如果要使用 Perfetto 工具分析跟踪文件,还需要执行几个额外的步骤。您可以使用 Perfetto 检查跟踪期间整个设备上发生的所有进程,而 Android Studio 的 CPU 性能分析器只能检查单个进程。

如果您从 Android Studio 或使用 Gradle 命令行调用测试,系统会自动将跟踪文件从设备复制到主机。这些报告将写入主机上的以下位置:

project_root/module/build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/device_id/TrivialStartupBenchmark_startup[mode=COLD]_iter002.perfetto-trace

将跟踪文件复制到主机系统后,您可以在 Android Studio 中通过依次点击 File > Open 菜单打开此跟踪文件。此时系统会显示上一部分中显示的性能分析器工具视图。

配置错误

如果应用配置有误(可调试或不可分析),微基准就会返回错误,而不会报告不正确或不完整的衡量结果。您可以使用 androidx.benchmark.suppressErrors 参数抑制这些错误。

如果尝试衡量模拟器,或在电量不足的设备上进行衡量,系统也会抛出错误,因为这些情况可能会影响核心可用性和时钟速度。

自定义基准

measureRepeated 函数接受各种参数,这些参数会影响库收集的指标、应用的启动和编译方式或基准将运行的迭代次数。

捕获指标

指标是从基准中提取的主要信息类型。可用选项包括 StartupTimingMetricFrameTimingMetricTraceSectionMetric。如需详细了解这些选项,请参阅捕获指标页面。

利用自定义事件改进跟踪数据

利用自定义跟踪事件进行应用插桩非常有用,这些事件会与跟踪报告的其余部分一起显示,有助于找出应用特有的问题。如需详细了解如何创建自定义跟踪事件,请参阅定义自定义事件指南。

CompilationMode

宏基准可以指定 CompilationMode,用于定义应该将应用的多大部分从 DEX 字节码(APK 中的字节码格式)预编译为机器代码(类似于预编译的 C++)。

默认情况下,系统会使用 CompilationMode.DEFAULT 运行宏基准,这会在 Android 7(API 级别 24)及更高版本上安装基准配置文件(如果有)。如果您使用的是 Android 6(API 级别 23)或更低版本,编译模式会将 APK 完全编译为默认系统行为。

如果目标应用同时包含基准配置文件和 ProfileInstaller 库,您可以安装基准配置文件。

在 Android 7 及更高版本中,您可以自定义 CompilationMode 以影响设备上的预编译量,从而模拟不同级别的预先 (AOT) 编译或 JIT 缓存。请参阅 CompilationMode.FullCompilationMode.PartialCompilationMode.None

此功能基于 ART 编译命令构建而成。每次基准测试都会在开始之前清除分析数据,确保基准测试之间互不干扰。

StartupMode

如需执行 activity 启动,您可以传递一种预定义的启动模式(COLDWARMHOT 中的一种)。此参数会更改 activity 的启动方式,以及测试开始时的进程状态。

如需详细了解启动类型,请参阅 Android Vitals 启动文档

示例

GitHub 上提供了一个示例项目,该项目位于 android/performance-samples 代码库中。

提供反馈

如需针对 Jetpack Macrobenchmark 报告问题或提交功能请求,请参阅公开问题跟踪器