基准测试#

设置#

首先安装 Archery 工具来运行基准测试套件。

运行基准测试套件#

可以使用 benchmark run 子命令运行基准测试套件。

# Run benchmarks in the current git workspace
archery benchmark run
# Storing the results in a file
archery benchmark run --output=run.json

有时,需要传递自定义 CMake 标志,例如:

export CC=clang-8 CXX=clang++8
archery benchmark run --cmake-extras="-DARROW_SIMD_LEVEL=NONE"

此外,还可以指定一个完整的 CMake 构建目录。

archery benchmark run $HOME/arrow/cpp/release-build

比较#

基准测试的一个目标是检测性能退化。为此,archery 通过 benchmark diff 子命令实现了一个基准测试比较功能。

在默认调用中,它将当前源代码(在 git 中称为当前工作区)与本地 main 分支进行比较。

archery --quiet benchmark diff --benchmark-filter=FloatParsing
-----------------------------------------------------------------------------------
Non-regressions: (1)
-----------------------------------------------------------------------------------
               benchmark            baseline           contender  change % counters
 FloatParsing<FloatType>  105.983M items/sec  105.983M items/sec       0.0       {}

------------------------------------------------------------------------------------
Regressions: (1)
------------------------------------------------------------------------------------
                benchmark            baseline           contender  change % counters
 FloatParsing<DoubleType>  209.941M items/sec  109.941M items/sec   -47.632       {}

欲了解更多信息,请调用 archery benchmark diff --help 命令以获取多个调用示例。

高效迭代#

由于构建时间长和运行时间长,基准测试开发中的迭代过程可能很繁琐。可以使用 archery benchmark diff 的多种技巧来减少这种开销。

首先,benchmark 命令支持比较现有构建目录,这可以与 --preserve 标志配合使用,以避免从头开始重新构建源文件。

# First invocation clone and checkouts in a temporary directory. The
# directory is preserved with --preserve
archery benchmark diff --preserve

# Modify C++ sources

# Re-run benchmark in the previously created build directory.
archery benchmark diff /tmp/arrow-bench*/{WORKSPACE,master}/build

其次,基准测试运行结果可以保存在 json 文件中。这也可以避免重新构建源文件,以及执行(有时)繁重的基准测试。这项技术可以作为一种简易缓存。

# Run the benchmarks on a given commit and save the result
archery benchmark run --output=run-head-1.json HEAD~1
# Compare the previous captured result with HEAD
archery benchmark diff HEAD run-head-1.json

第三,benchmark 命令支持过滤套件 (--suite-filter) 和基准测试 (--benchmark-filter),这两个选项都支持正则表达式。

# Taking over a previous run, but only filtering for benchmarks matching
# `Kernel` and suite matching `compute-aggregate`.
archery benchmark diff                                       \
  --suite-filter=compute-aggregate --benchmark-filter=Kernel \
  /tmp/arrow-bench*/{WORKSPACE,master}/build

除了在比较时重新运行基准测试外,还可以为竞争者和/或基线指定一个 JSON 文件(由 archery benchmark run 生成)。

archery benchmark run --output=baseline.json $HOME/arrow/cpp/release-build
git checkout some-feature
archery benchmark run --output=contender.json $HOME/arrow/cpp/release-build
archery benchmark diff contender.json baseline.json

回归检测#

编写基准测试#

  1. 默认情况下,benchmark 命令将使用正则表达式 ^Regression 过滤基准测试。这样,默认情况下并非所有基准测试都会运行。因此,如果您希望您的基准测试自动进行回归验证,则其名称必须匹配。

  2. benchmark 命令将使用 --benchmark_repetitions=K 选项运行以获得统计显著性。因此,基准测试不应覆盖 (C++) 基准测试参数定义中的重复次数。

  3. 由于 #2,基准测试应该运行得足够快。通常,当输入不适合内存 (L2/L3) 时,基准测试将是内存限制而不是 CPU 限制。在这种情况下,可以缩小输入。

  4. 默认情况下,Google 的基准测试库将使用 cputime 指标,它是进程所有线程在 CPU 上花费的运行时之和。与 realtime(即挂钟时间,例如 end_time - start_time 之间的差值)相比。在单线程模型中,cputime 更可取,因为它受上下文切换的影响较小。在多线程场景中,cputime 将给出不正确的结果,因为它会被线程数夸大,并且可能与 realtime 相差甚远。因此,如果基准测试是多线程的,最好使用 SetRealtime(),请参阅此示例

脚本编写#

archery 是一个带命令行前端的 python 库。该库可以导入以自动化某些任务。

由于构建输出,命令行界面的一些调用可能相当冗长。这可以通过 --quiet 选项或 --output=<file> 来控制/避免,例如:

archery benchmark diff --benchmark-filter=Kernel --output=compare.json ...