TadaoYamaokaの日記

山岡忠夫Homeで公開しているプログラムの開発ネタを中心に書いていきます。

LinuxとWindowsのマルチスレッド性能

将棋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

Windowsは0ミリ秒のスリープと変わりません。
Linuxはだいぶ改善されましたが、Windowsの半分以下です。

condition_variableに変更

通知の処理を、ビジーループからcondition_variableに変更しました。

探索スレッド側
std::unique_lock<std::mutex> lk(mtx);
while (uct_node[child_index].evaled == 0)
	cond.wait(lk);
GPUスレッド側
uct_node[index].evaled = 1;
cond.notify_all();

探索速度は、以下の通りとなりました。

Windows 1823
Linux 2769

Linuxは今までで一番よい値になりましたが、やはりWindowsのビジーループの場合の半分以下です。
Windowsはcondition_variableを使うと、ビジーループの場合の29%まで落ち込みました。

考察

以上の実験結果から、Linuxではビジーループよりもcondition_variableの方がマルチスレッドの性能がよさそうです。
しかし、Windowsでビジーループする場合の半分以下の性能しかでません。
Windowsでは、condition_variableを使うと、ビジーループよりも性能が低下します。

LinuxWindowsと同等のマルチスレッドの性能を出す方法は今のところ不明です。
AWSを借りる場合、料金は上がりますが、Windowsを借りることになりそうです・・・。
どなたかLinuxでもマルチスレッドの性能について知見をお持ちの方がいたらアドバイスいただけると嬉しいです。