linux - 当 copts 包含空格时,如何使用 bazel 在 docker build 镜像上交叉编译 tensorflow-serving

标签 linux docker cross-compiling bazel tensorflow-serving

背景资料

我想在一些不支持标准 tensorflow 构建中使用的现代 cpu 指令的旧机器(目标系统)上运行 tensorflow-serving。我用过这些 instructions用于通过 docker 安装 tf-serving。但是我遇到了错误 Tensorflow Serving Illegal Instruction core dumped类似于 one on github .建议的解决方案是使用 docker build-image 在我的目标系统上编译二进制文件,描述为 here。 .

由于这部分与我的问题的重现有关,我将在此处复制相关命令:

git clone https://github.com/tensorflow/serving
cd serving
docker build --pull -t $USER/tensorflow-serving-devel -f tensorflow_serving/tools/docker/Dockerfile.devel .


这将编译带有 -march=native 标志的二进制文件。在我的慢速目标机器上的 docker 容器中并且可以正常工作。

目标系统信息

但是在我的旧机器上编译需要很长时间,我想使用我的另一台更强大的电脑来交叉编译二进制文件。我使用了 answer 中提供的命令找出我的目标系统所需的编译标志来复制构建标志-march=native这是在上述过程中隐式使用的默认标志。
gcc -### -E - -march=native 2>&1 | sed -r '/cc1/!d;s/(")|(^.* - )//g'

给了我以下标志:
-march=core2 -mmmx -mno-3dnow -msse -msse2 -msse3 -mssse3 -mno-sse4a -mcx16 -msahf -mno-movbe -mno-aes -mno-sha -mno-pclmul -mno-popcnt -mno-abm -mno-lwp -mno-fma -mno-fma4 -mno-xop -mno-bmi -mno-bmi2 -mno-tbm -mno-avx -mno-avx2 -mno-sse4.2 -mno-sse4.1 -mno-lzcnt -mno-rtm -mno-hle -mno-rdrnd -mno-f16c -mno-fsgsbase -mno-rdseed -mno-prfchw -mno-adx -mfxsr -mno-xsave -mno-xsaveopt -mno-avx512f -mno-avx512er -mno-avx512cd -mno-avx512pf -mno-prefetchwt1 -mno-clflushopt -mno-xsavec -mno-xsaves -mno-avx512dq -mno-avx512bw -mno-avx512vl -mno-avx512ifma -mno-avx512vbmi -mno-clwb -mno-mwaitx -mno-clzero -mno-pku --param l1-cache-size=32 --param l1-cache-line-size=64 --param l2-cache-size=2048 -mtune=core2

请特别注意末尾包含空格的以下标志:
 --param l1-cache-size=32 --param l1-cache-line-size=64 --param l2-cache-size=2048

我可以通过构建参数 TF_SERVING_BUILD_OPTIONS 在 docker 构建过程中提供这些标志。如 docs here 中所述

然后使用此字符串运行 bazel 构建,可以在 Dockerfile.devel 中看到。

因此,我从上面取出所有标志并将 --copt=将结果字符串放在变量 TF_SERVING_BUILD_OPTIONS 中.这是我的总命令,包括末尾带有空格的 copts:
docker build --pull \
    --build-arg TF_SERVING_BUILD_OPTIONS="--copt=-mmmx --copt=-mno-3dnow --copt=-msse --copt=-msse2 --copt=-msse3 --copt=-mssse3 --copt=-mno-sse4a --copt=-mcx16 --copt=-msahf --copt=-mno-movbe --copt=-mno-aes --copt=-mno-sha --copt=-mno-pclmul --copt=-mno-popcnt --copt=-mno-abm --copt=-mno-lwp --copt=-mno-fma --copt=-mno-fma4 --copt=-mno-xop --copt=-mno-bmi --copt=-mno-bmi2 --copt=-mno-tbm --copt=-mno-avx --copt=-mno-avx2 --copt=-mno-sse4.2 --copt=-mno-sse4.1 --copt=-mno-lzcnt --copt=-mno-rtm --copt=-mno-hle --copt=-mno-rdrnd --copt=-mno-f16c --copt=-mno-fsgsbase --copt=-mno-rdseed --copt=-mno-prfchw --copt=-mno-adx --copt=-mfxsr --copt=-mno-xsave --copt=-mno-xsaveopt --copt=-mno-avx512f --copt=-mno-avx512er --copt=-mno-avx512cd --copt=-mno-avx512pf --copt=-mno-prefetchwt1 --copt=-mno-clflushopt --copt=-mno-xsavec --copt=-mno-xsaves --copt=-mno-avx512dq --copt=-mno-avx512bw --copt=-mno-avx512vl --copt=-mno-avx512ifma --copt=-mno-avx512vbmi --copt=-mno-clwb --copt=-mno-mwaitx --copt=-mno-clzero --copt=--param l1-cache-size=32 --copt=--param l1-cache-line-size=64 --copt=--param l2-cache-size=2048 --copt=-mtune=core2" \
    -t $USER/tensorflow/serving-devel \
    -f tensorflow_serving/tools/docker/Dockerfile.devel .

问题

然而bazel提示如下,这可能是由于--param之间的空格。和 l1-cache-size=32这是提供给 bazel 构建调用的 C 编译器的一个选项。
ERROR: Skipping 'l1-cache-line-size=64': couldn't determine target from filename 'l1-cache-line-size=64'
ERROR: couldn't determine target from filename 'l1-cache-line-size=64'
INFO: Elapsed time: 20.233s
INFO: 0 processes.
FAILED: Build did NOT complete successfully (0 packages loaded)
The command '/bin/sh -c bazel build --color=yes --curses=yes     ${TF_SERVING_BAZEL_OPTIONS}     --verbose_failures     --output_filter=DONT_MATCH_ANYTHING     ${TF_SERVING_BUILD_OPTIONS}     tensorflow_serving/model_servers:tensorflow_model_server &&     cp bazel-bin/tensorflow_serving/model_servers/tensorflow_model_server     /usr/local/bin/' returned a non-zero code: 1

我试过的
  • 我尝试在最后一个标志中转义空格字符:
  • TF_SERVING_BUILD_OPTIONS="--copt=-mmmx ... --copt=--param\ l1-cache-size=32 --copt=--param\ l1-cache-line-size=64 --copt=--param\ l2-cache-size=2048 --copt=-mtune=core2 "
    

    但是 bazel 仍然提示与上面相同的错误消息。
  • 我尝试用双引号或单引号将命令括起来:
  • TF_SERVING_BUILD_OPTIONS="--copt=-mmmx ... --copt=\"--param l1-cache-size=32\" --copt=\"--param l1-cache-line-size=64\" --copt=\"--param l2-cache-size=2048\" --copt=-mtune=core2 "
    

    还会出现与以前相同的错误。
  • 我尝试对 copts 使用内部双引号并包装 TF_SERVING_BUILD_OPTIONS带有外部单引号但相同的错误。
  • 我尝试使用 \x22 转义来自 copts 的双引号。 .出现与之前类似的错误。这次表明目标格式不正确ERROR: Skipping 'l1-cache-size=32\x22': Bad target pattern...
  • 我尝试使用 \40 转义空格字符:
  • TF_SERVING_BUILD_OPTIONS="--copt=-mmmx ... --copt=--param\40l1-cache-size=32 --copt=--param\40l1-cache-line-size=64 --copt=--param\40l2-cache-size=2048 --copt=-mtune=core2 "
    

    这次 bazel 没有提示,因为 copt 的参数是一个没有正常空格的字符串。但是,参数被错误地传递给 gcc,因为我收到以下错误:
    ERROR: /root/.cache/bazel/_bazel_root/e53bbb0b0da4e26d24b415310219b953/external/grpc/BUILD:692:1: C++ compilation of rule '@grpc//:grpc_base_c' failed (Exit 1): gcc failed: error executing command 
      (cd /root/.cache/bazel/_bazel_root/e53bbb0b0da4e26d24b415310219b953/execroot/tf_serving && \
      exec env - \
        PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
        PWD=/proc/self/cwd \
        PYTHON_BIN_PATH=/usr/bin/python \
      /usr/bin/gcc -U_FORTIFY_SOURCE -fstack-protector -Wall -Wunused-but-set-parameter -Wno-free-nonheap-object -fno-omit-frame-pointer -g0 -O2 '-D_FORTIFY_SOURCE=1' -DNDEBUG -ffunction-sections -fdata-sections '-std=c++0x' -MD -MF bazel-out/k8-opt/bin/external/grpc/_objs/grpc_base_c/endpoint_pair_uv.d '-frandom-seed=bazel-out/k8-opt/bin/external/grpc/_objs/grpc_base_c/endpoint_pair_uv.o' '-DGRPC_ARES=0' -iquote external/grpc -iquote bazel-out/k8-opt/genfiles/external/grpc -iquote bazel-out/k8-opt/bin/external/grpc -iquote external/zlib_archive -iquote bazel-out/k8-opt/genfiles/external/zlib_archive -iquote bazel-out/k8-opt/bin/external/zlib_archive -isystem external/grpc/include -isystem bazel-out/k8-opt/genfiles/external/grpc/include -isystem bazel-out/k8-opt/bin/external/grpc/include -isystem external/zlib_archive -isystem bazel-out/k8-opt/genfiles/external/zlib_archive -isystem bazel-out/k8-opt/bin/external/zlib_archive -mmmx -mno-3dnow -msse -msse2 -msse3 -mssse3 -mno-sse4a -mcx16 -msahf -mno-movbe -mno-aes -mno-sha -mno-pclmul -mno-popcnt -mno-abm -mno-lwp -mno-fma -mno-fma4 -mno-xop -mno-bmi -mno-bmi2 -mno-tbm -mno-avx -mno-avx2 -mno-sse4.2 -mno-sse4.1 -mno-lzcnt -mno-rtm -mno-hle -mno-rdrnd -mno-f16c -mno-fsgsbase -mno-rdseed -mno-prfchw -mno-adx -mfxsr -mno-xsave -mno-xsaveopt -mno-avx512f -mno-avx512er -mno-avx512cd -mno-avx512pf -mno-prefetchwt1 -mno-clflushopt -mno-xsavec -mno-xsaves -mno-avx512dq -mno-avx512bw -mno-avx512vl -mno-avx512ifma -mno-avx512vbmi -mno-clwb -mno-mwaitx -mno-clzero '--param\40l1-cache-size=32' '--param\40l1-cache-line-size=64' '--param\40l2-cache-size=2048' '-mtune=core2' '-std=c++14' '-D_GLIBCXX_USE_CXX11_ABI=0' -fno-canonical-system-headers -Wno-builtin-macro-redefined '-D__DATE__="redacted"' '-D__TIMESTAMP__="redacted"' '-D__TIME__="redacted"' -c external/grpc/src/core/lib/iomgr/endpoint_pair_uv.cc -o bazel-out/k8-opt/bin/external/grpc/_objs/grpc_base_c/endpoint_pair_uv.o)
    Execution platform: @bazel_tools//platforms:host_platform
    gcc: error: unrecognized command line option '--param\40l1-cache-size=32'
    gcc: error: unrecognized command line option '--param\40l1-cache-line-size=64'
    gcc: error: unrecognized command line option '--param\40l2-cache-size=2048'
    Target //tensorflow_serving/model_servers:tensorflow_model_server failed to build
    

    好像这和下面的issue on github有关.
  • 我尝试了没有包含空格的标志的编译,并且完成得很好,这加强了错误是由于从 bazel 错误处理的空间引起的假设。

  • 我该如何解决这个问题?

    最佳答案

    I would like to run tensorflow-serving on some older machine (target system) which doesn't support modern cpu instructions used in the standard tensorflow build. I used these instructions for installing tf-serving via docker. However I ran into the error Tensorflow Serving Illegal Instruction core dumpedsimilar to this one on github...



    Bazel 和 TensorFlow 使用 -march=native如果我没记错的话,默认情况下在其构建标志中。

    您应该省略该标志,或指定更合适的标志,如 -march=sse4.2 .

    -march=core2 -mmmx -mno-3dnow -msse -msse2 -msse3 -mssse3 -mno-sse4a -mcx16 -msahf
    -mno-movbe -mno-aes -mno-sha -mno-pclmul -mno-popcnt -mno-abm -mno-lwp -mno-fma
    -mno-fma4 -mno-xop -mno-bmi -mno-bmi2 -mno-tbm -mno-avx -mno-avx2 -mno-sse4.2
    -mno-sse4.1 -mno-lzcnt -mno-rtm -mno-hle -mno-rdrnd -mno-f16c -mno-fsgsbase
    -mno-rdseed -mno-prfchw -mno-adx -mfxsr -mno-xsave -mno-xsaveopt -mno-avx512f
    -mno-avx512er -mno-avx512cd -mno-avx512pf -mno-prefetchwt1 -mno-clflushopt -mno-xsavec
    -mno-xsaves -mno-avx512dq -mno-avx512bw -mno-avx512vl -mno-avx512ifma -mno-avx512vbmi
    -mno-clwb -mno-mwaitx -mno-clzero -mno-pku --param l1-cache-size=32
    --param l1-cache-line-size=64 --param l2-cache-size=2048 -mtune=core2
    


    您的转储显示 -mno-sse4.1 .我相信这意味着您可以使用以下内容并完成它。
    -msse2 -msse3 -mssse3
    

    x86_64 将 SSE2 作为核心指令集的一部分,因此它暗示了 MMX 和 SSE。

    我认为你不应该使用 -march=core2-mtune=core2因为Core2意味着你有SSE4.1(早期的iCore cpus)或SSE4.2(后来的iCore cpus)。

    来自 x86_64 options 的 GCC 手册页这对我来说看起来很可疑/错误:

    core2

    Intel Core2 CPU with 64-bit extensions, MMX, SSE, SSE2, SSE3 and SSSE3 instruction set support.



    我相当肯定 Core2 比 SSSE3 更有能力。我保留了几台 Core2 机器进行测试,它们有 SSE4.1 和 SSE4.2。 (我相信有 CRC 指令,即 SSE4.2 ISA )。

    我可能对 GCC 选项页面有误,但对我来说它看起来很可疑。

    Tensorflow Serving Illegal Instruction core dumped



    什么是非法指令?

    gcc -### -E - -march=native 2>&1 | sed -r '/cc1/!d;s/(")|(^.* - )//g'



    只是另一种观点,但我发现这样的东西更有用。从 Skylake 机器:

    $ gcc -march=native -dM -E - </dev/null | grep -E 'SSE|CRC|AES|PCL|RDRND|RDSEED|AVX' | sort
    #define __AES__ 1
    #define __AVX__ 1
    #define __AVX2__ 1
    #define __PCLMUL__ 1
    #define __RDRND__ 1
    #define __RDSEED__ 1
    #define __SSE__ 1
    #define __SSE2__ 1
    #define __SSE2_MATH__ 1
    #define __SSE3__ 1
    #define __SSE4_1__ 1
    #define __SSE4_2__ 1
    #define __SSE_MATH__ 1
    #define __SSSE3__ 1
    

    从预处理器转储中,我知道我可以使用 -msse2 , -msse3 , -mssse3 , -msse4.1 , -msse4.2 , -mavx-mavx2 .

    从 Core2 机器:

    $ gcc -march=native -dM -E - </dev/null | grep -E 'SSE|CRC|AES|PCL|RDRND|RDSEED|AVX' | sort
    #define __SSE__ 1
    #define __SSE2__ 1
    #define __SSE2_MATH__ 1
    #define __SSE3__ 1
    #define __SSE4_1__ 1
    #define __SSE_MATH__ 1
    #define __SSSE3__ 1
    

    从预处理器转储中,我知道我可以使用 -msse2 , -msse3 , -mssse3-msse4.1 .

    在另一台 Core2 机器上:

    $ gcc -march=native -dM -E - </dev/null | grep -E 'SSE|CRC|AES|PCL|RDRND|RDSEED|AVX' | sort
    #define __SSE2_MATH__ 1
    #define __SSE2__ 1
    #define __SSE3__ 1
    #define __SSE4_1__ 1
    #define __SSE_MATH__ 1
    #define __SSE__ 1
    #define __SSSE3__ 1
    

    从预处理器转储中,我知道我可以使用 -msse2 , -msse3 , -mssse3-msse4.1 .

    随着所有的漫无边际,这对我来说看起来很可疑。什么文件名?该选项指定缓存行大小。你错过了--选择?
    ERROR: Skipping 'l1-cache-line-size=64': couldn't determine target from filename 'l1-cache-line-size=64'
    ERROR: couldn't determine target from filename 'l1-cache-line-size=64'
    

    关于linux - 当 copts 包含空格时,如何使用 bazel 在 docker build 镜像上交叉编译 tensorflow-serving,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59098232/

    相关文章:

    linux - 适用于嵌入式设备的视频 session 堆栈

    linux - 更改查找命令的输出

    docker - 无法将诗歌包上传到本地 dockerized pypiserver

    linux - 如何在 Linux Ubuntu 16 上安装 luasql?

    r - TCGA2STAT R 包在 windows 中不起作用 : How to resolve?

    Docker 构建步骤名称不能以数字开头

    linux - 如何自定义 golang-docker 镜像以使用 golang 进行脚本编写?

    c++ - 对静态成员的 undefined reference

    erlang - 在 Xeon Phi 上运行 Erlang

    ios - 为 iOS 交叉编译 libogg