将棋AIをAWSで動かそうとLinux対応しましたが、Linuxでマルチスレッドの性能がでないため、いろいろ実験してみました。
検証している将棋AIではGPUの計算が終わったら、待機中の複数の探索スレッドに通知する処理を行っています。
それを、以下のような処理で実装していましたが、Linux(Ubuntu 16.04)ではWindowsの1/10以下の探索速度になってしまいます。
探索スレッド側
while (uct_node[child_index].evaled == 0) this_thread::sleep_for(chrono::milliseconds(0));
GPUスレッド側
uct_node[index].evaled = 1;
探索スレッド数は255です。evaled はatomicです。
探索速度(シミュレーション/秒)の比較は、以下の通りです。
Windows | 6305 |
Linux | 561 |
sleep時間変更
はじめ、GPUまわりのコードを疑いましたが、GPUの処理を外しても変わらないため、マルチスレッドに起因する問題と推測し、探索スレッド側でビジーループしている箇所を0ミリ秒のsleepから1ミリ秒のsleepに変更してみました。
すると以下の通り少しだけ改善されました。
Windows | 5190 |
Linux | 1354 |
Windowsでは逆に探索速度が落ちています。
yieldに変更
今度は、0ミリ秒のsleepの代わりにyiledに変更してみました。
while (uct_node[child_index].evaled == 0) this_thread::yield();
今度はだいぶ改善されました。
Windows | 6301 |
Linux | 2258 |
condition_variableに変更
通知の処理を、ビジーループからcondition_variableに変更しました。
探索スレッド側
std::unique_lock<std::mutex> lk(mtx); while (uct_node[child_index].evaled == 0) cond.wait(lk);
考察
以上の実験結果から、Linuxではビジーループよりもcondition_variableの方がマルチスレッドの性能がよさそうです。
しかし、Windowsでビジーループする場合の半分以下の性能しかでません。
Windowsでは、condition_variableを使うと、ビジーループよりも性能が低下します。
LinuxでWindowsと同等のマルチスレッドの性能を出す方法は今のところ不明です。
AWSを借りる場合、料金は上がりますが、Windowsを借りることになりそうです・・・。
どなたかLinuxでもマルチスレッドの性能について知見をお持ちの方がいたらアドバイスいただけると嬉しいです。