Apache Arrow 基准测试构建环境全解:conbench_envs 与 @ursabot 钩子机制实战
【免费下载链接】arrowApache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics项目地址: https://gitcode.com/GitHub_Trending/arrow3/arrow
Apache Arrow 作为通用列式内存格式与多语言工具箱,其性能演进高度依赖一套稳定、可复现的基准测试(benchmark)体系。本文聚焦仓库中dev/conbench_envs目录下的 benchmarks.env 与 hooks.sh 两份核心文件,完整讲解它们如何支撑@ursabot please benchmarkPR 评论触发的自动化基准构建:包括环境变量全量解析、钩子函数与 CI 脚本的调用关系、baseline/contender 对比机制,以及一条从零搭建 Arrow C++/Python/R/Java/JavaScript 基准环境的 14 步实战流程。读完本文,你将能够理解 Arrow 官方基准基础设施的工作原理,并能在自己的仓库中复用这套机制来评估不同构建选项、依赖版本对性能的影响。
一、dev/conbench_envs目录的两大核心资产
dev/conbench_envs/README.md 开宗明义:该目录包含两个文件,分别解决「构建与运行环境怎么配」和「基准构建流程怎么挂钩」两个问题。
1.benchmarks.env:基准构建的运行环境变量清单
benchmarks.env 是一个纯环境变量文件,用于配置 Arrow C++/Python/R/Java/JavaScript 的构建参数以及运行基准测试时的环境。它通过set -a/source的方式被载入 shell 环境(见后文set_arrow_build_and_run_env_vars钩子)。
| 环境变量 | 取值 | 含义 |
|---|---|---|
CMAKE_BUILD_TYPE | release | CMake 构建类型,基准必须使用 release 优化 |
ARROW_BUILD_TESTS | OFF | 关闭单元测试编译,加速构建 |
ARROW_BUILD_BENCHMARKS | ON | 开启 Arrow C++ 基准(benchmark)目标编译 |
ARROW_BUILD_BENCHMARKS_REFERENCE | OFF | 关闭参考实现基准(避免与主基准混淆) |
ARROW_BUILD_TYPE | release | Arrow 顶层构建类型,与 CMake 构建类型对应 |
ARROW_DEPENDENCY_SOURCE | AUTO | 第三方依赖来源自动探测(系统/捆绑/conda) |
ARROW_DATASET | ON | 启用 Dataset 组件(基准数据读取需要) |
ARROW_DEFAULT_MEMORY_POOL | mimalloc | 默认内存池使用 mimalloc |
ARROW_FLIGHT | OFF | 关闭 Flight RPC 组件 |
ARROW_GANDIVA | OFF | 关闭 Gandiva 表达式引擎 |
ARROW_HDFS | ON | 启用 HDFS 文件系统支持 |
ARROW_HOME | $CONDA_PREFIX | Arrow 安装前缀指向 conda 环境 |
ARROW_INSTALL_NAME_RPATH | ON | macOS 上写入安装名 RPATH |
ARROW_JEMALLOC | OFF | 关闭 jemalloc 内存池(与 mimalloc 二选一) |
ARROW_MIMALLOC | ON | 启用 mimalloc 内存池 |
ARROW_ORC | ON | 启用 ORC 文件格式支持 |
ARROW_PARQUET | ON | 启用 Parquet 文件格式支持 |
ARROW_S3 | ON | 启用 S3 文件系统支持 |
ARROW_USE_CCACHE | ON | 使用 ccache 加速重复构建 |
ARROW_WITH_BROTLI | ON | 启用 Brotli 压缩编解码 |
ARROW_WITH_BZ2 | ON | 启用 Bzip2 压缩编解码 |
ARROW_WITH_LZ4 | ON | 启用 LZ4 压缩编解码 |
ARROW_WITH_SNAPPY | ON | 启用 Snappy 压缩编解码 |
ARROW_WITH_ZLIB | ON | 启用 zlib 压缩编解码 |
ARROW_WITH_ZSTD | ON | 启用 Zstandard 压缩编解码 |
CMAKE_VERBOSE_MAKEFILE | ON | 输出完整编译命令行,便于排查构建问题 |
GTest_SOURCE | BUNDLED | GTest 使用捆绑源码编译 |
ORC_SOURCE | BUNDLED | ORC 使用捆绑源码编译 |
PARQUET_BUILD_EXAMPLES | ON | 编译 Parquet 示例程序 |
PARQUET_BUILD_EXECUTABLES | ON | 编译 Parquet 命令行工具 |
PYTHON | python | Python 解释器名称 |
LD_LIBRARY_PATH | $CONDA_PREFIX/lib:$LD_LIBRARY_PATH | 运行时动态库搜索路径指向 conda 前缀 |
值得注意的组合语义:该配置刻意选择了ARROW_DEFAULT_MEMORY_POOL=mimalloc并关闭 jemalloc、开启全部主流压缩编解码、开启 Parquet/ORC/Dataset/S3/HDFS 等大组件、同时关闭 Flight 与 Gandiva,构成一套「贴近真实分析负载且组件齐全」的基准基线。
2.hooks.sh:可被外部基准构建调用的钩子函数集合
hooks.sh 是一份bash脚本,末尾的"$@"使其支持以source dev/conbench_envs/hooks.sh <函数名>的形式按名调用内部函数。脚本以set -ex开头——任何命令失败立即退出并打印执行轨迹,保证基准构建在出错时能第一时间暴露问题。
脚本定义了以下钩子函数:
| 钩子函数 | 作用 |
|---|---|
create_conda_env_for_benchmark_build | 用 conda-forge 创建名为${BENCHMARKABLE_TYPE}的 conda 环境,安装 ci/conda_env_cpp.txt、ci/conda_env_python.txt、ci/conda_env_unix.txt 中的依赖,外加compilers、python=${PYTHON_VERSION}、pandas、r |
activate_conda_env_for_benchmark_build | 执行conda init bash并激活上述环境 |
install_arrow_python_dependencies | 通过 pip 安装 python/requirements-build.txt 与 python/requirements-test.txt |
set_arrow_build_and_run_env_vars | 以set -a方式 source benchmarks.env,将全部变量导出到环境 |
build_arrow_cpp | 在/tmp/arrow-cpp-$(uuidgen)目录调用 ci/scripts/cpp_build.sh 编译并安装 Arrow C++ |
build_arrow_python | 调用 ci/scripts/python_build.sh 构建 Arrow Python 绑定 |
build_arrow_r | 追加 ci/etc/rprofile 到 R 的 Rprofile,必要时为 R 的 Makeconf 补写 C++20 配置(conda-forge 的 R 可能缺少CXX20项,而 Arrow 要求 C++20),再执行 ci/scripts/r_deps.sh 安装 R 依赖并R CMD INSTALL安装 R 包 |
build_arrow_java | 调用ci/scripts/java_build.sh构建 Arrow Java |
install_archery | 以可编辑模式安装 dev/archery(Arrow 开发工具链,C++ 基准运行依赖) |
install_java_script_project_dependencies | 在js目录执行yarn安装 JavaScript 依赖 |
create_conda_env_with_arrow_python | 组合钩子:依次执行创建环境、激活环境、安装 Python 依赖、设置环境变量、构建 C++、构建 Python 六步 |
其中create_conda_env_with_arrow_python是「一条命令完成 Arrow Python 基准环境」的总入口,README 第 6 步正是使用它。
二、钩子机制为什么必须放在 Arrow 仓库内
README 专门用一节解释了hooks.sh存在的必要性,其核心逻辑是「版本随提交走」:
@ursabot基准构建本身维护在 Ursa 的私有仓库中,但构建过程需要根据被基准的某个 Arrow commit来创建 conda 环境、编译 Arrow C++/Python/R/Java/JavaScript。- 如果将钩子定义放在外部,那么当 Arrow 仓库中安装依赖的脚本(如 ci/conda_env_cpp.txt)或构建脚本(如 ci/scripts/cpp_build.sh)发生重命名、移动或增删时,外部钩子会与目标 commit 的脚本失配。
- 把钩子定义在 Arrow 仓库内,基准构建针对某个 commit 执行时,使用的就是该 commit 自带版本的钩子与脚本,天然保证兼容。
这使 Arrow 贡献者可以通过修改hooks.sh或benchmarks.env来评估不同构建选项、依赖版本对性能的影响——这是该机制最核心的用途。
三、@ursabot please benchmark:baseline 与 contender 对比工作流
README 给出了通过 PR 评论触发基准的完整闭环:
- 创建
apache/arrowPR; - 在 dev/conbench_envs/benchmarks.env 中更新或新增环境变量;
- 在 PR 下评论
@ursabot please benchmark; - 基准构建完成后,结果通过 PR 评论中的 compare/runs 链接查看,其中:
- baseline= PR 基础分支(base)HEAD commit,使用未改动的
benchmarks.env; - contender= PR 分支 HEAD commit,使用被覆盖(改动过)的
benchmarks.env。
- baseline= PR 基础分支(base)HEAD commit,使用未改动的
这种「同 commit 双份环境变量」的设计,使性能对比严格隔离了代码差异与配置差异:baseline 与 contender 的差异仅在于benchmarks.env的改动,从而可以精准归因性能变化来自哪个构建选项或依赖版本。
四、在自有仓库复用这两份文件的前提
README 明确表示其他仓库和服务欢迎复用benchmarks.env与hooks.sh,但必须遵守三条约束:
- 不得移除或重命名现有钩子;
- 现有钩子的函数定义只能在 Arrow commit 中构建脚本或依赖文件发生重命名、移动、新增时更新;
- 函数定义更新后,必须通过
@ursabot please benchmark评论实际运行一次基准构建,确认更新没有破坏构建。
这套约定保证了钩子 API 的向后兼容性,避免外部依赖方因钩子签名悄然变化而静默失败。
五、从零搭建基准环境的 14 步实战(Ubuntu)
以下按 README 原始步骤完整复现,并结合仓库脚本补充必要说明。所有命令在 Ubuntu 上以 root(sudo su)执行。
步骤 1:安装 Arrow 系统依赖
sudo su apt-get update -y -q && \ apt-get install -y -q --no-install-recommends \ autoconf \ ca-certificates \ ccache \ cmake \ g++ \ gcc \ gdb \ git \ libbenchmark-dev \ libboost-filesystem-dev \ libboost-regex-dev \ libboost-system-dev \ libbrotli-dev \ libbz2-dev \ libgflags-dev \ libcurl4-openssl-dev \ libgoogle-glog-dev \ liblz4-dev \ libprotobuf-dev \ libprotoc-dev \ libre2-dev \ libsnappy-dev \ libssl-dev \ libthrift-dev \ libutf8proc-dev \ libzstd-dev \ make \ ninja-build \ pkg-config \ protobuf-compiler \ rapidjson-dev \ tzdata \ wget && \ apt-get clean && \ rm -rf /var/lib/apt/lists* apt-get update -y -q && \ apt-get install -y -q \ python3 \ python3-pip \ python3-dev && \ apt-get clean && \ rm -rf /var/lib/apt/lists/*此清单覆盖了 Arrow C++ 编译所需的压缩库(brotli/bz2/lz4/snappy/zstd)、序列化库(protobuf/thrift)、正则引擎(re2)、性能分析基础(libbenchmark-dev)、构建工具(cmake/ninja/pkg-config)等。与 ci/conda_env_cpp.txt 中的 conda 依赖清单(含benchmark>=1.6.0,!=1.8.4,<1.9.5、orc<2.1.0、xsimd>=14.2等)互为补充:前者面向 conda 环境,此处面向系统 apt 环境。
步骤 2:安装 Java 依赖并校验版本
sudo su apt-get install openjdk-11-jdk apt-get install maven校验最低版本:
# java -version openjdk version "11.0.22" 2024-01-16 .. # javac -version javac 11.0.22 ... # mvn -version Apache Maven 3.6.3 ...步骤 3:安装 JavaScript 依赖并校验版本
sudo apt update sudo apt -y upgrade sudo apt update sudo apt -y install curl dirmngr apt-transport-https lsb-release ca-certificates curl -fsSL https://deb.nodesource.com/setup_14.x | sudo -E bash - sudo apt-get install -y nodejs sudo apt -y install yarn sudo apt -y install gcc g++ make校验最低版本:
# node --version v14.17.2 ... # yarn --version 1.22.5 ...(注:以上版本号是 README 编写时的示例基线;当前仓库对 Node.js 的最低要求以 ci/conda_env_cpp.txt 中的nodejs>=16为准。)
步骤 4:安装 Miniconda
sudo apt install curl curl -LO https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh sudo bash Miniconda3-latest-Linux-x86_64.sh步骤 5:设置基准构建环境变量
export ARROW_REPO=https://github.com/apache/arrow.git export BENCHMARKABLE=e6e9e6ea52b7a8f2682ffc4160168c936ca1d3e6 export BENCHMARKABLE_TYPE=arrow-commit export PYTHON_VERSION=3.8 export CONBENCH_EMAIL=... export CONBENCH_URL="https://conbench.ursa.dev" export CONBENCH_PASSWORD=... export MACHINE=...其中BENCHMARKABLE是待基准的 Arrow commit SHA,BENCHMARKABLE_TYPE同时用作 conda 环境名,PYTHON_VERSION传给create_conda_env_for_benchmark_build钩子(该钩子用python="${PYTHON_VERSION}"创建环境),CONBENCH_*与MACHINE用于后续向 conbench 服务端提交结果。
步骤 6:用create_conda_env_with_arrow_python钩子构建 Arrow C++ 与 Python
git clone "${ARROW_REPO}" pushd arrow git fetch -v --prune -- origin "${BENCHMARKABLE}" git checkout -f "${BENCHMARKABLE}" source dev/conbench_envs/hooks.sh create_conda_env_with_arrow_python popd这条命令内部依次完成:基于 ci/conda_env_cpp.txt、ci/conda_env_python.txt、ci/conda_env_unix.txt 创建 conda 环境 → 激活环境 → 安装 Python 构建/测试依赖 → 导出 benchmarks.env 全部变量 → 调用 ci/scripts/cpp_build.sh 编译 C++ → 调用 ci/scripts/python_build.sh 构建 Python。cpp_build.sh会把benchmarks.env中的ARROW_*变量逐项映射为 CMake 参数(例如ARROW_BUILD_BENCHMARKS=ON→-DARROW_BUILD_BENCHMARKS=ON),python_build.sh则据此导出PYARROW_WITH_*系列变量决定 Python 绑定编译哪些组件。
步骤 7:安装 conbench CLI
git clone https://github.com/ursacomputing/conbench.git pushd conbench pip install -r requirements-cli.txt pip install -U PyYAML python setup.py install popd步骤 8:准备 benchmarks 基准仓库
git clone https://github.com/ursacomputing/benchmarks.git pushd benchmarks python setup.py develop popd步骤 9:配置 conbench 凭据
pushd benchmarks touch .conbench echo "url: $CONBENCH_URL" >> .conbench echo "email: $CONBENCH_EMAIL" >> .conbench echo "password: $CONBENCH_PASSWORD" >> .conbench echo "host_name: $MACHINE" >> .conbench popd步骤 10:运行 Python 基准
cd benchmarks conbench file-read ALL --iterations=3 --all=true --drop-caches=true--drop-caches=true在每次迭代前清空操作系统文件缓存,避免缓存命中造成性能虚高,是保证结果可复现的关键参数。
步骤 11:安装 archery 并运行 C++ 基准
pushd arrow source dev/conbench_envs/hooks.sh install_archery popd cd benchmarks conbench cpp-micro --iterations=1install_archery以可编辑模式安装 dev/archery(pip install -e dev/archery),其为 C++ 微基准的运行提供配套工具链。
步骤 12:构建 Arrow R 并运行 R 基准
pushd arrow source dev/conbench_envs/hooks.sh build_arrow_r popd R -e "remotes::install_github('ursacomputing/arrowbench')" cd benchmarks conbench dataframe-to-table ALL --iterations=3 --drop-caches=true --language=Rbuild_arrow_r钩子内部会调用 ci/scripts/r_deps.sh 安装 R 包依赖。针对 conda-forge 的 R 可能缺失CXX20配置的问题,该钩子会在 R 的Makeconf中补写CXX20 = g++、CXX20FLAGS = -g -O2 $(LTO)、CXX20STD = -std=gnu++20等条目,以满足 Arrow 的 C++20 编译要求。
步骤 13:构建 Arrow Java 并运行 Java 基准
pushd arrow source dev/conbench_envs/hooks.sh build_arrow_java source dev/conbench_envs/hooks.sh install_archery popd cd benchmarks conbench java-micro --iterations=1步骤 14:安装 JavaScript 依赖并运行 JS 基准
pushd arrow source dev/conbench_envs/hooks.sh install_java_script_project_dependencies popd cd benchmarks conbench js-microinstall_java_script_project_dependencies会在js目录执行yarn拉取全部 JavaScript 依赖,随后conbench js-micro直接运行 JS 微基准。
六、钩子函数的内部调用链一览
综合 hooks.sh 与ci目录脚本,可以梳理出完整的调用关系:
create_conda_env_with_arrow_python ├── create_conda_env_for_benchmark_build │ └── conda create --file ci/conda_env_{cpp,python,unix}.txt ... ├── activate_conda_env_for_benchmark_build ├── install_arrow_python_dependencies │ └── pip install -r python/requirements-build.txt -r python/requirements-test.txt ├── set_arrow_build_and_run_env_vars │ └── source dev/conbench_envs/benchmarks.env ├── build_arrow_cpp │ └── ci/scripts/cpp_build.sh <repo> /tmp/arrow-cpp-$(uuidgen) └── build_arrow_python └── ci/scripts/python_build.sh <repo> /tmp/arrow单语言钩子(build_arrow_r、build_arrow_java、install_archery、install_java_script_project_dependencies)则分别复用 ci/scripts/r_deps.sh、ci/scripts/java_build.sh、dev/archery 的 pip 安装入口与js/yarn入口。
七、复用这套机制时的注意事项
- 环境前提:完整流程基于 Ubuntu + apt + Miniconda,且步骤 1~5 需要 root 权限;若在 conda 环境内构建,依赖应优先取自 ci/conda_env_cpp.txt 等清单,避免 apt 与 conda 两套依赖互相污染。
- 版本随 commit 走:务必在 checkout 到目标 commit 之后、执行钩子之前使用该 commit 自带的
hooks.sh与benchmarks.env,这正是钩子机制设计的初衷。 - 构建目录隔离:
build_arrow_cpp每次使用uuidgen生成唯一构建目录,避免并发或重复构建相互覆盖;ci/scripts/cpp_build.sh 构建完成后还会删除*.o以节省磁盘。 - 性能对比语义:通过 PR 评论触发时,baseline 与 contender 的唯一变量就是
benchmarks.env的改动,因此修改任何ARROW_*构建选项或依赖版本后,都应回归一次基准构建以确认钩子与脚本的兼容性。
结语
dev/conbench_envs是 Apache Arrow 性能工程基础设施的「可移植单元」:benchmarks.env 以声明式方式固化了一套贴近真实分析负载的构建配置,hooks.sh 以「版本随 commit 走」的钩子模式保证了外部基准构建与任意历史 commit 的脚本兼容。无论是 Arrow 贡献者评估构建选项对性能的影响,还是其他仓库借鉴这套基准 CI 体系,本文的 14 步流程与源码级调用链分析都可以作为直接落地的操作手册。
【免费下载链接】arrowApache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics项目地址: https://gitcode.com/GitHub_Trending/arrow3/arrow
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考