-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ao] 読み進めメモ #5
Comments
すごく初歩から
|
順に、NCCL_APIについて Lines 25 to 39 in 9db4b1d
Line 13 in 9db4b1d
通常版の Lines 36 to 38 in 9db4b1d
しているだけ。後者はgcc拡張で、実はNCCLはattributeで明示的に指定しない関数は全部ライブラリの外からは見えなくなっている Line 46 in 9db4b1d
|
ncclInfoは単に引数をまとめただけのもの Lines 23 to 43 in 9db4b1d
大体はncclAllreduceの引数をそのまま転送しているが違うのは以下
|
ncclEnqueueCheck Lines 409 to 442 in 9db4b1d
Asyncモードかどうかで別れている。asyncモードとは、1プロセスで複数GPUを使う時に、ncclAllreduceを非同期にして、全GPUでncclAllreduceを呼び出すためのもの。複雑になるすぎるので割愛する。 ということで、ここでの処理は Lines 435 to 439 in 9db4b1d
|
ArgsCheckLines 35 to 68 in 9db4b1d
|
チャンネルという概念が出てくるが、これは何を指しているのだろう・・・? |
ncclChannelの定義 Lines 147 to 171 in 9db4b1d
通信方法を規定している何かには見えるが・・・? 初期化は Lines 12 to 34 in 9db4b1d
|
Lines 812 to 818 in 8e04d80
|
なおリングというのは https://research.preferred.jp/2018/07/prototype-allreduce-library/ にあるやつ。 となると、リングが複数あるのってどういう状況なんだろう? |
チャンネル=リングと仮定して話を進める。 チャンネル数は上限16なので、それほど多く作るものではないらしい。 そしてSlack等で話した限り、リングは、NVLink等で各GPUが全結合しているのを使い切るために複数作られる模様。 16個しかないのは、NVLinkが16GPUまでしかサポートしてないからか?実際のnringsを決めているのは Line 204 in 0ceaec9
だが割と複雑そう。ちょっと脱線するがどうやって決めてるのか興味あるので読み解いてみよう。 |
Lines 209 to 225 in 0ceaec9
の部分。NCCL_RINGS環境変数から設定を読み込んでいる。文字列を解析してリングが作れたら使うし、使えなかった場合はエラーではなくそのまま内部生成に進む。中身はあんまり面白くなさそうなので割愛 |
どうやら #1 にあるリング生成アルゴリズムを理解しておく必要がありそう。誰か知ってそうだが、練習(?)も兼ねて自力でやる。 |
新しくtransportsという概念が出てきたので整理。transportには3種類ある
Lines 13 to 17 in 9db4b1d
|
リングを作る前に、各デバイス(というかランク)間の接続状況を Lines 131 to 171 in 0ceaec9
で調べている。 |
接続されているかは、実はここではなく Lines 472 to 484 in 8e04d80
で調べて、それを引数matrixで渡されているだけっぽい |
canConnectは関数ポインタになっていて分かりづらいが、実体は
どうやって確認しているかは難しそう&今はあんまり興味ないので割愛 |
Lines 142 to 150 in 0ceaec9
isConnected(curRank, p2pConnected, nranks, matrix, 0);
for (int r=0; r<nranks; r++) {
if (p2pConnected[r]) {
rankToIdx[r] = idx;
idxToRank[idx] = r;
for (int t=0; t<NTRANSPORTS; t++) coords[r*NTRANSPORTS+t] = current[t];
idx++;
curRank = r;
current[0]++;
}
}
current[0] = 0; |
の0はp2pを指している |
全部P2P通信できるならそれで終わり #それはそう Lines 152 to 155 in 0ceaec9
|
あ、違うな。P2P接続されているもの同士をグループと呼び、最初にランク0から辿れるランクを全部取りに行って0番目のグループにしてますね。 |
次のグループを探しているところ Lines 157 to 169 in 0ceaec9
また分かりづらいので書き下した // Find next group, either connected through SHM or NET.
int rank;
int transport = 1;
do {
rank = -1;
for (int r=0; r<nranks; r++) {
if (coords[r*NTRANSPORTS + 0] == -1 && matrix[curRank*nranks+r] == transport) {
rank = r;
break;
}
}
if(rank == -1) {
current[transport] = 0;
transport++;
if (transport == NTRANSPORTS) {
WARN("Error : Could not find transport to connect next group\n");
free(p2pConnected);
return ncclInternalError;
}
}
} while(rank == -1);
curRank = rank;
current[transport]++; ここでは、curRank(つまりさっき見つけたP2P相互接続集団の最後のランク)とshmかnet接続されているもののうち(shm優先)、これまでにどこかのP2P集団に含まれていないランクを探している。そのランクが次のP2P集団を探す始点になるということ。 至って普通。 |
で、ここまで読んでようやくcoordの意味がわかった。つまり Lines 72 to 73 in 0ceaec9
だが、順番が逆で、自分のランクがrankの時に
を表してますね。 |
ということで、 |
そして、この |
そしてncclGetRings()に戻り Lines 253 to 263 in 0ceaec9
の処理は、net,shm,p2pの順に、より上位(広い)集団において引数のrankと同じものを探索している |
TValueについて rmatsumiya 情報
|
次回以降やること:
Lines 280 to 322 in 0ceaec9
|
やります。 |
Lines 257 to 270 in 0ceaec9
はコメント通り。自分のrankと
を保存している。 |
Line 283 in 0ceaec9
のtransports変数について。これは #5 (comment) で作られるもので、中身としては、2次元配列transport[i][j]で、ランクiとjがつながっている最小のtransport番号、つまりp2p/shm/netの順が入っている。 |
Lines 281 to 288 in 0ceaec9
subvaluesというのは、単にvaluesをrankからidxに変換し、かつ今処理しているtransport以外は0にする、というだけ |
subprev/subnextは初回は Lines 293 to 304 in 0ceaec9
が全部成立しないので-1 |
Ring生成処理自体はtransportに投げていて Line 306 in 0ceaec9
それぞれ以下
|
getRingsの各中身を読んでいたらgroupの定義が崩壊してきた・・・。単に #5 (comment) のような識別番号の保存だけではないっぽい。 |
#5 (comment) がちょっと間違っていて訂正した。なので、groupとは、自分と同じ上位のtransportに属している中で割り振っている。 で、groups[gidx]とループを回していたりすることから分かる通り、groupの番号っぽい。そしてそこにはtransport内識別番号が入っている。 ということは、同じtransportに属しているデバイスを、別々のgroupに割り当てていると推測される。 |
と思ったけど、nranksInGroupという変数があって Line 78 in 9db4b1d
先述の通り、同じtransport内にあるデバイスは別々のgroup番号になっているので、group内にあるrank(つまりデバイス)の数はつねに1だと思うんだけど? |
嘘。shmとかだと同じP2P内にいるやつは同じgroup番号になるし、netだと同じshmに属するやつは同じgroup。 |
で、話が戻ってgetRings()が何をしているか。 全部の詳細は追うと大変なので置いといて、何が起きるかだけをshm実装(一番簡単そうなので)から読み解くと、要はnringsTmp, subprev, subnextだけが出力のよう。 で、中では Lines 216 to 217 in 9db4b1d
みたいに代入されていて、このstarts/ends[group]は、そのgroupの先頭/末尾rank。 つまり、subprev/nextには、そのrankが各groupの先頭・末尾だった時に、前・次のgroupの末尾・先頭rankが入っているということ。 |
Lines 319 to 322 in 0ceaec9
|
なんか順番がおかしいように見えるので自分で取り直す |
いや、大丈夫だった。
だけ見れば良さそう。全部P2Pでつながっていてshmがないから変に見えただけだった。 (あと、printfのrはrankではなくてring) |
1nodeだったり1GPUのときは簡単で、t=0,2(P2P, net)だけでそれぞれ順に1周して終わり。 複数ノード複数GPUだとちょっとやっかいで、2node2GPUの例
だと、net(i.e. t=2)しかやってない状態では
ここから、P2P(i.e. t=0)まで含めると
になって、ノード内の接続状況も書かれる。2->3がないのは、他のノードの状況は知らないから。逆に、rank=2では
となっているので、rank=0のいたノードの情報は知らないが、2->3が出力される。 |
実行例ではminScore=NCCL_MAX_SCOREのままで、つまりdo-whileは1回しか回ってないが、複数回実行されることはあるのか。 nringsTmpに0が入った時がそれに該当するが、それはgetRingsが0を返してきた時だけである。 ということで、やはりgetRings #5 (comment) を真面目に読まないとダメそうだ |
getRingsは、net,shm,p2pの順番で呼ばれ、以前のprevTmp/nextTmpを保存しているので、最初はnetから読み始めるのが簡単そう。 Lines 183 to 219 in 9db4b1d
|
netつまりt=2の時、 Line 262 in 0ceaec9
Line 265 in 0ceaec9
なので、nGroupsは1になって Line 177 in 9db4b1d
Line 184 in 9db4b1d
|
coords[net]=0以外になることがあるのか検証するために Lines 116 to 133 in 9db4b1d
Line 169 in 0ceaec9
実際の接続判定は Line 477 in 8e04d80
Line 119 in 9db4b1d
ncclNetTvalues は計算結果のキャッシュなので放置で良くて、本体は Lines 127 to 128 in 9db4b1d
getTValueの中身 Lines 28 to 36 in 9db4b1d
Lines 90 to 113 in 9db4b1d
|
そういえば前回誰かやってなかったかなと思ったらrmatsumiyaメモにあった。
もうちょっと深読みします。 |
Lines 105 to 111 in 9db4b1d
lineとかsprintfとか入っているが、単なるデバッグログようなので無視して良くて、本体は Lines 78 to 88 in 9db4b1d
distanceの決定は Line 84 in 9db4b1d
まず、getCudaPathとncclNetPciPathのどちらかがNULLだと Line 37 in 9db4b1d
このうち、getCudaPathは、NULLを返すときは戻り値がエラーになっている Line 21 in 0ceaec9
Line 19 in 8e04d80
ncclNetPciPathはまた関数ポインタになっていてややこしい・・・。ncclNetはIBかSocketしかない Lines 131 to 137 in ccb1298
のどっちか。これらがNULLを返す時は、そもそも |
pciDistanceの方は Lines 45 to 56 in 0ceaec9
以上から、つまりdistanceは何もなければ0から4の数字が絶対に入っている。別に複雑でもない。 で、スコア算出 Lines 28 to 36 in 9db4b1d
1 + PATH_SYS - distances[d]; なので、scoreは1から5。NET_BITS_PER_IF_MASKは1<<3-1 = 0b111で3bitつまり1-5は表現できるので、絶対にゼロになることはない。
ということで結論として、何があってもnetCanConnectがfalseにはならないので、 #5 (comment) のcoord[net]=0以外はありえない。 なので最終的にぐるっと戻って Line 184 in 9db4b1d
のgroupはつねに0固定、他は考えなくて良い。 |
netGetRings()がnRings=0を返すのは、starts/endsのどちらかが-1、つまり見つからなかった時 Lines 208 to 209 in 9db4b1d
starts/endsは
ゆえ、少なくともnet(transport=2)でnringsTmp=0はありえない。 |
今日はここまで。次回
|
allreduceを上から追っておきます
The text was updated successfully, but these errors were encountered: