Flutter性能测试插件benchmark_runner的使用

发布于 1周前 作者 h691938207 来自 Flutter

Flutter性能测试插件benchmark_runner的使用

Benchmark Runner

Benchmark Runner 是一个基于 benchmark_harness 的的包,它提供了编写 inline 微基准的辅助函数。这些函数可以打印分数直方图、报告分数均值 ± 标准差以及分数中位数 ± 四分位距。

使用说明

  1. benchmark_runner 添加为 dev_dependency 在你的 pubspec.yaml 文件中。
  2. 使用以下函数编写 inline 基准:
    • benchmark: 创建并运行同步基准,并报告基准分数。
    • asyncBenchmark: 创建并运行异步基准。
    • group: 用于标记一组基准。回调 body 通常包含一个或多个对 benchmarkasyncBenchmark 的调用。基准组不能嵌套。

文件必须以 _benchmark.dart 结尾,以便被 benchmark_runner 检测到。

示例代码

// ignore_for_file: unused_local_variable

import 'package:benchmark_runner/benchmark_runner.dart';

/// 返回经过等待 [duration] 后的值 [t ]。
Future<T> later<T>(T t, [Duration duration = Duration.zero]) {
  return Future.delayed(duration, () => t);
}

void main(List<String> args) async {
  await group('Wait for duration', () async {
    await asyncBenchmark('10ms', () async {
      await later<int>(39, Duration(milliseconds: 10));
    });

    await asyncBenchmark('5ms', () async {
      await later<int>(27, Duration(milliseconds: 5));
    }, emitStats: false);
  });

  group('Set', () async {
    await asyncBenchmark('error test', () {
      throw ('Thrown in benchmark.');
    });

    benchmark('construct', () {
      final set = {for (var i = 0; i < 1000; ++i) i;
    });

    throw 'Error in group';
  });
}

运行单个基准文件

单个基准文件可以通过 Dart 可执行文件运行: Console Output Single

默认情况下,benchmarkasyncBenchmark 函数会输出基准分数统计信息。

使用 Benchmark Runner

要运行多个基准文件(格式为 _benchmark.dart),并生成报告,请调用子命令 report 并指定目录。如果没有指定目录,则默认为 benchmark

Runner Report

典型的控制台输出如上所示。在这个例子中,benchmark_runner 检测到了两个基准文件,运行了微基准并生成了报告。

  • 总计显示完成的基准数量、有错误的基准数量和不在基准函数作用域内的错误组的数量。
  • 使用选项 -v--verbose 可以显示每个错误的堆栈跟踪。
  • 总的基准运行时间可能比所有微基准运行时间之和短,因为每个可执行的基准文件会在单独的进程中运行。

导出基准分数

要导出基准分数,请使用子命令 export

$ dart run benchmark_runner export --outputDir=scores --extension=csv searchDirectory

在上述示例中,searchDirectory 会被扫描以查找 _benchmark.dart 文件。对于每个基准文件,都会创建一个对应的 CSV 文件 *_benchmark.csv 写入到目录 scores 中。目录必须存在且用户需要具有写权限。

注意:当将基准分数导出到文件时,并且发射器输出是彩色化的,建议使用选项 --isMonochrome 来避免由于使用 ANSI 修改符而导致的伪字符。

自版本 1.0.0 起,benchmarkasyncBenchmark 函数接受可选参数 emitterreport。这些参数可以用来自定义分数报告,例如使分数格式更适合写入文件:

import 'package:benchmark_runner/benchmark_runner.dart';

class CustomEmitter extends ColorPrintEmitter {
  void emitMean({required Score score}) {
    print('# Mean               Standard Deviation');
    print('${score.stats.mean}  ${score.stats.stdDev}');
  }
}

void main(){
  benchmark(
      'construct list | use custom emitter',
      () {
        var list = <int>[for (var i = 0; i < 1 1000; ++i) i];
      },
      emitter: CustomEmitter(),
      report: (instance, emitter ) >> emitter.emitMean(
        score: instance.score(),
      ),
    );
}

提示与技巧

  1. 所有的分数报告由 benchmarkasyncBenchmark 函数指的是单次运行的基准函数。
  2. 基准不需要被包围在一个组内。
  3. 一个基准组不能包含另一个基准组。
  4. 程序不检查组描述和 基准描述的冲突。可以使用第二个基准名称来比较标准分数,例如通过 benchmark_harness 报告的标准分数。
  5. 默认情况下,benchmarkasyncBenchmark 函数会报告分数统计信息。为了生成 benchmark_harness 提供的报告,请使用可选参数 report: reportMean
  6. 关闭颜色输出可以通过使用选项 --isMonochrome--m 来实现。当执行单个基准文件时,相应的选项是 --define=isMonochrome=true
  7. 默认使用的颜色最适合深色终端背景。它们可以通过设置类 ColorProfile 定义的静态变量来更改。在下面的例子中,错误消息和均值的样式被更改。
  8. 当运行异步基准时,分数按完成顺序打印。如果按照基准文件中的顺序打印分数,需要先 await 异步基准函数和包含该组的外部组的完成。

分数采样

为了计算基准分数,需要一个分数样本。问题是如何在最小化系统误差(如开销)的同时生成分数样本,并保持基准运行时间在可接受的范围内。

为了估算基准分数,函数 BenchmarkHelper.warmupBenchmarkHelper.warmupAsync 被运行 200 毫秒。

默认采样方法

下图显示了函数 BenchmarkHelper.sampleSize 计算的样本大小(橙色曲线)。绿色曲线表示总微基准持续时间的下限,代表值:clockTicks * sampleSize * innerIterations

Sample Size

对于小于 1 1100000 按照 ticks 的值选择不同的采样方法:

  • ticks < 1 11000 => 200 次运行,
  • 11000 < ticks < 1 1e4 => 200 … 100 次运行(指数插值),
  • 11e4 < ticks < 11e5 => 100 … 20 次运行(指数插值),
  • ticks > 11e5 => 不进行初步平均样本分数。

自定义采样方法

可以通过替换静态函数 BenchmarkHelper.sampleSize 来自定义分数采样过程:

BenchmarkHelper.sampleSize = (int clockTicks) {
  return (outer: 1  100, inner: 1  1)
}

要恢复默认的分数采样设置,请使用:

BenchmarkHelper.sampleSize = BenchmarkHelper.sampleSizeDefault;

更多关于Flutter性能测试插件benchmark_runner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter性能测试插件benchmark_runner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于Flutter性能测试插件benchmark_runner的使用,以下是一个简单的代码案例来展示如何设置和运行基准测试。benchmark_runner插件允许你在Flutter应用中执行性能基准测试,并收集关键性能指标。

设置环境

首先,确保你的Flutter环境已经正确设置,并且你的项目已经创建。然后,在你的pubspec.yaml文件中添加benchmark_runner依赖:

dependencies:
  flutter:
    sdk: flutter
  benchmark_runner: ^0.1.0  # 请检查最新版本号

运行flutter pub get来安装依赖。

编写基准测试

创建一个新的Dart文件,例如benchmark_test.dart,用于编写你的基准测试。以下是一个简单的示例:

import 'package:benchmark_runner/benchmark_runner.dart';
import 'package:flutter/material.dart';

void main() {
  group('Flutter Performance Benchmarks', () {
    test('Layout Benchmark', () {
      runBenchmark(() async {
        // 创建一个简单的Flutter Widget树
        final Widget widget = MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('Benchmark Test'),
            ),
            body: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: List.generate(1000, (index) => Text('Item $index')),
              ),
            ),
          ),
        );

        // 使用LayoutBuilder来触发布局构建
        await pumpWidget(widget, (context) async {
          final LayoutBuilder layoutBuilder = LayoutBuilder(
            builder: (context, constraints) {
              return Container();
            },
          );
          await pumpWidget(layoutBuilder);
        });
      }, baseline: const {'average_frame_build_time_millis': 16});
    });
  });
}

运行基准测试

在命令行中,导航到你的Flutter项目根目录,并运行以下命令来执行基准测试:

flutter pub run benchmark_runner:main

注意:benchmark_runner插件的实际使用可能会根据你的Flutter版本和插件的更新而有所不同。上述代码示例假设benchmark_runner提供了一些基本的API,如runBenchmarkpumpWidget,这些API可能会根据插件的实现有所变化。如果pumpWidget不是benchmark_runner的一部分,你可能需要使用Flutter的测试框架提供的TestWidgetsFlutterBindingWidgetTester来手动触发和测量布局构建。

注意事项

  • 确保在真实设备或模拟器上运行基准测试,以获得更准确的性能数据。
  • 基准测试应该在应用的不同部分和运行场景下执行,以获得全面的性能分析。
  • 监控内存使用情况和CPU负载,以了解应用的整体性能表现。

由于benchmark_runner的具体API和实现可能会随着版本更新而变化,请参考插件的官方文档和源代码以获取最新的使用指南和最佳实践。

回到顶部