数据工程大数据序列化数据分析【免费下载链接】arrowApache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing项目地址https://gitcode.com/gh_mirrors/arrow13/arrow点击查看免费下载本文是一篇面向 Apache Arrow 开发者的基准测试Benchmark实战指南。文章以仓库文档 docs/source/developers/benchmarks.rst 为主体脉络结合dev/archery下的源码实现命令入口、Benchmark 数据模型、比较器逻辑与cpp/src下的 C 基准测试用例系统讲解如何用 Archery 工具运行、对比基准测试如何在开发迭代中高效复用构建与结果缓存以及编写可被自动回归检测的基准测试时需要遵守的规范。读完本文你将掌握archery benchmark run/archery benchmark diff/archery benchmark list的完整用法并能独立完成一次性能回归分析。一、前置准备安装 Archery运行基准测试套件的第一步是安装 Archery 工具。Archery 是 Apache Arrow 的开发者工具集以 Python 库加命令行前端CLI的形式组织其 benchmark 相关代码位于 dev/archery/archery/benchmark/ 目录。Archery 的详细安装与使用说明参见仓库文档 docs/source/developers/continuous_integration/archery.rst。其依赖与打包配置见 dev/archery/setup.py 与 dev/archery/requirements.txt通常通过pip install -e dev/archery的方式以可编辑模式安装。安装完成后可通过archery --help查看全部子命令。基准测试功能由benchmark命令组提供源码见 dev/archery/archery/cli.py#L346-L353包含三个子命令子命令作用archery benchmark list列出某个目标revision 或构建目录下的全部基准测试名称archery benchmark run针对单个目标运行基准测试套件并输出结果archery benchmark diff像git diff一样对比两组基准测试结果检测回归二、运行基准测试套件基准测试套件通过benchmark run子命令运行。最基本的用法是在当前 git 工作区workspace中直接运行# 在当前 git 工作区运行基准测试 archery benchmark run # 将结果保存到文件 archery benchmark run --outputrun.json这里WORKSPACE是一个保留的特殊标记代表当前 git 工作区意味着不会执行额外的 clone 操作见 dev/archery/archery/cli.py#L472-L473。除工作区外目标参数还可以是 git 修订版本commit、tag、HEAD、HEAD~1等或一个已有的 CMake 构建目录。从源码看CppBenchmarkRunner.default_configuration()见 dev/archery/archery/benchmark/runner.py#L117-L134为基准测试构建提供了默认配置build_typerelease、with_testsFalse、with_benchmarksTrue并默认启用 compute、csv、dataset、json、parquet 以及 brotli/bz2/lz4/snappy/zlib/zstd 等压缩算法模块关闭 Python 绑定。也就是说基准测试默认在 Release 模式下构建并覆盖 Arrow 的核心计算与 IO 能力。2.1 自定义 CMake 参数有时需要传入自定义的 CMake 编译参数例如指定编译器或关闭 SIMD 指令集export CCclang-8 CXXclang8 archery benchmark run --cmake-extras-DARROW_SIMD_LEVELNONE--cmake-extras是benchmark命令组的公共选项之一可多次堆叠使用multipleTrue会被透传给 CMake 配置阶段见 dev/archery/archery/cli.py#L381-L383。这类场景常用于验证不同编译器GCC vs Clang、不同优化级别、不同指令集如 SSE4.2 / AVX2 / AVX512对性能的影响。benchmark命令组的公共选项源码见 dev/archery/archery/cli.py#L356-L391还包括--src arrow_src指定 Arrow 源码目录默认取当前环境推断的源码根--preserve保留临时工作区下文详述--output file将输出结果写入文件--language {cpp,java}指定目标语言目前仅支持cpp与java默认cpp--cmake-extras透传给 CMake 的额外参数cpp--cpp-benchmark-extras透传给 C benchmark 可执行文件的额外参数--build-extras/--benchmark-extras透传给 Maven build / benchmark 的额外参数java。2.2 指定已有构建目录如果已经有一个完整的 CMake 构建目录可以跳过构建阶段直接运行基准测试archery benchmark run $HOME/arrow/cpp/release-build从CppBenchmarkRunner.from_rev_or_path见 dev/archery/archery/benchmark/runner.py#L195-L231的实现可以看到目标参数的三种解析方式若目标是 JSON 字符串或 JSON 文件则反序列化为静态结果集StaticBenchmarkRunner若目标是合法的 CMake 构建目录则直接复用该构建CMakeBuild.is_build_dir判断否则将其视为 git 修订版本在临时目录中 clone 并 checkout 对应代码后创建全新构建。此外benchmark run还支持--repetitions N与--repetition-min-time seconds参数用于控制每个基准的重复次数与单次最短运行时长提高统计精度cpp 默认 1 次、java 默认 5 次见 dev/archery/archery/cli.py#L447-L454。2.3 了解可运行的基准测试在运行之前可以用benchmark list先查看某个目标下有哪些基准测试# 列出当前工作区的全部基准测试 archery benchmark list # 列出某个构建目录中的基准测试 archery benchmark list /build/cpp # 列出某个历史提交的基准测试会临时 clone 该修订版本 archery benchmark list HEAD~1list与run复用相同的 runner 解析逻辑只是输出内容不同前者逐个输出套件名.基准名后者真正执行并序列化结果。以 C 为例runner 会扫描构建目录中所有匹配*-benchmark的可执行文件作为套件见 dev/archery/archery/benchmark/runner.py#L136-L143仓库中真实的基准套件分布在 cpp/src/arrow/io/memory_benchmark.cc、cpp/src/arrow/io/file_benchmark.cc、cpp/src/arrow/compute/kernels/scalar_arithmetic_benchmark.cc 等数十个文件中。三、结果对比检测性能回归基准测试的核心目标之一是检测性能回归performance regression。为此archery通过benchmark diff子命令实现了基准对比功能——它的定位就像针对基准测试结果的 git diff见 dev/archery/archery/cli.py#L555-L557。默认调用下它会将当前源码即 git 中的当前工作区作为 contender与本地主干分支默认基线 baseline 为origin/HEAD进行对比archery --quiet benchmark diff --benchmark-filterFloatParsing ----------------------------------------------------------------------------------- Non-regressions: (1) ----------------------------------------------------------------------------------- benchmark baseline contender change % counters FloatParsingFloatType 105.983M items/sec 105.983M items/sec 0.0 {} ------------------------------------------------------------------------------------ Regressions: (1) ------------------------------------------------------------------------------------ benchmark baseline contender change % counters FloatParsingDoubleType 209.941M items/sec 109.941M items/sec -47.632 {}输出被划分为Non-regressions无回归与Regressions回归两个分组字段包括基准名、基线值baseline、对比值contender、变化百分比change %与 counters。上述示例中FloatParsingDoubleType从 209.941M items/sec 跌到 109.941M items/sec变化达 -47.632%被判定为回归。3.1 对比判定逻辑的源码实现回归判定逻辑位于 dev/archery/archery/benchmark/compare.py全局回归阈值DEFAULT_THRESHOLD 0.055%注释明确说明这是一个主观且并不完美的全局默认值不追踪累积回归见 dev/archery/archery/benchmark/compare.py#L19-L21BenchmarkComparator.change计算变化率(new - old) / abs(old)regression属性结合less_is_better单位是否是per_second类型决定越小越好还是越大越好与阈值判定回归即调整后的变化超过 5% 即视为回归见 dev/archery/archery/benchmark/compare.py#L104-L108RunnerComparator.comparisons对两套 runner 的套件与基准按名称做两两对比pairwise_compare生成BenchmarkComparator序列输出格式化在_format_comparisons_with_pandas见 dev/archery/archery/cli.py#L687-L713使用 pandas 将结果解析为 DataFrame按change %降序排列再切分为 Non-regressions / Regressions 两组打印。--threshold选项可覆盖默认的 5% 阈值# 将回归阈值放宽到 10% archery benchmark diff --threshold0.13.2 对比任意目标组合benchmark diff的两个位置参数分别是contender与baseline二者均可为 git 修订版本或 CMake 构建目录因此可以灵活组合出多种对比场景例如对比不同编译器、不同编译选项构建的结果# 用 gcc-7 构建 gcc7-build用 clang-8 构建 clang8-build archery build --with-benchmarkstrue \ --cxx-flags-ftree-vectorize \ --ccgcc-7 --cxxg-7 gcc7-build archery build --with-benchmarkstrue \ --cxx-flags-flax-vector-conversions \ --ccclang-8 --cxxclang-8 clang8-build # 对比两个构建目录 archery benchmark diff gcc7-build clang8-build对比主干分支与最新发布 tagexport LAST$(git tag -l apache-arrow-[0-9]* | sort -rV | head -1) archery benchmark diff default-branch $LAST更多调用示例可通过archery benchmark diff --help查看。四、高效迭代三招降低基准测试开发开销基准测试开发往往因漫长的构建时间与运行时间而显得繁琐。archery benchmark diff提供了多种技巧来显著降低这一开销。4.1 复用已有构建目录--preserve基准测试命令支持直接对比已有构建目录。配合--preserve标志可以避免从零开始重复构建源码# 第一次调用在临时目录中 clone 并 checkout--preserve 保留该目录 archery benchmark diff --preserve # 修改 C 源码 ... # 在先前创建的构建目录中重新运行基准测试 archery benchmark diff /tmp/arrow-bench*/{WORKSPACE,master}/build当目标为 git 修订版本时archery 默认在临时目录中完成 clone/checkout 与构建临时目录随命令结束被清理--preserve会保留该目录目录名形如/tmp/arrow-bench*/{WORKSPACE,master}/build供后续迭代直接复用仅增量重建修改过的部分对应 dev/archery/archery/cli.py#L366-L368 中--preserve选项以及tmpdir(preservepreserve)的上下文管理。4.2 用 JSON 结果文件做穷人缓存benchmark run的结果可以保存为 JSON 文件。这既能避免重新构建源码也能避免重复执行有时代价很高的基准测试——相当于一种轻量级缓存机制# 在某个 commit 上运行基准测试并保存结果 archery benchmark run --outputrun-head-1.json HEAD~1 # 将此前捕获的结果与 HEAD 对比 archery benchmark diff HEAD run-head-1.json运行结果文件同样可用于 diff 的 contender 与 baseline 两个位置archery benchmark run --outputbaseline.json $HOME/arrow/cpp/release-build git checkout some-feature archery benchmark run --outputcontender.json $HOME/arrow/cpp/release-build archery benchmark diff contender.json baseline.json从from_rev_or_path的第一条分支可见dev/archery/archery/benchmark/runner.py#L211-L214只要目标是可反序列化为 runner 的 JSON文件或字符串就会走StaticBenchmarkRunner.from_json直接加载静态结果不再触发任何构建与执行。JSON 的编解码格式定义在 dev/archery/archery/benchmark/codec.py每个 Benchmark 序列化为name / unit / less_is_better / values / time_unit / times / counters字段套件与 runner 逐层嵌套最终可整体存入一个文件。4.3 正则过滤套件与基准benchmark命令支持用--suite-filter过滤套件、用--benchmark-filter过滤基准两者均接受正则表达式# 从一次既有运行中接手只保留匹配 Kernel 的基准、匹配 compute-aggregate 的套件 archery benchmark diff \ --suite-filtercompute-aggregate --benchmark-filterKernel \ /tmp/arrow-bench*/{WORKSPACE,master}/build过滤器的实现位于 dev/archery/archery/benchmark/runner.py#L33-L37regex_filter将正则编译后对套件名 / 基准名执行searchNone表示不过滤。过滤在suites属性中逐级应用先过滤套件、再过滤套件内基准见 dev/archery/archery/benchmark/runner.py#L168-L193。另外若过滤条件匹配不到任何基准runner 会抛出ValueError(No benchmark matches the suite/benchmark filter)用于及早发现拼写错误。--benchmark-filter同样适用于run/list见benchmark_filter_optionsdev/archery/archery/cli.py#L394-L403例如按套件前缀精确收窄对比范围archery benchmark diff --suite-filter^arrow-compute-aggregate \ --benchmark-filter(Sum|Mean)Kernel五、回归检测如何编写合格的基准测试要让基准测试被自动纳入回归检测编写时需要遵守以下规范规则详见 docs/source/developers/benchmarks.rst 的 Regression detection 一节。5.1 四条硬性规则规则 1基准名必须以^Regression开头。benchmark命令默认用正则^Regression过滤基准测试因此并非所有基准都会默认运行。如果希望自己的基准被自动执行回归校验命名必须匹配该前缀。例如仓库中的RegressionSumKernel、RegressionMeanKernel一类命名在 dev/archery/archery/tests/test_benchmarks.py 的测试与 fixtures 中均有体现。规则 2不要覆盖 C 基准参数定义中的 repetitions。命令会以--benchmark_repetitionsK运行以获得统计显著性对应 dev/archery/archery/benchmark/google.py#L53-L68 中GoogleBenchmarkCommand.results组装--benchmark_repetitions、--benchmark_out、--benchmark_out_formatjson等参数。因此基准自身不应在参数定义中硬编码重复次数否则会与命令行重复设置冲突。规则 3基准应运行得足够快。受规则 2 影响基准会被重复执行多次。当输入数据放不进内存L2/L3 缓存时基准往往会变成内存带宽受限而非 CPU 受限此时应缩小输入规模保证测量的是 CPU 计算路径。这一原则在仓库的基准实现中有大量体现例如ParallelMemoryCopy基准cpp/src/arrow/io/memory_benchmark.cc#L311-L315通过RangeMultiplier(2)、Range(1, kNumCores)控制线程数范围BufferOutputStream系列基准固定写入约 32 MB 数据(1 25) / raw_nbytes次迭代以维持可控的运行时长cpp/src/arrow/io/memory_benchmark.cc#L317-L329。规则 4正确选择时间度量cputime vs realtime。Google benchmark 库默认使用cputime度量——即进程所有线程在 CPU 上花费的运行时间之和与之相对的realtime是墙钟时间end_time - start_time。两者的取舍如下单线程模型下cputime 受上下文切换影响更小是更优选择多线程场景下cputime 会被线程数放大、严重偏离 realtime此时应改用SetRealtime()C 中对应UseRealTime()。仓库中多线程基准ParallelMemoryCopy与多个 IO 流基准都显式调用了UseRealTime()见 cpp/src/arrow/io/memory_benchmark.cc#L311-L315 与 cpp/src/arrow/io/file_benchmark.cc#L290-L296。Archery 在解析 GoogleBenchmark 结果时也会识别名称含/real_time的观测并优先采用 realtime 值见 dev/archery/archery/benchmark/google.py#L108-L120 的is_realtime与time属性。5.2 结果聚合中位数与统计信息archery 对单次运行的多次重复观测runs做聚合处理GoogleBenchmark会剔除 Google benchmark 生成的_mean、_median、_stddev等聚合观测run_type aggregate仅保留真实 runs并排序后取中位数作为基准的代表值dev/archery/archery/benchmark/google.py#L155-L166。Benchmark.median的计算见 dev/archery/archery/benchmark/core.py#L19-L26。单位方面bytes_per_second与items_per_second型指标越大越好less_is_betterFalse纯时间型指标则相反对比输出时数值会由items_per_seconds_fmt/bytes_per_seconds_fmt自动格式化为 K/M/G 单位见 dev/archery/archery/benchmark/compare.py#L24-L58因此文档示例中会出现105.983M items/sec这类读数。六、脚本化把 benchmark 能力集成进自动化流程archery以 Python 库 命令行前端的形态编写其库可以导入用于自动化任务。benchmark run与benchmark diff在内部均以 Python 对象表达BenchmarkRunnerrunner、BenchmarkSuite/Benchmark数据模型、RunnerComparator/BenchmarkComparator比较器均可直接 import 复用。由于 CLI 的构建输出可能相当冗长有两种方式控制输出使用--quiet选项抑制日志输出使用--outputfile将结果写入文件。# 将 diff 结果写入文件等价于 --output archery benchmark diff --benchmark-filterKernel --outputcompare.json ... # 用 --quiet 避免 stdout 被日志干扰再重定向到文件 archery --quiet benchmark diff result.json--output写入的内容实际是 JSON Lines 格式每个 comparator 序列化为一行 JSON见_get_comparisons_as_jsondev/archery/archery/cli.py#L678-L684便于下游程序逐行解析而终端直接展示的表格则依赖 pandas 格式化。结合JSON 结果文件可被 diff 直接当作 contender/baseline 使用的特性可以实现先采集、后分析的解耦流水线archery benchmark run --outputrun.json HEAD~1 archery --quiet benchmark diff WORKSPACE run.json result.json第一条命令在历史提交上采集基线结果并缓存第二条命令将当前工作区与缓存结果对比——由于run.json是静态结果diff 不会重新构建或运行任何基准见 dev/archery/archery/benchmark/runner.py#L196-L231 的三种目标解析优先级。仓库自身的测试 dev/archery/archery/tests/test_benchmarks.py 及其 fixtures如 dev/archery/archery/tests/fixtures/archery-benchmark-diff.jsonl覆盖了 diff 输出解析等关键路径可作为二次开发时理解数据格式的参考。七、小结围绕基准测试这一主题Archery 提供了运行run— 对比diff— 回归检测Regression 前缀 阈值判定— 脚本化的完整闭环用archery benchmark run [rev_or_path]采集结果支持 git 修订版本、WORKSPACE 与已有 CMake 构建目录三种目标必要时以--cmake-extras注入自定义编译参数用archery benchmark diff [contender] [baseline]完成基准测试版的 git diff默认以 5% 阈值划分 Regressions 与 Non-regressions--suite-filter/--benchmark-filter用正则收窄范围用--preserve、JSON 结果缓存、正则过滤三种手段大幅压缩迭代成本编写回归基准时遵守命名前缀^Regression、不覆盖 repetitions、控制运行时长、多线程场景使用UseRealTime()四条规则即可无缝接入自动回归检测。对于深度使用场景建议直接阅读 dev/archery/archery/benchmark/ 下的 runner、compare、google、codec 四个模块理解 runner 的目标解析优先级、比较器的阈值判定与 JSON 编解码格式即可将基准能力进一步集成到自定义的性能监控与 CI 流程中。赞分享数据工程大数据序列化数据分析【免费下载链接】arrowApache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing项目地址https://gitcode.com/gh_mirrors/arrow13/arrow点击查看免费下载相关推荐使用 Archery 运行 Apache Arrow 基准测试套件执行、结果对比与回归检测实战指南使用 Archery 运行 Apache Arrow 基准测试套件执行、结果对比与回归检测实战指南 本文面向 Apache Arrow 的贡献者与性能敏感型使大数据数据分析数据工程序列化Apache Arrow 性能基准测试实践用 Archery 运行、对比与回归检测Apache Arrow 性能基准测试实践用 Archery 运行、对比与回归检测 本文是 Apache Arrow 开发者基准测试Benchmark指南数据工程数据分析大数据如何用 archery 运行 Arrow C 基准测试并与 main 分支比较检测性能回退如何用 archery 运行 Arrow C 基准测试并与 main 分支比较检测性能回退 如果你在 Arrow 仓库中修改了 C 代码想确认这次改动大数据数据分析数据工程序列化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
