编写 Macrobenchmark

使用 Macrobenchmark 库测试应用的更大用例,包括应用启动和复杂的 UI 操作,例如滚动 RecyclerView 或运行动画。如果您想测试代码的较小区域,请参阅 Microbenchmark 库。此页面介绍如何设置 Macrobenchmark 库。

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

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

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

项目设置

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

设置 Macrobenchmark 模块

Macrobenchmark 需要一个 com.android.test 模块(与您的应用代码分开),该模块负责运行测量应用的测试。

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

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

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

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

  3. 点击Finish

Benchmark Module
template

图 1. Benchmark 模块模板。

设置应用

要对应用进行基准测试(称为 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. 打开**Build Variants** 面板。
  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. 具有选定的发布和基准测试构建类型的多模块项目的基准测试变体。

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

(可选) 设置产品风格

如果您的应用中设置了多个产品风格,请配置: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'
    }
}

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

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

图 4. 显示已选择“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 = 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 使用。每次测量的迭代都会捕获单独的系统跟踪。您可以通过点击**Test Results**面板中的链接打开这些跟踪结果,如图 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.NoneCompilationMode.Ignore

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

StartupMode

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

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

示例

GitHub 上的存储库中提供了示例项目,请参阅Macrobenchmark 示例

提供反馈

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