如何在 Intel x86 服务器上构建 IBM PowerLinux 应用程序
IBM® Advanced Toolchain for PowerLinux 交叉编译器的实际价值在于,开发人员可在他们已熟悉的开发平台上(在大多数情况下是 x86)编译和构建 IBM Power Architecture® 应用程序。本文将介绍开发人员如何使用 Toolchain 交叉编译器,轻松地构建在 Power Architecture 上运行的源代码。本文还会回答有关交叉编译的应用程序性能、功能和在 IBM PowerLinux™ 服务器上原生地调试交叉编译应用程序的能力的问题。
简介
将在 x86 服务器上运行的 Linux® 应用程序移植到另一个平台上,比如 PowerLinux,需要设置一个不同的构建环境来编译该应用程序,是吗?没有必要。您可以在 x86 服务器上使用交叉编译器,构建针对一种不同平台架构(比如 IBM Power®)的应用程序二进制文件。交叉编译器已存在很长时间。它们主要用于为具有有限的资源的嵌入式系统构建应用程序,以便运行能够支持原生编译器的操作系统。我第一次了解交叉编译器是在参与一个针对手持设备的项目的时候。我在 x86 工作站上编写并编译源代码,并通过一个串行通信连接来将这些二进制文件加载到设备中。最近,我正在使用交叉编译器构建简单的应用程序,以便控制我所研究的一个遥控设备的伺服电动机。好了,我们进入正题。
本文将介绍 IBM Advance Toolchain for PowerLinux 中包含的交叉编译器。从这里开始,我会将 IBM Advance Toolchain for PowerLinux 称为 “toolchain”。toolchain 是一组开源开发工具和运行时库,它使用户能够在 Linux 上利用 IBM 最新的 Power 硬件特性。toolchain 本身是自成一体的,不依赖于系统 toolchain。它安装在 /opt
中,所以不会覆盖默认的 Linux 发行版 toolchain。截至撰写本文时,最新版本包含以下包的最新稳定版本:
- GNU Compiler Collection(gcc、g++ 和 gfortran),以及各个针对支持的 IBM POWER® 处理器而优化的 gcc 运行时
- GNU C 库 (glibc),单独针对支持的 POWER 处理器而进行了优化
- GNU 二进制实用程序 (binutils)
- 十进制浮点库 (libdfp),进行了优化,添加了对基于 IBM POWER7® 和 IBM POWER8™ 处理器的服务器的硬件 DFP 支持
- AUXV 库 (libauxv)
- GNU 调试器 (gdb)
- 性能分析工具(oprofile、valgrind 和 itrace)
- 多核利用库(Intel® TBB、Userspace RCU),从 5.0-3 版本开始
- 以及多个支持库(比如 libhugetlbfs、zlib 等)
有关下载 toolchain 的信息,请参阅本文末尾的参考资料节。
出于本文的目的,我们将主要介绍 toolchain 交叉编译器。本文介绍如何使用 toolchain 交叉编译器,在 x86 服务器上构建适合 PowerLinux 的二进制可执行程序。文中还回答了以下问题。
- 在 x86 平台上构建的交叉编译应用程序,执行性能有在 PowerLinux 上原生构建的二进制程序那么好吗?
- 在 x86 平台上构建的交叉编译应用程序和库,是否拥有与在 PowerLinux 上构建的应用程序相同的应用程序二进制功能?
- 在 x86 平台上构建的交叉编译应用程序,是否会生成可在 PowerLinux 上执行原生调试的二进制程序?
为了回答这些问题,我使用了两个流行的开源应用程序 PostgreSQL 和 Apache httpd 服务器。PostgreSQL 和 Apache httpd 源代码发行版都是在 x86 服务器上使用 toolchain 交叉编译器来构建的,而且在 PowerLinux 服务器上是原生构建的。然后,这些应用程序被安装在一个 PowerLinux 服务器上的不同安装目录中并运行。我对这些应用程序运行了两个基准测试工具,比较了它们的性能和功能。
测试的结果将在以下各节中介绍。对于对重新创建测试感兴趣的读者,环境和配置 和 使用 toolchain 构建应用程序 节中分别介绍了环境配置和如何构建这些应用程序的信息。
结果
为了测试这些应用程序,我使用了一些公开的基准测试工具。对于 PostgreSQL,我使用了来自 GitHub 的 pgbench-tool。它使用了 PostgreSQL 源代码发行版随带的 pgbench 工具。对于 Apache httpd,我使用了 Apache httpd 源代码发行版随带的 apache bench (ab) 工具。请查阅本文底部的参考资料节,了解下载 pgbench-tools 的地方的信息。
PostgreSQL 测试设置和结果
在 x86 服务器上使用交叉编译器构建 PostgreSQL 应用程序后,完整的二进制程序集合被转移到一个 PowerLinux 服务器上。我们对默认的配置文件进行了以下修改:
Postgresql.conf max_connections = 4096 shared_buffers = 2048MB synchronous_commit = off checkpoint_segments = 3 checkpoint_timeout = 5min
修改 PowerLinux 系统设置的 kernel.sem
值。
sysctl.conf kernel.sem = 250 32000 32 12288
修改 pgbench-tools 的配置文件
MAX_WORKERS="32"。
根据 pgbench-tools 网站中的介绍,PostgreSQL 测试按照以下步骤运行:
- 创建 pgbench 和 results 数据库。
- 初始化 results 数据库。
- 创建一个包含描述的测试集。
- 使用 runset 脚本运行测试。
- 编译并提交测试结果。
有关执行这些步骤时使用的具体信息,请参阅 pgbench-tools 自述文件。
Postgresql 结果(交叉编译)
以下是在 Power 服务器上对交叉编译的二进制程序运行 pgbench-tools 的结果。
图 1. 交叉编译的 PostgreSQL 二进制程序的比例系数
该比例系数显示了随着数据库大小的增长,每秒处理的事务数的变化趋势。绿线表示数据库大小 (MB),红线表示每秒处理的事务数。该图表明,随着数据库大小增加,每秒处理的事务数将会下降。
图 2. 交叉编译的 PostgreSQL 二进制程序的可伸缩性图
图 2 显示了可伸缩性图。它表明随着客户端数量增加,每秒处理的事务数也会增加。
PostgreSQL 结果(原生编译)
测试原生编译的二进制程序时,使用了与交叉编译的 PostgreSQL 完全相同的配置设置和数据库位置 (/tmp/usr/local/pgsql/data)。要确保数据库是干净的,在开始测试之前请丢弃 results 和 pgbench 数据库。
Postgresql# drop database results;
DROP DATABASE
postgresql# drop database pgbench;
DROP DATABASE
比例系数和可伸缩性图如 图 3 和 图 4 所示。正如之前所提到的,该比例系数显示了随着数据库大小的增长,每秒处理的事务数的变化趋势。绿线表示数据库大小 (MB),红线表示每秒处理的事务数。
图 3. 原生构建的 PostgreSQL 二进制程序的比例系数
图 4 中的可伸缩性图显示,随着客户端数量增加,每秒处理的事务数也会增加。
图 4. 原生构建的 PostgreSQL 二进制程序的可伸缩性图
您可以注意到,交叉编译的二进制程序的曲线图与原生编译的二进制程序的曲线图非常相似。这个简单测试表明,x86 服务器上的交叉编译可得到拥有与原生编译的代码相同的性能特征的二进制程序。
Apache httpd 测试设置和结果
为了测试 Apache httpd,我使用了 Apache httpd 源代码发行版随带的基准测试工具 ab。类似于 PostgreSQL,Apache httpd 是使用 toolchain 交叉编译器构建的,并将二进制程序传输到 PowerLinux 服务器。我修改了默认的 httpd.conf 文件,以便将 htdocs 目录更改为指向本地文档目录。剩余设置保留默认值。
我用于运行 ab 工具的命令行和参数如下:
#./ab -n 500000 -c 100 -g out1.data http://9.3.4.241/
我运行该命令 3 次,将输出写入到 out1.data、out2.data 和 out3.data,并使用 gnuplot 实用程序和 benchmark.tpl 文件中的参数描绘了这些文件的图像,如下所示。
# gnuplot benchmark.tpl benchmark.tpl # output as png image set terminal png # save file to "benchmark.png" set output "benchmark.png" # graph title set title "Benchmark for 9.3.4.241" # aspect ratio for image size set size 1,1 # enable grid on y-axis set grid y # x-axis label set xlabel "Request" # y-axis label set ylabel "Response Time (ms)" # plot data using column 10 with smooth sbezier lines plot "out1.data" using 10 smooth sbezier with lines title "Benchmark 1:", \ "out2.data" using 10 smooth sbezier with lines title "Benchmark 2:", \ "out3.data" using 10 smooth sbezier with lines title "Benchmark 3:"
有关 Apache 基准测试工具的更多信息,请参阅本文末尾的 参考资料 部分。
Apache httpd 结果(原生编译和交叉编译)
gnuplot 实用程序为每个测试生成一个名为 benchmark.png 的文件。这些图可以使用任何图像查看器进行查看。两幅图如 图 5 和 图 6 所示。
图 5 显示了原生编译的 httpd 的曲线图。
图 5. 原生编译的 httpd 的响应时间曲线图
图 6 显示了交叉编译的 httpd 的曲线图。
图 6. 交叉编译的 httpd 的响应时间曲线图
您可以注意到,两个曲线图显示出了非常相似的性能特征。读者可以使用不同的 Web 文档和���据执行更多测试。
回页首
功能和调试发现
除了性能之外,开发人员可能还有其他与 toolchain 交叉编译器的使用相关的问题。本节回答了与功能和调试交叉编译的二进制程序的能力相关的问题。这些问题是:
- 交叉编译器构建的二进制程序,在功能上是否与原生构建的可执行程序兼容?
- 交叉编译的二进制程序能否在 PowerLinux 服务器上进行调试?
接下来的两个简单用例有助于回答这些问题。
- 用例 1:将一个原生构建的 httpd 的一个或多个共享库替换为使用 toolchain 交叉编译器构建的共享库。查看原生构建的 httpd 是否仍能正常运行。
- 用例 2:在 PowerLinux 服务器上,将一个正在运行的进程附加一个调试器。该进程是一个从 x86 服务器构建的交叉编译的二进制可执行程序。设置一个断点,设置源代码目录,并执行一组函数。
用例 1:功能测试
以下是我在用例 1 中遵循的操作说明:
- 将原生构建的 httpd 安装在 /home/usr/local 中。
- 对 /home/use/local/bin/httpd 二进制程序运行 ldd 实用程序,以显示它的共享二进制依赖项。您可以注意到,libaprutil-1.so.0 和 libapr-1.so.0 都位于 /home/usr/local/lib 中。这些库是 httpd 需要的原生编译的库的一部分。
[root@localhost lib]# ldd ../../bin/httpd linux-vdso64.so.1 => (0x00000fffa1140000) libaprutil-1.so.0 => /home/usr/local/apr/lib/libaprutil-1.so.0 (0x00000fffa10c0000) libapr-1.so.0 => /home/usr/local/apr/lib/libapr-1.so.0 (0x00000fffa1060000) librt.so.1 => /opt/at7.0-5-rc1/lib64/power7/librt.so.1 (0x00000fffa1040000) libcrypt.so.1 => /opt/at7.0-5-rc1/lib64/power7/libcrypt.so.1 (0x00000fffa0ff0000) libpthread.so.0 => /opt/at7.0-5-rc1/lib64/power7/libpthread.so.0 (0x00000fffa0fb0000) libdl.so.2 => /opt/at7.0-5-rc1/lib64/power7/libdl.so.2 (0x00000fffa0f90000) libc.so.6 => /opt/at7.0-5-rc1/lib64/power7/libc.so.6 (0x00000fffa0da0000) /opt/at7.0-5-rc1/lib64/ld64.so.1 => /lib64/ld64.so.1 (0x00000000267a0000)
- 删除共享库 libaprutil-1.so.0 和 libapr-1.so.0。
- 将交叉编译的库 libaprutil-1.so.0 和 libapr-1.so.0 复制到 /tmp/usr/local/lib 中。
- 将 /tmp/usr/local/lib 包含在 LD_LIBRARY_PATH 中。
# cd /home/usr/local/apr/lib # rm libaprutil-1.so.0 # rm libapr-1.so.0 # export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/tmp/usr/local/lib
- 再次运行 ldd 实用程序,可以看到 httpd 现在使用了 /tmp/usr/local/lib 中的库。
[root@localhost lib]# ldd ../../bin/httpd linux-vdso64.so.1 => (0x00000fff951a0000) libaprutil-1.so.0 => /tmp/usr/local/apr/lib/libaprutil-1.so.0 (0x00000fff95150000) libapr-1.so.0 => /tmp/usr/local/apr/lib/libapr-1.so.0 (0x00000fff950f0000) librt.so.1 => /opt/at7.0-5-rc1/lib64/power7/librt.so.1 (0x00000fff950d0000) libcrypt.so.1 => /opt/at7.0-5-rc1/lib64/power7/libcrypt.so.1 (0x00000fff95080000) libpthread.so.0 =>/opt/at7.0-5-rc1/lib64/power7/libpthread.so.0 (0x00000fff95040000) libdl.so.2 => /opt/at7.0-5-rc1/lib64/power7/libdl.so.2 (0x00000fff95020000) libc.so.6 => /opt/at7.0-5-rc1/lib64/power7/libc.so.6 (0x00000fff94e30000) libexpat.so.0 => /tmp/usr/local/apr/lib/libexpat.so.0 (0x00000fff94df0000) /opt/at7.0-5-rc1/lib64/ld64.so.1 => /lib64/ld64.so.1 (0x0000000022730000)
- 启动应用程序,以查看它是否能像正常应用程序一样运行。
# cd /home/usr/local/bin # ./apachectl start # ps –ef | grep http root 11022 1 0 15:41 ?00:00:00 /home/usr/local/bin/httpd -k start daemon 11023 11022 0 15:41 ?00:00:00 /home/usr/local/bin/httpd -k start daemon 11024 11022 0 15:41 ?00:00:00 /home/usr/local/bin/httpd -k start daemon 11025 11022 0 15:41 ?00:00:00 /home/usr/local/bin/httpd -k start daemon 11111 11022 0 15:41 ?00:00:00 /home/usr/local/bin/httpd -k start
- 在浏览器中打开运行 httpd 进程的 PowerLinux 服务器,查看浏览器上是否显示了以下消息:
它起作用了!
在此场景中,我们结合使用了一个原生编译的库和交叉编译的库。交叉编译的库是使用 ppc64 架构选项构建的。在此用例中我们可以证明,我们可以在 PowerLinux 服务器上结合使用交叉编译的库和原生编译的可执行程序。
用例 2:调试
在第二个用例中,我们尝试证明交叉编译的可执行程序可以在 PowerLinux 服务器上进行调试。以下是我在用例 2 中遵循的操作说明:
- 使用 gdb,附加到 httpd 进程。确保使用的 httpd 版本是 toolchain 交叉编译器在 x86 平台上构建的版本。
[root@localhost ~]# gdb attach 25412 GNU gdb (GDB) 7.6.50.20130722-cvs Copyright (C) 2013 Free Software Foundation, Inc. License GPLv3+:GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.Type "show copying" and "show warranty" for details. This GDB was configured as "powerpc64-linux". … (gdb)
- 将目录设置到源代码发行版。
(gdb) set directories /home/ProjectToolchainPLCompile/apr-1.5.1 (gdb) where #0 0x00000fff7cb676f8 in ___newselect_nocancel () at ../sysdeps/unix/syscall-template.S:81 #1 0x00000fff7cd38274 in apr_sleep (t=<optimized out>) at time/unix/time.c:246 #2 0x0000000010034220 in ap_wait_or_timeout (status=0xfffeaa1e704, exitcode=0xfffeaa1e700, ret=0xfffeaa1e6e0, p=0x1003d0c6138, s=<optimized out>) at mpm_common.c:195 #3 0x0000000010079238 in server_main_loop (remaining_children_to_start=<optimized out>) at worker.c:1654 #4 worker_run (_pconf=<optimized out>, plog=<optimized out>, s=<optimized out>) at worker.c:1823 #5 0x0000000010033430 in ap_run_mpm (pconf=0x1003d0c6138, plog=0x1003d0f3378, s=0x1003d0ef4c0) at mpm_common.c:96 #6 0x000000001002a5d8 in main (argc=3, argv=0xfffeaa1ee28) at main.c:777
- 将一个函数移动到
apr_sleep
。
(gdb) up #1 0x00000fff7cd38274 in apr_sleep (t=<optimized out>) at time/unix/time.c:246 246 select(0, NULL, NULL, NULL, &tv);
- 列出
apr_sleep
的源代码。
(gdb) list 241 delay(t/1000); 242 #else 243 struct timeval tv; 244 tv.tv_usec = t % APR_USEC_PER_SEC; 245 tv.tv_sec = t / APR_USEC_PER_SEC; 246 select(0, NULL, NULL, NULL, &tv); 247 #endif 248 } 249 250 #ifdef OS2
- 与该进程分离。
(gdb) detach Detaching from program:/tmp/usr/local/bin/httpd, process 25412 (gdb) quit
远程调试
toolchain 还包含 gdbserver 程序。它允许开发人员从一个远程 gdb 会话连接到他们的应用程序。请确保在 PowerLinux 服务器上调用 gdbserver 程序时,您使用了来自 toolchain 的 gdb。对我而言,一定要检查它是否在我的路径上。
# type gdbserver gdbserver is hashed (/opt/at7.0-5-rc1/bin/gdbserver)
这是在 PowerLinux 服务器上使用 gdbserver 程序的一个例子。我们将附加到一个正在运行的 httpd 进程:
[root@stgisv241 bin]# gdbserver --attach 9.3.4.240:2345 22589 Attached; pid = 22589 Listening on port 2345
在 x86 服务器上,对本地服务器上的 httpd 二进制程序调用 powerpc64-linux-gdb 程序。请注意,来自 toolchain 的 gdb 版本名为 powerpc64-linux-gdb。使用的 httpd 二进制程序是 PowerLinux 服务器上运行的同一个交叉编译的二进制程序版本。
# pwd /tmp/usr/local/bin [root@stgisv240 bin]# powerpc64-linux-gdb ./httpd GNU gdb (GDB) 7.6.50.20130722-cvs Copyright (C) 2013 Free Software Foundation, Inc. License GPLv3+:GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.Type "show copying" and "show warranty" for details. This GDB was configured as "--host=i686-linux --target=powerpc64-linux". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word". .. Reading symbols from /tmp/usr/local/bin/httpd...done. (gdb)
仍在 x86 gdb 会话上,在 gdb 内调用目标命令,如下面的示例所示。
(gdb) target remote 9.3.4.241:2345 Remote debugging using 9.3.4.241:2345 warning:Could not load shared library symbols for 7 libraries, e.g. /opt/at7.0-5-rc1/lib64/power7/librt.so.1. Use the "info sharedlibrary" command to see the complete listing. Do you need "set solib-search-path" or "set sysroot"? Reading symbols from /tmp/usr/local/apr/lib/libaprutil-1.so.0...done. Loaded symbols for /tmp/usr/local/apr/lib/libaprutil-1.so.0 Reading symbols from /tmp/usr/local/apr/lib/libexpat.so.0...done. Loaded symbols for /tmp/usr/local/apr/lib/libexpat.so.0 Reading symbols from /tmp/usr/local/apr/lib/libapr-1.so.0...done. Loaded symbols for /tmp/usr/local/apr/lib/libapr-1.so.0 …. Reading symbols from /tmp/usr/local/modules/mod_alias.so...done. Loaded symbols for /tmp/usr/local/modules/mod_alias.so warning:Unable to find dynamic linker breakpoint function. GDB will be unable to debug shared library initializers and track explicitly loaded dynamic code. 0x00000fffa8fe76f8 in ??() (gdb)
可以看到一些与 gdb 无法找到库符号相关的警告消息。 gdb 命令 info sharedlibrary
显示了 gdb 未能从中读取符号的库。下面的示例输出显示了 gdb 未能从中读取符号的库。请注意,这些库是系统的一部分,除非它们在编译时打开了符号,否则您无需担忧它们。
(gdb) info sharedlibrary From To Syms Read Shared Object Library No linux-vdso64.so.1 0x00000fffa924ce80 0x00000fffa927e8a8 Yes /tmp/usr/local/apr/lib/libaprutil-1.s 0x00000fffa91f7940 0x00000fffa922aa18 Yes /tmp/usr/local/apr/lib/libexpat.so.0 0x00000fffa9192e60 0x00000fffa91ca0b8 Yes /tmp/usr/local/apr/lib/libapr-1.so.0 No /opt/at7.0-5-rc1/lib64/power7/librt.s No /opt/at7.0-5-rc1/lib64/power7/libcrypt No /opt/at7.0-5-rc1/lib64/power7/libdl.s No /opt/at7.0-5-rc1/lib64/power7/libpthre No /opt/at7.0-5-rc1/lib64/power7/libc.so No /opt/at7.0-5-rc1/lib64/ld64.so.1 No /opt/at7.0-5-rc1/lib64/power7/libnss_f 0x00000fffa8ea0c00 0x00000fffa8ea1878 Yes /tmp/usr/local/modules/mod_authn_file 0x00000fffa8e810a0 0x00000fffa8e82108 Yes /tmp/usr/local/modules/mod_authn_core. 0x00000fffa8e60da0 0x00000fffa8e61bb0 Yes /tmp/usr/local/modules/mod_authz_host. 0x00000fffa8e40f40 0x00000fffa8e41ed0 Yes /tmp/usr/local/modules/mod_authz_group 0x00000fffa8e208e0 0x00000fffa8e20f18 Yes /tmp/usr/local/modules/mod_authz_user. 0x00000fffa8e019e0 0x00000fffa8e046d8 Yes /tmp/usr/local/modules/mod_authz_core. ...
如用例 2 所示,可以在调试原生编译的可执行程序的 PowerLinux 服务器上本地或远程调试交叉编译的可执行程序。另外,可以注意到二进制程序使用 –g
选项来编译,以便生成调试信息。