DragonArray 文档

从源码构建适用于 LoongArch 的 TensorFlow 2.21.0

DragonArray 的 TensorFlow 补丁加入了 LoongArch Bazel platform 与 wheel tag、 CPython 3.13 toolchain 支持、GCC 15 兼容性修复、old-world 构建 shim、sparse BF16 修复,以及 LASX path 使用的 Eigen convolution 改动。

同一份补丁支持三种 CPU profile,但编译器 flag 不能混用。请选择一种 profile, 并在 TensorFlow、static C++ runtime、NumPy 及所有其他 native dependency 中 始终使用同一套 flag。

源码版本与补丁

请构建以下准确的 TensorFlow revision:

tag:     v2.21.0
commit:  a481b10260dfdf833a1b16007eead49c1d7febf3

下载 tensorflow-2.21.0-loongarch64.patch.gz 补丁。已发布文件的 checksum 如下:

compressed .gz: b6804b551a01693c517eab7f26f7bd571e558b52df94c3b87425f9a45a8ad9af
uncompressed:   15de4da62c2d1309a39362a7a44cf2a9f948cab7aaf9abc772a969b4e47134d4

从干净的 checkout 开始,并只应用一次 consolidated patch:

git clone --branch v2.21.0 --depth 1 \
  https://github.com/tensorflow/tensorflow.git tensorflow-2.21.0
cd tensorflow-2.21.0

test "$(git rev-parse HEAD)" = \
  a481b10260dfdf833a1b16007eead49c1d7febf3

curl --fail --location --output tensorflow.patch.gz \
  https://dragon-array.org/download/tensorflow-2.21.0-loongarch64.patch.gz
printf '%s  %s\n' \
  b6804b551a01693c517eab7f26f7bd571e558b52df94c3b87425f9a45a8ad9af \
  tensorflow.patch.gz | sha256sum -c -

gzip -dc tensorflow.patch.gz > tensorflow.patch
printf '%s  %s\n' \
  15de4da62c2d1309a39362a7a44cf2a9f948cab7aaf9abc772a969b4e47134d4 \
  tensorflow.patch | sha256sum -c -

git apply --check tensorflow.patch
git apply tensorflow.patch
git diff --check
git apply --reverse --check tensorflow.patch

最后一个命令是只读检查:它证明完整补丁已存在于 working tree。不要在此文件之上 叠加较旧的 incremental TensorFlow 或 XLA patch;这些改动已经包含在内。 h5py、grpcio 和准备好的 Bazel override repository 补丁仍是独立文件,因为它们 修改的是其他 source tree。

选择 CPU profile

如果不清楚处理器型号,请在目标系统上运行 lscpu

LC_ALL=C lscpu | grep -E 'Architecture|Model name|Flags'
目标系统 ISA level 必需的编译器 flag Bazel output base 示例
龙芯 3A5000 和 3B5000 LA464,仅 LSX -march=la464 -mtune=la464 -mlsx -mno-lasx ~/.cache/bazel/tf-2.21.0-la464-lsx
龙芯 3C5000 LA464,LASX -march=la464 -mtune=la464 -mlasx ~/.cache/bazel/tf-2.21.0-la464-lasx
龙芯 3A6000、3B6000 与 3C6000 系列 LA664,LASX -march=la664 -mtune=la664 -mlasx ~/.cache/bazel/tf-2.21.0-la664-lasx

所有 profile 的 native release build 还要使用 -O2 -g0 -fPIC -mcmodel=medium

这些差异不能忽略:

不要对可重新分发的 wheel 使用 -march=native。target 与 host C/C++ action、 static libstdc++.a、TensorFlow、NumPy、HDF5/h5py、grpcio、ml_dtypes 和 optree 都必须使用选定的 ISA flag。每个 profile 都应使用独立的 build tree、 virtual environment、wheel directory 与 Bazel output base。

已验证的构建环境

DragonArray wheel 使用以下环境生成:

GCC                 15.2.0  /opt/loongson-gcc-15.2.0
Bazel                8.4.2
CMake                4.3.2
Ninja                 1.10
OpenJDK              21.0.10
pyenv                 2.8.1
build Python         3.13.13
validation Python    3.13.14

请准备至少 15 GiB RAM(并配置 swap),以及 60 GiB 可用磁盘空间供独立 Bazel output tree 使用。reference build 使用四个 job 和 10 GB Bazel memory budget, 并采用 old-world LoongArch LP64 ABI 与 glibc 2.28。

支持 LASX 的 3A6000 可以构建全部三种 profile。只有在所有位置都使用 -mno-lasx 时,3A5000 profile 才是安全的。为 LA664 生成的 code 不能在 LA464 机器上执行验证。

准备 Python 与源码输入

TensorFlow 2.21.0 支持 CPython 3.13。reference build 使用 CPython 3.13.13, 并在干净的 CPython 3.13.14 环境中验证最终 wheel:

export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

pyenv install 3.13.13
pyenv install 3.13.14

Bazel build 使用顶层目录为 python/ 的 hermetic CPython 3.13.13 archive:

python-3.13.13-loongarch64.tar.gz
SHA-256 ca540b5ab4804d27fb8f6ddae1e4792fcf2b4050dfc88f22ed227fd5fc673b84

通过以下 repository setting 传入:

--repo_env=HERMETIC_PYTHON_VERSION=3.13
--repo_env=HERMETIC_PYTHON_URL=file:///path/to/python-3.13.13-loongarch64.tar.gz
--repo_env=HERMETIC_PYTHON_SHA256=ca540b5ab4804d27fb8f6ddae1e4792fcf2b4050dfc88f22ed227fd5fc673b84
--repo_env=HERMETIC_PYTHON_PREFIX=python

完整 wheel set 还需要从源码构建:

实验版 NumPy 从 adamdeprince/numpyloongson-experimental 分支 构建;reference build 固定在 commit 79b033101a38a0f1fa2c6b94380f31041f74da55

准备 Bazel override

TensorFlow 补丁会启用 LoongArch build,但 TensorFlow 的 external repository graph 仍需要支持 LoongArch 的 source snapshot。reference build 为以下项目提供 prepared override:

platforms
rules_python
eigen_archive
ducc
tf_runtime
io_bazel_rules_closure
build_bazel_rules_android
local_execution_config_python
local_config_python
local_execution_config_platform
system_python
cpuinfo
skcms
png
pybind11_protobuf
pybind11_abseil
boringssl
org_brotli
hwloc

使用 --override_repository=name=/absolute/source/path 传入每个目录。对于 grpcio、 optree、h5py、SciPy、libclang 和 TensorBoard data server 等不支持 LoongArch 的 预编译 x86/AArch64 PyPI repository,请使用空的本地 repository stub,防止 foreign wheel 进入 LoongArch build graph。

consolidated TensorFlow patch 不会嵌入这些 third-party source tree。分发任何 build kit 时,请保留其许可证和 source revision 记录。

构建与目标匹配的 static C++ runtime

TensorFlow 约 2 GiB 的 shared library 超出了 LoongArch normal code model 的 范围。请从 GCC 15.2 source 重新构建 PIC、medium-model libstdc++.a,并使用 上表中选定的同一套 CPU flag:

gcc_root=/opt/loongson-gcc-15.2.0
source_root=/path/to/gcc-15.2.0
build_root=/path/to/libstdcxx-build
prefix=/path/to/target-libstdcxx
cpu_flags='-march=la464 -mtune=la464 -mlsx -mno-lasx'  # 从表中选择
common_flags="-O2 -g0 -fPIC -mcmodel=medium $cpu_flags"
bits_include="$gcc_root/include/c++/15.2.0/loongarch64-linux-gnu/bits"

mkdir -p "$build_root"
cd "$build_root"
CC="$gcc_root/bin/gcc" \
CXX="$gcc_root/bin/g++" \
CFLAGS="$common_flags" \
CXXFLAGS="$common_flags -I$bits_include" \
  "$source_root/libstdc++-v3/configure" \
    --prefix="$prefix" \
    --build=loongarch64-linux-gnu \
    --host=loongarch64-linux-gnu \
    --disable-multilib \
    --disable-shared \
    --enable-static \
    --disable-libstdcxx-pch \
    --enable-libstdcxx-threads

make -j4
make install
test -f "$prefix/lib/libstdc++.a"

target 与 host link 都要使用此 archive 和 -static-libstdc++。保持 libgcc_s.so.1 为 dynamic;如果强制把安装好的 libgcc_eh.a 加入大型 TensorFlow link,可能再次出现 normal-model relocation overflow。

对 LA464/LSX profile,请先反汇编 archive,并拒绝其中的任何 LASX instruction。 对 LASX profile,请确认存在有代表性的 LASX instruction,并在 compatible host 上执行验证。

构建 native dependency wheel

为选定 profile 创建干净的 CPython 3.13.13 virtual environment。通过 CFLAGSCXXFLAGS 和各 build system 的专用 option,把所选 flag 传给每个 native project:

export CFLAGS="-O2 -g0 -fPIC -mcmodel=medium $cpu_flags"
export CXXFLAGS="$CFLAGS"

先构建 standard NumPy、HDF5/h5py、ml_dtypes、optree 与 grpcio wheel,再构建 TensorFlow。需要时,可单独构建实验版 NumPy。

三种 profile 的 NumPy Meson option 都保持 -Dcpu-baseline=LSX,因为 NumPy 将 LSX 而非 LASX 暴露为命名的 LoongArch baseline。是否允许生成 LASX code 仍由全局 compiler flag 控制。3A5000/3B5000 build 必须保留 -mno-lasx

把 private C++ runtime 静态链接进 ml_dtypes 时,请使用:

-Wl,--exclude-libs,libstdc++.a

这样可以防止 private static C++ symbol 在 import order 改变时 interpose 到 TensorFlow、grpcio、optree 或其他 extension。

配置并构建 TensorFlow

target 和 host action 都使用 GCC 15.2。reference build 的 common Bazel configuration 包括:

--enable_workspace
--noenable_bzlmod
--config=opt
--config=nogcp
--config=nonccl
--config=clang_local
--define=tflite_with_ruy=true
--define=tensorflow_mkldnn_contraction_kernel=0
--platforms=//:linux_loongarch64
--host_platform=//:linux_loongarch64
--repo_env=TF_DOWNLOAD_CLANG=0
--repo_env=USE_PYWRAP_RULES=1
--repo_env=WHEEL_NAME=tensorflow
--local_resources=cpu=4
--local_resources=memory=10000
--jobs=4

选定 CPU profile 中的每个 flag 都要传入以下四种形式:

--copt=FLAG
--cxxopt=FLAG
--host_copt=FLAG
--host_cxxopt=FLAG

-mcmodel=medium 也要以全部四种形式传入。把与目标匹配的 static runtime 放在 search path 首位,并用于 target 与 host link:

--linkopt=-L/path/to/target-libstdcxx/lib
--host_linkopt=-L/path/to/target-libstdcxx/lib
--linkopt=/path/to/target-libstdcxx/lib/libstdc++.a
--host_linkopt=/path/to/target-libstdcxx/lib/libstdc++.a
--linkopt=-static-libstdc++
--host_linkopt=-static-libstdc++

先加入 --nobuild 执行 analysis-only pass,再编译 wheel:

bazel --output_base="$HOME/.cache/bazel/tf-2.21.0-TARGET" \
  build //tensorflow/tools/pip_package:wheel \
  "${bazel_args[@]}" --nobuild

bazel --output_base="$HOME/.cache/bazel/tf-2.21.0-TARGET" \
  build //tensorflow/tools/pip_package:wheel \
  "${bazel_args[@]}"

这里的 bazel_args 包含上述 common setting、hermetic Python setting、 repository override、compiler environment、选定 CPU flag 与 link flag。 请把 TARGET 替换为 la464-lsxla464-lasxla664-lasx;绝不能在 不同 profile 之间共享 output base。

验证并打包结果

请在新的 CPython 3.13.14 环境中测试 wheel。至少验证:

请把 TensorFlow 与同一 CPU profile 下构建的 dependency wheel 一起打包。不要把 某一 profile 的 TensorFlow wheel 与另一 profile 的 native dependency wheel 混在一起。release 中应记录 SHA-256 checksum、source revision、third-party license 与选定的 compiler flag。

常见失败模式