英特尔® C++ 编译器支持的 OpenMP* 4.0 设备构造可以通过外设组件接口 Express*(PCIe*)将工作负载从基于英特尔® 至强® 处理器的主机卸载至英特尔® 至强融核™ 协处理器。Offload over Fabric (OoF) 可以扩展这个卸载编程模型,以支持第二代 英特尔® 至强融核™ 处理器,也就是说,基于英特尔® 至强® 处理器的主机可以通过 OoF、利用高速网络(如英特尔® Omni-Path 架构 (Intel® OPA) 或 Mellanox InfiniBand*)将工作负载卸载至第二代至强融核处理器。
本教程展示了如何安装 Oof 软件、配置硬件、测试基本配置和启动 Oof。本教程提供示例源代码,以展示 Oof 的工作原理。
硬件安装
本教程中使用了两台设备:作为主机的英特尔® 至强® 处理器 E5-2670 2.6 GHz 处理器和作为目标设备的英特尔® 至强融核™ 处理器。主机和目标设备运行 Red Hat Enterprise Linux* 7.2,都配有千兆位以太网适配器,以支持远程登录。需要指出的是,主机和目标设备的名称分别为 host-device和 knl-sb2。
首先,我们需要设置高速网络。由于硬件可用性,本实验使用 InfiniBand,也可以使用英特尔 OPA。
测试之前,关闭主机和目标设备,设置设备间的高速网络。将 Mellanox ConnectX*-3 VPI InfiniBand 适配器安装至主机和目标设备的 PCIe 插槽中,通过 InfiniBand 线缆连接,没有路由器的介入。重启设备后,首先验证 Mellanox 网络适配器是否已安装至主机:
[host-device]$ lspci | grep Mellanox
84:00.0 Network controller:Mellanox Technologies MT27500 Family [ConnectX-3]
然后验证其是否已安装至目标设备:
[knl-sb2 ~]$ lspci | grep Mellanox 01:00.0 Network controller:Mellanox Technologies MT27500 Family [ConnectX-3]
软件安装
主机和目标设备运行 Red Hat Enterprise Linux 7.2。您可以在主机验证 Linux Kernel 是否为最新版:
[host-device]$ uname -a Linux host-device 3.10.0-327.el7.x86_64 #1 SMP Thu Oct 29 17:29:29 EDT 2015 x86_64 x86_64 x86_64 GNU/Linux
您还可以验证在目标设备上运行的当前操作系统内核:
[knl-sb2 ~]$ uname –a Linux knl-sb2 3.10.0-327.el7.x86_64 #1 SMP Thu Oct 29 17:29:29 EDT 2015 x86_64 x86_64 x86_64 GNU/Linux
访问此处,获取最新 Oof 软件,并将 Oof 安装至主机,以启用 Oof。本教程安装了面向 Red Hat Enterprise Linux 7.2 (xppsl-1.4.0-offload-host-rhel7.2.tar
) 的 Oof 软件 1.4.0 版。如欲获取关于安装的更多信息,请参考文档《英特尔® 至强融核™ 处理器 x200 Offload over Fabric 用户指南》。此外,在主机安装英特尔® Parallel Studio XE 2017,以启用 Oof 支持,特别是由英特尔编译器提供的卸载编程模型支持。
访问此处,获取最新版英特尔至强融核处理器软件,并将其安装在目标设备。本教程中安装了面向 Red Hat Enterprise Linux 7.2 (xppsl-1.4.0-rhel7.2.tar
)的英特尔至强融核处理器软件 1.4.0 版。如欲获取关于安装的更多信息,请参考文档《英特尔® 至强融核™ 处理器软件用户指南》。
在主机和目标设备上安装面向 Linux 驱动程序 MLNX_OFED_LINUX 3.2-2 和 Red Hat Enterprise Linux 7.2 的 Mellanox OpenFabrics Enterprise Distribution (OFED),以设置主机和目标设备之间的 InfiniBand 网络。该驱动程序可以通过以下链接下载 www.mellanox.com(导航至Products > Software > InfiniBand/VPI Drivers下载Mellanox OFED Linux)。
基本硬件测试
在主机和目标设备上安装 Mellanox 驱动程序后,测试网卡,以确保 Mellanox InfiniBand HCA 能够正常工作。为了完成这一操作,请连接 InfiniBand 网络,并使用 ibping
命令测试网络连接。
首先启动主机的 InfiniBand 和子网管理器,然后显示连接信息:
[knl-sb2 ~]$ sudo service openibd start Loading HCA driver and Access Layer: [ OK ] [knl-sb2 ~]$ sudo service opensm start Redirecting to /bin/systemctl start opensm.service [knl-sb2 ~]$ iblinkinfo CA: host-device HCA-1: 0x7cfe900300a13b41 1 1[ ] ==( 4X 14.0625 Gbps Active/ LinkUp)==> 2 1[ ] "knl-sb2 HCA-1" ( ) CA: knl-sb2 HCA-1: 0xf4521403007d2b91 2 1[ ] ==( 4X 14.0625 Gbps Active/ LinkUp)==> 1 1[ ] "host-device HCA-1" ( )
以相同方式在目标设备启动 InfiniBand 和子网管理器,然后显示 InfiniBand 网络每个端口的连接信息:
[knl-sb2 ~]$ sudo service openibd start Loading HCA driver and Access Layer: [ OK ] [knl-sb2 ~]$ sudo service opensm start Redirecting to /bin/systemctl start opensm.service [knl-sb2 ~]$ iblinkinfo CA: host-device HCA-1: 0x7cfe900300a13b41 1 1[ ] ==( 4X 14.0625 Gbps Active/ LinkUp)==> 2 1[ ] "knl-sb2 HCA-1" ( ) CA: knl-sb2 HCA-1: 0xf4521403007d2b91 2 1[ ] ==( 4X 14.0625 Gbps Active/ LinkUp)==> 1 1[ ] "host-device HCA-1" ( )
iblinkinfo
报告该架构中所有端口的连接信息,一个位于目标设备,一个位于主机。然后,借助 ibping
命令测试连接(等同于面向以太网的 ping
命令)。利用以下命令启动主机的 ibping
服务器:
[host-device ~]$ ibping –S
在目标设备上,利用 ping 命令识别主机端口:
[knl-sb2 ~]$ ibping -G 0x7cfe900300a13b41 Pong from host-device.(none) (Lid 1): time 0.259 ms Pong from host-device.(none) (Lid 1): time 0.444 ms Pong from host-device.(none) (Lid 1): time 0.494 ms
同样,在目标设备上启动 ibping 服务器:
[knl-sb2 ~]$ ibping -S
在主机上,利用 ping 命令识别目标设备端口:
[host-device ~]$ ibping -G 0xf4521403007d2b91 Pong from knl-sb2.jf.intel.com.(none) (Lid 2): time 0.469 ms Pong from knl-sb2.jf.intel.com.(none) (Lid 2): time 0.585 ms Pong from knl-sb2.jf.intel.com.(none) (Lid 2): time 0.572 ms
通过 InfiniBand (IPoIB) 进行 IP 配置
到目前为止,我们已经验证了 InfiniBand 网络能够正常运行。下一步,我们需要通过 InfiniBand (IPoIB) 配置 IP,才能使用 OoFabric。该配置提供目标 IP 地址,用于通过架构卸载计算。
首先,验证 ib_ipoib
驱动程序是否安装:
[host-device ~]$ lsmod | grep ib_ipoib ib_ipoib 136906 0 ib_cm 47035 3 rdma_cm,ib_ucm,ib_ipoib ib_sa 33950 5 rdma_cm,ib_cm,mlx4_ib,rdma_ucm,ib_ipoib ib_core 141088 12 rdma_cm,ib_cm,ib_sa,iw_cm,mlx4_ib,mlx5_ib,ib_mad,ib_ucm,ib_umad,ib_uverbs,rdma_ucm,ib_ipoib mlx_compat 16639 17 rdma_cm,ib_cm,ib_sa,iw_cm,mlx4_en,mlx4_ib,mlx5_ib,ib_mad,ib_ucm,ib_addr,ib_core,ib_umad,ib_uverbs,mlx4_core,mlx5_core,rdma_ucm ib_ipoib
如果未显示 ib_ipoib
驱动程序已安装,需要使用以下命令将该模块添加至 Linux 内核:
[host-device ~]$ modprobe ib_ipoib
然后,通过 ifconfig
命令在主机列出 InfiniBand 接口 ib0:
[host-device ~]$ ifconfig ib0 ib0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 2044 Infiniband hardware address can be incorrect!Please read BUGS section in ifconfig(8). infiniband A0:00:02:20:FE:80:00:00:00:00:00:00:00:00:00:00:00:00:00:00 txqueuelen 1024 (InfiniBand) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
将该接口的 IP 地址配置为 10.0.0.1:
[host-device ~]$ sudo ifconfig ib0 10.0.0.1/24 [host-device ~]$ ifconfig ib0 ib0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 2044 inet 10.0.0.1 netmask 255.255.255.0 broadcast 10.0.0.255 Infiniband hardware address can be incorrect!Please read BUGS section in ifconfig(8). infiniband A0:00:02:20:FE:80:00:00:00:00:00:00:00:00:00:00:00:00:00:00 txqueuelen 1024 (InfiniBand) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 10 bytes 2238 (2.1 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
同理,在目标设备上将 InfiniBand 接口的 IP 地址配置为 10.0.0.2
:
[knl-sb2 ~]$ ifconfig ib0 ib0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 2044 Infiniband hardware address can be incorrect!Please read BUGS section in ifconfig(8). infiniband A0:00:02:20:FE:80:00:00:00:00:00:00:00:00:00:00:00:00:00:00 txqueuelen 1024 (InfiniBand) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 [knl-sb2 ~]$ sudo ifconfig ib0 10.0.0.2/24 [knl-sb2 ~]$ ifconfig ib0 ib0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 2044 inet 10.0.0.2 netmask 255.255.255.0 broadcast 10.0.0.255 Infiniband hardware address can be incorrect!Please read BUGS section in ifconfig(8). infiniband A0:00:02:20:FE:80:00:00:00:00:00:00:00:00:00:00:00:00:00:00 txqueuelen 1024 (InfiniBand) RX packets 3 bytes 168 (168.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 10 bytes 1985 (1.9 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
最后,利用主机上的 ping
命令验证目标设备的新 IP 地址 10.0.0.2
,并测试连接:
[host-device ~]$ ping 10.0.0.2 PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data. 64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.443 ms 64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.410 ms<CTRL-C>
同样地,利用目标设备验证主机的新 IP 地址 10.0.0.1
:
[knl-sb2 ~]$ ping 10.0.0.1 PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data. 64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.313 ms 64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.359 ms 64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.375 ms<CTRL-C>
SSH 免密码设置(可选)
将工作负载迁移至目标设备时,安全外壳 (SSH) 需要通过目标设备密码登录目标设备以及执行工作负载。为了避免通过人工干预才能完成迁移,必须启用无密码的 ssh
登录。为了进行这一操作,首先需要在主机上生成一对身份验证密钥,无需输入密码:
[host-device ~]$ ssh-keygen -t rsa
然后利用 ssh-copy-id
命令将主机的新公共密钥添加至目标设备的公共密钥:
[host-device ~]$ ssh-copy-id @10.0.0.2
Offload over Fabric
此时,高速网络已启用并正常运行。为了启用 Oof 功能,您需要在主机安装面向 Linux 的英特尔® Parallel Studio XE 2017。然后,利用以下命令设置您的 shell 环境:
[host-device]$ source /opt/intel/parallel_studio_xe_2017.0.035/psxevars.sh intel64 Intel(R) Parallel Studio XE 2017 for Linux* Copyright (C) 2009-2016 Intel Corporation.All rights reserved.
以下是用于测试 Oof 函数的示例程序。该示例程序在主机上分配并初始化一个常量 A
和若干缓冲区 x, y, z
,然后利用 OpenMP 设备构造指令 (#pragma omp target map…)
将计算卸载至目标设备。目标指令创建设备数据环境(在目标设备中)。运行时变量 x,y
和 A
的值被复制到目标设备中,然后进行计算。目标设备完成计算后,变量 y 的值被复制回主机。在本示例中,目标设备通过 lscpu
命令解析 CPU 信息,并生成一组 OpenMP 线程,计算矢量标量积,并将结果与矢量相加。
#include <stdio.h> int main(int argc, char* argv[]) { int i, num = 1024;; float A = 2.0f; float *x = (float*) malloc(num*sizeof(float)); float *y = (float*) malloc(num*sizeof(float)); float *z = (float*) malloc(num*sizeof(float)); for (i=0; i<num; i++) { x[i] = i; y[i] = 1.5f; z[i] = A*x[i] + y[i]; } printf("Workload is executed in a system with CPU information:\n"); #pragma omp target map(to: x[0:num], A) \ map(tofrom: y[0:num]) { char command[64]; strcpy(command, "lscpu | grep Model"); system(command); int done = 0; #pragma omp parallel for for (i=0; i<num; i++) { y[i] = A*x[i] + y[i]; if ((omp_get_thread_num() == 0) && (done == 0)) { int numthread = omp_get_num_threads(); printf("Total number of threads:%d\n", numthread); done = 1; } } } int passed = 0; for (i=0; i<num; i++) if (z[i] == y[i]) passed = 1; if (passed == 1) printf("PASSED!\n"); else printf("FAILED!\n"); free(x); free(y); free(z); return 0; }
利用英特尔编译器选项 -qoffload-arch=mic-avx512
编译该 OpenMP 程序,表示卸载部分专为第二代英特尔至强融核处理器构建。执行程序之前,将环境变量 OFFLOAD_NODES
设置为目标设备的 IP 地址(本例中为 10.0.0.2
),表示高速网络已被使用。
[host-device]$ icc -qopenmp -qoffload-arch=mic-avx512 -o OoF-OpenMP-Affinity OoF-OpenMP-Affinity.c [host-device]$ export OFFLOAD_NODES=10.0.0.2 [host-device]$ ./OoF-OpenMP-Affinity Workload is executed in a system with CPU information: Model: 87 Model name: Intel(R) Xeon Phi(TM) CPU 7250 @000000 1.40GHz PASSED! Total number of threads:268
需要指出的是,卸载过程由英特尔® 协处理器卸载基础架构(英特尔® COI)内部处理。默认情况下,卸载代码运行时,目标设备中 OpenMP 线程的全部可用。目标设备共有 68 个内核,英特尔 COI 后台程序在目标设备的一个内核上运行时,其它 67 个内核为可用;总线程数为 268(4 个线程/内核)。您可以利用 coitrace
命令跟踪所有的英特尔 COI API 调用:
[host-device]$ coitrace ./OoF-OpenMP-Affinity COIEngineGetCount [ThID:0x7f02fdd04780] in_DeviceType = COI_DEVICE_MIC out_pNumEngines = 0x7fffc8833e00 0x00000001 (hex) :1 (dec) COIEngineGetHandle [ThID:0x7f02fdd04780] in_DeviceType = COI_DEVICE_MIC in_EngineIndex = 0x00000000 (hex) :0 (dec) out_pEngineHandle = 0x7fffc8833de8 0x7f02f9bc4320 Workload is executed in a system with CPU information: COIEngineGetHandle [ThID:0x7f02fdd04780] in_DeviceType = COI_DEVICE_MIC in_EngineIndex = 0x00000000 (hex) :0 (dec) out_pEngineHandle = 0x7fffc88328e8 0x7f02f9bc4320 COIEngineGetInfo [ThID:0x7f02fdd04780] in_EngineHandle = 0x7f02f9bc4320 in_EngineInfoSize = 0x00001440 (hex) :5184 (dec) out_pEngineInfo = 0x7fffc8831410 DriverVersion: DeviceType:COI_DEVICE_KNL NumCores:68 NumThreads:272 <truncate here>
OpenMP* 线程相似性
上述程序的结果显示了目标设备上运行的默认线程数量 (272),但是,您可以明确设置目标设备上运行的线程数量。一种方法是通过主机上的环境变量来修改目标设备的执行环境。首先,定义一个专门针对目标设备的环境变量前缀,将该前缀添加至 OpenMP 线程相似性环境变量。例如,以下环境变量设置配置卸载运行时使用 8 个目标设备线程:
[host-device]$ $ export MIC_ENV_PREFIX=PHI [host-device]$ $ export PHI_OMP_NUM_THREADS=8
英特尔 OpenMP 运行时扩展 KMP_PLACE_THREAD
和 KMP_AFFINITY
环境变量可以将线程绑定至物理处理单元(也就是内核)(如欲获取更多信息,请参考“英特尔® C++ 编译器用户和参考指南”中的线程相似性接口章节)。例如,以下环境变量设置配置卸载运行时使用 8 个相邻线程:
[host-device]$ $ export PHI_KMP_AFFINITY=verbose,granularity=thread,compact [host-device]$ $ ./OoF-OpenMP-Affinity
您也可以通过 OMP_PROC_BIND
环境变量使用 OpenMP 相似性。例如,可以通过以下命令重复以上范例(使用 OMP_PROC_BIND
运行 8 个相邻线程):
[host-device]$ $ export MIC_ENV_PREFIX=PHI [host-device]$ $ export PHI_KMP_AFFINITY=verbose [host-device]$ $ export PHI_OMP_PROC_BIND=close [host-device]$ $ export PHI_OMP_NUM_THREADS=8 [host-device]$ $ ./OoF-OpenMP-Affinity
或者运行 8 个线程,并利用以下命令分散线程:
[host-device]$ $ export PHI_OMP_PROC_BIND=spread [host-device]$ $ ./OoF-OpenMP-Affinity
结果在下表中列出:
OpenMP* 线程数量 | 内核数量 |
---|---|
0 | 0 |
1 | 10 |
2 | 19 |
3 | 31 |
4 | 39 |
5 | 48 |
6 | 56 |
7 | 65 |
如欲运行 8 个线程,2 个线程/内核(共计 4 个内核),请执行以下命令:
[host-device]$ export PHI_OMP_PROC_BIND=close; [host-device]$ export PHI_OMP_PLACES="cores(4)" [host-device]$ export PHI_OMP_NUM_THREADS=8 [host-device]$ $ ./OoF-OpenMP-Affinity
结果在下表中列出:
OpenMP* 线程数量 | 内核数量 |
---|---|
0 | 0 |
1 | 0 |
2 | 1 |
3 | 1 |
4 | 2 |
5 | 2 |
6 | 3 |
7 | 3 |
总结
该教程详细介绍了如何设置并运行一个 Oof 应用以及如何安装硬件和软件。本文示例使用的是 Mellanox InfiniBand 主机通道适配器,也可以使用英特尔 OPA。示例代码是一个 OpenMP 卸载编程模型应用,展示了利用高速网络将运行在英特尔至强处理器主机上的运算卸载至英特尔至强融核处理器目标设备。本教程还展示了如何面向英特尔至强融核处理器编译并运行卸载程序,以及如何控制英特尔至强融核处理器上的 OpenMP 线程相似性。
参考文献
关于作者
Loc Q Nguyen拥有达拉斯大学 MBA 学位、麦吉尔大学电子工程专业硕士学位以及蒙特利尔理工学院电子工程专业学士学位。目前在英特尔公司软件及服务事业部担任软件工程师。研究领域包括计算机网络、并行计算和计算机图形。