编写宏基准测试

使用 Macrobenchmark 库来测试应用程序的更大用例,包括应用程序启动和复杂的 UI 操作,例如滚动 RecyclerView 或运行动画。如果您想测试代码的较小区域,请参考 微基准测试库。此页面展示了如何设置 Macrobenchmark 库。

该库将基准测试结果输出到 Android Studio 控制台和包含更多详细信息的 JSON 文件中。它还提供可以在 Android Studio 中加载和分析的跟踪文件。

在持续集成中进行基准测试 中所述,您可以在持续集成 (CI) 环境中使用 Macrobenchmark 库。

您可以使用 Macrobenchmark 来生成基线配置文件。首先,设置 Macrobenchmark 库,然后您可以 创建基线配置文件

项目设置

建议您将 Macrobenchmark 与最新版本的 Android Studio 配合使用,以利用 IDE 中与 Macrobenchmark 集成的功能。

设置 Macrobenchmark 模块

宏基准测试需要一个 com.android.test 模块(与您的应用程序代码分离),该模块负责运行测量您的应用程序的测试。

在 Android Studio 中,提供了一个模板来简化 Macrobenchmark 模块设置。基准测试模块模板会自动在您的项目中创建一个模块,用于测量应用程序模块构建的应用程序,包括一个示例启动基准测试。

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

  1. 在 Android Studio 的 **项目** 面板中右键单击您的项目或模块,然后选择 **新建 > 模块**。

  2. 从 **模板** 窗格中选择 **基准测试**。您可以自定义目标应用程序(即要进行基准测试的应用程序),以及新 Macrobenchmark 模块的包名和模块名。

  3. 单击 **完成**。

Benchmark Module
template

**图 1。** 基准测试模块模板。

设置应用程序

要对应用程序(称为 Macrobenchmark 的*目标*)进行基准测试,该应用程序必须是 profileable,这使得能够在不影响性能的情况下读取详细的跟踪信息。模块向导会自动将 <profileable> 标签添加到应用程序的 AndroidManifest.xml 文件中。

确保目标应用包含 ProfilerInstaller 1.3 或更高版本,Macrobenchmark 库需要此版本才能启用配置文件捕获和重置以及着色器缓存清除。

尽可能将基准测试应用配置为与发布版本或生产版本接近。将其设置为不可调试,最好开启缩小,这可以提高性能。通常,您可以通过创建发布变体的副本来完成此操作,该副本执行相同的操作,但使用调试密钥在本地签名。或者,您可以使用 initWith 指示 Gradle 为您完成此操作。

Kotlin

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

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

Groovy

buildTypes {
    getByName("release") {
        isMinifyEnabled = true
        isShrinkResources = true
        proguardFiles(
            getDefaultProguardFile("proguard-android-optimize.txt"),
            "proguard-rules.pro"
        )
        // In real app, this would use its own release keystore
        signingConfig = signingConfigs.getByName("debug")
    }
}

为了帮助确保运行基准测试既构建又测试了您的应用的正确变体,如您在图 2 中看到的那样,请执行以下操作。

  1. 执行 Gradle 同步。
  2. 打开 **构建变体** 面板。
  3. 选择应用和 Macrobenchmark 模块的基准测试变体。

Select benchmark
variant

**图 2.** 选择基准测试变体。

(可选) 设置多模块应用

如果您的应用包含多个 Gradle 模块,请确保您的构建脚本知道要编译哪个构建变体。在您的 :macrobenchmark:app 模块的 benchmark 构建类型中添加 matchingFallbacks 属性。您应用中的其他 Gradle 模块可以与以前保持相同的配置。

Kotlin

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

    matchingFallbacks += listOf("release")
 }

Groovy

benchmark {
    initWith buildTypes.release
    signingConfig signingConfigs.debug

    matchingFallbacks = ['release']
 }

如果没有此配置,新添加的 benchmark 构建类型会导致构建失败,并提供以下错误消息。

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

在您的项目中选择构建变体时,为 :app:macrobenchmark 模块选择 benchmark,为应用中的任何其他模块选择 release,如图 3 所示。

Benchmark variants for multi-module project with release and benchmark build
types
selected

**图 3.** 多模块项目中的基准测试变体,其中选择了 release 和 benchmark 构建类型。

有关更多信息,请参阅 使用变体感知的依赖项管理

(可选) 设置产品风格

如果您的应用中设置了多个产品风格,请配置 :macrobenchmark 模块,使其知道要构建和基准测试的应用产品风格。

本页中的示例使用 :app 模块中的两个产品风格:demoproduction,如下面的代码片段所示。

Kotlin

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

Groovy

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

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

如果没有此配置,您可能会遇到与多个 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:
           ...

以下两个部分介绍了在存在多个产品风格的情况下配置基准测试的方法。

使用 missingDimensionStrategy

:macrobenchmark 模块的 defaultConfig 中指定 missingDimensionStrategy 会告诉构建系统回退到风格维度。如果您在模块中找不到维度,请指定要使用的维度。在以下示例中,production 风格用作默认维度。

Kotlin

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

Groovy

defaultConfig {
    missingDimensionStrategy "environment", "production"
}

通过这种方式,:macrobenchmark 模块能够仅构建和基准测试指定的产品风格,这在您知道只有一个产品风格具有可供基准测试的正确配置时非常有用。

在 :macrobenchmark 模块中定义产品风格

如果您想构建和基准测试其他产品风格,请在 :macrobenchmark 模块中定义它们。与在 :app 模块中一样指定它,但仅将 productFlavors 分配给一个 dimension。不需要其他设置。

Kotlin

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

Groovy

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

    production {
        dimension 'environment'
    }
}

定义并同步项目后,从 **构建变体** 面板中选择相关的构建变体,如图 4 所示。

Benchmark variants for project with product flavors showing
productionBenchmark and release
selected

**图 4.** 项目中的基准测试变体,其中产品风格显示了已选中的 “productionBenchmark” 和 “release”。

有关更多信息,请参阅 解决与变体匹配相关的构建错误

创建 Macrobenchmark 类

基准测试通过 Macrobenchmark 库中的 JUnit4 规则 API MacrobenchmarkRule 提供。它包含一个 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 = DEFAULT_ITERATIONS,
        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 一样运行基准测试,使用测试类或方法旁边的代码行操作,如图 5 所示。

Run macrobenchmark with gutter action next to test
class

**图 5.** 使用测试类旁边的代码行操作运行 Macrobenchmark。

您还可以通过在命令行中执行 connectedCheck 命令来运行 Gradle 模块中的所有基准测试。

./gradlew :macrobenchmark:connectedCheck

您可以通过执行以下操作来运行单个测试。

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

有关如何在持续集成中运行和监控基准测试的信息,请参阅 在持续集成中进行基准测试

基准测试结果

基准测试成功运行后,指标将直接显示在 Android Studio 中,并将输出到 JSON 文件 中,以便 CI 使用。每次测量的迭代都会捕获单独的系统跟踪。您可以通过单击 **测试结果** 面板中的链接来打开这些跟踪结果,如图 6 所示。

Macrobenchmark startup
results

**图 6.** Macrobenchmark 启动结果。

加载跟踪后,Android Studio 会提示您选择要分析的进程。选择内容会预先填充目标应用进程,如图 7 所示。

Studio trace process
selection

**图 7.** Studio 跟踪进程选择。

加载跟踪文件后,Studio 会在 CPU 分析器工具 中显示结果。

Studio
Trace

**图 8.** 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 中打开它。这将显示上一节中显示的分析器工具视图。

配置错误

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

当尝试测量模拟器或在电池电量低的设备上进行测量时,Macrobenchmark 也会返回错误,这可能会影响核心可用性和时钟速度。

自定义基准测试

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

捕获指标

指标是从您的基准测试中提取的主要信息类型。以下指标可用。

有关指标的更多信息,请参阅 捕获 Macrobenchmark 指标

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

使用自定义跟踪事件来检测您的应用可能会有所帮助,这些事件会与跟踪报告的其余部分一起显示,并且可以帮助指出您的应用特有的问题。要了解有关创建自定义跟踪事件的更多信息,请参阅 定义自定义事件

CompilationMode

Macrobenchmark 可以指定 CompilationMode,它定义了应用中的多少代码必须从 DEX 字节码(APK 中的字节码格式)预编译为机器码(类似于预编译的 C++)。

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

如果目标应用包含基线配置文件和 ProfileInstaller 库,则可以安装基线配置文件。

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

此功能基于 ART 编译命令。每个基准测试在开始之前都会清除配置文件数据,以确保基准测试之间不会相互影响。

StartupMode

要执行活动启动,您可以传递预定义的启动模式:COLDWARMHOT。此参数会更改活动启动的方式以及测试开始时的进程状态。

要了解有关启动类型的更多信息,请参阅 应用启动时间

示例

GitHub 上的存储库中提供了 Macrobenchmark 示例 项目。

提供反馈

要报告 Jetpack Macrobenchmark 的问题或提交功能请求,请参阅 公共问题跟踪器