InfiniBand QDR を Ubuntu 20.04 or 22.04 で設定するメモ(2023 年版)
情報
執筆時点(2023/07)ですと ConnectX-3 が中古でよく出回っている感じですね.
ConnectX-3 VPI ですと Eth mode もありますが, 10 GbE どまりになります.
RoCE(Ethernet(TCP/IP)互換で RMDA 的なのを行う) だと 40 GbE 相当になるのかしら? 著者が IB をよくいじっていたころ(2014 年くらい)は RoCE はまだまだ未成熟だった記憶がありますが, 最近はあたりまえのように使えるのかしらん.
いずれにせよ, ConnectX-3 は OEM 品多かったりいろいろ RoCE の過渡期の HW (RoCE v2 は ConnectX-3 Pro 以上)な感じなのようなので, 今から(2023/07 以降) IB を調達しようと考えている方は, ConnectX-4 以上を選んだほうがよいでしょう.
(ConnectX-4 だと IB のは 1.5 万円ほど? IB ではない 25GbE 品が安くある(1 万円くらい)ようですが...)
環境
注意点
Ubuntu のバージョン違いだと, software stack のバージョン違いで動かないものがります.
たとえば MPI や, ib_read_bw
など. https://bugzilla.redhat.com/show_bug.cgi?id=1883219
Ubuntu のバージョンの統一を強くおすすめします(2023/07 時点では 20.04 がよいでしょう(おおむね, 現 LTS のひとつ前の LTS バージョンを使う)
- Ubuntu 22.04 + ConnectX QDR(40 Gbps)(第一世代!) MT_0BB0110003
- およそ 9 年位前に調達して, 最近ずっと眠っていた
- fw ver:
2.8.60
- Ubuntu 20.04 + ConnectX-3 QDR(40 Gbps) MT_1090110028
- これはおよそ 7 年前くらいに調達.
- fw ver:
2.42.5000
ファームウェアアップデートですが, (最新の) ファームウェアアップデートツール mstflint は ConnectX, ConnectX-2 には対応しておりませんでしたので, ConnectX は調達時点のまま(2.8.600)を使いました.
mst の古いバージョン(3.0 あたり?)であればファームウェアアップデートツール動くかもですが...
ConnectX-3 は mst 4.24 でアップデートできました.
OFED?
かつて InfiniBand 関連(HPC 用インターコネクトや, Fiber channel など)で, OSS で開発されていたソフトウェアスタックです. もうメンテはされていないようです.
ドライバやカーネル関連は Linux kernel に直に取り込まれたり, ソフトウェアスタック周りは libfabric https://ofiwg.github.io/libfabric/ で主にメンテされるようになっています.
OFED の多くは Unbutu 標準パッケージに登録されているので, 最新の InfiniBand HW 使うとかでなければ, apt 以外でインストールするものはありません.
(libfabric も apt で入ります)
たとえば ConnectX-3(mlx4), ConnectX-4 あたりであれば Ubuntu 標準ので事足ります.
Windows の場合はベンダ(現在は NVIDIA)が WinOF(OFED の Windows 版をベンダが改修したりしているやつ)として配布しています. https://network.nvidia.com/products/adapter-software/ethernet/windows/winof-2/
Switch いりますか?
とりあえず直接接続でもいけます. 2 port ある HBA(ネットワークカード)が多いので頑張れば 4~8 台くらいであればリング接続 or チェーン接続でもいけるはず... ですが, 4 台以上つなぎたいときはスイッチ買うとよいでしょう.
IS5022(8port. QSFP QDR(40 Gbps))が 1 ~ 2 万円くらいで eBay などで手に入ります.
ファンがうるさいのでファン交換必須(or ファンに抵抗いれておそくする)!
ただ, switch のファン電源はサーバ用のためかピン配置が普通の PC 用と異なり, そのまま置き換えしてもファンが回りません. ファン用には別途で USB などから給電するとよいでしょう.
OpenSM
subnet manager は, 高いスイッチには HW で搭載されているようですが, HBA(ネットワークカード自体) or 安いスイッチだと搭載されていないので, Software でネットワークを管理するサービス(OpenSM)をどこかの PC で一つ立てておく必要あります.
HW 確認
ibv_devinfo
, ibv_devices
あたりで確認できます.
接続確認
ケーブル接続してリンクしていると ibnodes で相手先がとりあえず見えます.
ibwarn: [16002] mad_rpc_open_port: can't open UMAD port ((null):0)
と出たら sudo ibnodes
しましょう.
(umad の sys ファイルの permission をユーザー OK にするのがいいかも)
ネットワーク設定
IPoIB
InfiniBand 上に TCP/IP 流して Ethernet っぽく見せる.
一部の InfiniBand サービスで相手先を見つけるのに IPoIB が必要になったりします
(MPI とか? IPoIB で相手先見つけて, その後 RDMA 接続)
手動で設定が必要です.
DHCP off で固定 IP でよいでしょう.
Ubuntu 20.04 から(18.04 から?), ネットワークインターフェイス名が CentOS っぽくなりました.
$ ip a
や
$ sudo lshw -c network
で確認しておきます.
ibp7s0
(2 ポートある場合は, 2 ポート目は ibp7s0d1) のような名前になっているはずです.
ネットワーク設定は, Ubuntu 20.04 からは, netplan 経由でないと設定できないようですが,
実際のところ netplan のバグで infiniband 関連は設定できませんでした...
(ネットにある設定ためしたがダメだった)
$ cat /etc/netplan/01-network-manager-all.yaml
# Let NetworkManager manage all devices on this system
network:
version: 2
renderer: NetworkManager
Ubuntu デフォルトでは NetworkManager 経由になっていると思いますので, NetworkManager で設定します.
IPv6 は disabled がよいでしょう.
著者環境だと, nmtui でのデフォルト設定では ipv6 enabled なので, Datagram mode では不安定で通信していると ip が無効になってしまい, IPv6 に切り替わってしまうみたいな動作になっていました.
dmesg を出すと
IPv6: ADDRCONF(NETDEV_CHANGE): ibp12s0: link becomes ready
というメッセージが多量に出たり...
あと, 192.168 ですでに既存ネットワークがある場合はこれも不安定になるようでした(パケットの干渉? or fw 関連? 要確認)
10.0 や 172.16 など IB 専用の IP 範囲を使うとよいでしょう.
最終的に nmtui での設定では以下のようになりました.
/etc/NetworkManager/system-connections/
に ib 設定が記録されますのでそちらも参照ください.
再度 ip a
して, IP が割り振られているのを確認しておきます!
3: ibp12s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 2044 qdisc fq_codel state UP group default qlen 256
link/infiniband
xxxxxxxx
inet 10.0.100.100/24 brd 10.0.100.255 scope global noprefixroute ibp12s0
valid_lft forever preferred_lft forever
inet6 xxxxxxxx link noprefixroute
valid_lft forever preferred_lft forever
通常の TCP/IP でもそうかもしれませんが, 適切に IP 振っておけば IPoIB でも probe パケットが飛んで行って相手を見つけるので, ゲートウェイ IP 設定などは不要です(たとえば 192.168.250.100/24
, 192.168.250.101/24
と設定すれば, 192.168.250.1
などの IP を割り当てたノードを用意しなくともよい)
開通確認
あとは普通に ping なりするだけです.
...
64 bytes from 10.0.100.100: icmp_seq=3 ttl=64 time=0.221 ms
64 bytes from 10.0.100.100: icmp_seq=4 ttl=64 time=0.189 ms
64 bytes from 10.0.100.100: icmp_seq=5 ttl=64 time=0.202 ms
64 bytes from 10.0.100.100: icmp_seq=6 ttl=64 time=0.226 ms
64 bytes from 10.0.100.100: icmp_seq=7 ttl=64 time=0.186 ms
64 bytes from 10.0.100.100: icmp_seq=8 ttl=64 time=0.183 ms
64 bytes from 10.0.100.100: icmp_seq=9 ttl=64 time=0.182 ms
...
IB 自体はレイテンシは数 ns です.
ip のオーバヘッドを考えると 0.2 ms くらいは妥当なところでしょうか.
ConnectX-3 同士だとレイテンシはより改善されるかもしれません.
パフォーマンス計測
iperf3
まずは iperf3 で計測してみます.
$ iperf3 -s # server
# client
$ iperf3 -c 10.0.100.100
...
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 6.07 GBytes 5.21 Gbits/sec 9806 sender
[ 5] 0.00-10.04 sec 6.06 GBytes 5.19 Gbits/sec receiver
5 GbE 相当です. まあスレッド化なりしたら理論値(32 Gbits/sec)に近くなるかもしれません.
また, IPoIB で Connection mode だと 15 Gbps くらい出ました. IPoIB でもそこそこ性能欲しい場合は Connection mode にしておくとよいかもです.
qperf
Ubuntu だとデフォだとポートは解放されています(ufw disabled)
# server
$ qperf
# client
$ qperf 10.0.100.100 rc_rdma_read_bw
rc_rdma_read_bw:
bw = 3.47 GB/sec
Voila! おおむね QDR(8/10 encoding) の理論値(3.2 GB)が出ました!
トラブルシューティング
State: Down のまま接続されない(Link LED が点滅しない)
- PCI-ex スロットにきちんとささっているか
- ケーブルはかちっとなるまで挿さっているか
とくに銅線のケーブルは太くて重く, ケーブル抜き差し時に HBA が PCIex スロットからはずれてしまいやすいです(PC ケースに固定が理想だが, ミニクラスタを構築したい場合オープンエアにすることが多く固定が難しいときがある)
opensm のデーモンが active (exited) になる.
不明. Ubuntu 22.04 で発生する.
とりあえず opensm 動かすのは Ubuntu 20.04 がよいでしょう.
アプリ
ユーザから見た主なアプリは
- MPI
- pytorch + NCCL/RCCL
- 既存の TCP/IP(socket)
- 自前 RDMA アプリ(uverbs とかつかったり!)
あたりかなと思います.
MPI
以下は両ノードとも Ubuntu 20.04 で行いました.
Ubuntu 20.04 + 22.04 だと動かないのでご注意ください
(ソースから openmpi 関連ビルドしたとしても, openmpi が依存する ibverbs や librdma とかあたりでバージョン違うからうまくいかない)
openmpi, mpich どちらも apt パッケージでデフォで rdma 用の backend が入っています.
昔は mpich のほうが InfiniBand 対応がよかった記憶がありますが, 最近ですと openmpi も InfiniBand 対応したのと, 全体的に openmpi のほうが主流そうですので, openmpi がよいでしょうか.
(ただ, openmpi 最新版だと libfabric あたりでコードいろいろ変わったりで不安定っぽい)
$ sudo apt install openmpi-bin
ファイルシステムは理想は nfs or cifs(samba) で共通化ですが, とりあえず2ノードであれば両方で同じファイルレイアウトを使えば OK です.
(MPI で利用するファイルやディレクトリは rsync で同期しておくなどする)
benchmark
OSU MicroBenchmarks を使います.
apt では用意されていないようなので, ソースからビルドします.
$ ./configure --prefix=$HOME/local/osu CC=mpicc CXX=mpicxx
$ make
$ make install
hostfile には IPoIB の IP をリストしておきます.
# hostfile
10.0.100.100
10.0.100.101
各ノードに ssh でパスフレーズなしでログインできるようにしておきます(~/.ssh/authorized_key
に公開鍵登録)
デフォルトでは, ipoib の IP で mpirun すると
--------------------------------------------------------------------------
By default, for Open MPI 4.0 and later, infiniband ports on a device
are not used by default. The intent is to use UCX for these devices.
You can override this policy by setting the btl_openib_allow_ib MCA parameter
to true.
とでることあります.
export OMPI_MCA_btl_openib_allow_ib=1
か, mpirun
の引数で --mca btl_openib_allow_ib 1
を指定しておきます.
(--mca
はいろいろ mpi 実行の設定をするオプション https://docs.open-mpi.org/en/main/mca.html)
しておきます.
ただ, ubuntu 20.04 だと libfabric のバグなのか, osu_bw など実行すると
[aero:30099] *** Process received signal ***
[aero:30099] Signal: Segmentation fault (11)
[aero:30099] Signal code: (128)
[aero:30099] Failing at address: (nil)
[aero:30099] [ 0] /lib/x86_64-linux-gnu/libc.so.6(+0x43090)[0x7fbd3a70d090]
[aero:30099] [ 1] /lib/x86_64-linux-gnu/libibverbs.so.1(ibv_dereg_mr+0x20)[0x7fbd38978050]
[aero:30099] [ 2] /lib/x86_64-linux-gnu/libfabric.so.1(+0x536c7)[0x7fbd3844d6c7]
[aero:30099] [ 3] /lib/x86_64-linux-gnu/libfabric.so.1(+0x758d9)[0x7fbd3846f8d9]
[aero:30099] [ 4] /lib/x86_64-linux-gnu/libfabric.so.1(+0x759c1)[0x7fbd3846f9c1]
[aero:30099] [ 5] /lib/x86_64-linux-gnu/libfabric.so.1(+0x792b5)[0x7fbd384732b5]
[aero:30099] [ 6] /lib/x86_64-linux-gnu/libfabric.so.1(+0x7a52c)[0x7fbd3847452c]
[aero:30099] [ 7] /lib/x86_64-linux-gnu/libfabric.so.1(+0x7af71)[0x7fbd38474f71]
[aero:30099] [ 8] /lib/x86_64-linux-gnu/libfabric.so.1(+0x28475)[0x7fbd38422475]
[aero:30099] [ 9] /lib/x86_64-linux-gnu/libfabric.so.1(+0x27b02)[0x7fbd38421b02]
と segmentation fault します.
--mca mtl '^ofi'
として, mtl(matching transport layer)で ofi を off (^
は disable を意味する. '
でクォートしておくと確実)にするととりあえずは動きます.
Ubuntu 22.04 ではこのバグは治っているかもしれません.
最終的にこんな感じ.
# hostfile 使う場合は -hostfile hostfile
$ mpirun --mca btl_openib_allow_ib 1 --mca mtl '^ofi' -np 2 -host 10.0.100.101,10.0.100.100 ~/local/osu/libexec/osu-micro-benchmarks/mpi/pt2pt/osu_bw
# OSU MPI Bandwidth Test v7.1
# Size Bandwidth (MB/s)
# Datatype: MPI_CHAR.
1 2.41
2 4.80
4 9.60
8 17.55
16 35.49
32 54.91
64 109.68
128 299.92
256 602.31
512 1114.86
1024 2153.19
2048 2654.70
4096 3018.45
8192 3198.11
16384 3426.45
32768 3478.47
65536 3504.48
131072 3517.39
262144 3524.05
524288 3527.37
1048576 3529.10
2097152 3530.00
4194304 3530.25
Voila! 3.5 GB/s と理論値(3.2 GB/s) + alpha 出ました!
pt2pt/osu_latency
# OSU MPI Latency Test v7.1
# Size Latency (us)
# Datatype: MPI_CHAR.
1 1.22
2 1.21
4 1.21
8 1.30
16 1.31
32 1.33
64 1.43
128 2.61
256 2.78
512 2.99
1024 3.42
2048 4.28
4096 5.15
8192 6.48
16384 9.05
32768 13.45
65536 22.84
131072 41.30
262144 78.23
524288 152.06
1048576 299.80
2097152 595.11
4194304 1186.97
~ 64 bytes まで 1.5 ns くらいでした. これもおおむね仕様通りでしょうか.
pytorch + NCCL とか
たぶん普通に使えるはず... T.B.W.
既存 socket アプリ
rsocket(今は rspreload?)で行けます.
最近では librdmacm あたりのパッケージに標準で含まれており, ubuntu では /usr/lib/x86_64-linux-gnu/rsocket/librspreload.so
にあります.
リンク先のスクリプトを python3 で書き換えて 1GB 転送処理してみたところ...
なにもなし: elap 1511 [ms]
rsocket preload: elap: 1670 [ms]
あんまり変わりませんでした. 何もなしでも 700 MB/sec くらいは出ています.
IPoIB connected mode にしたらなにか効果があるかもしれません.
TODO
-
OS 環境を合わせて MPI osu benchmark を走らせる
- mpich 版を試す
- network 名が PCI スロットの構成変わると変わる. NetworkManager で mac アドレスで固定する方法を探す
Discussion