自宅のパソコンが壊れちゃったので、新しいノートPCを買った。
最近はいいやつが安く買えるので、思いきってCore i7のを買ってしまった。
で、前に仕事パソコンでやった並列処理の速度を測ってみた。
新PC
Core i7 2630
クロック 2.00GHz
コア数 4
MEM: 4GB
旧PC
Core?2 Duo SL9300
クロック 1.60GHz
コア数 2
MEM: 2GB
さらにi7はハイパースレッディングで仮想コアがあるのでOSからは8つのコアに見える。
処理は 2の10000乗を10000個計算して、下2桁の合計を求めるもの。
結果は
旧 5562 msecs
新 4251 msecs
クロックを比較すると、2.0GHzは1.6GHzの1.25倍なので所用時間が反比例するとしたら、 5562 / 1.25 = 4449 になる。 実際はもうちょっと速いけど、まあ、コア単体ではそれほど性能が上っているわけではないことがわかる。
次に、pmapを使って10000個をそれぞれ並列に処理してみる。
コード
結果
旧 3480 msecs
新 1150 msecs
半分以下の時間になった。単一スレッドとの時間で比較しても、旧では36%減だけど、新では、73%減。
タスクマネージャの表示をキャプチャしたのが下の画像。
また、前にも書いたとおり、上の並列処理は10000個を全部別のスレッドに割りあてていて、オーバーヘッドが大きくなってしまっている。適当なサイズに分割することで、もう少し速度が向上するはず。
以下のようにいくつかずつに分割して割り当てて実行してみた。
2分割の場合の処理がこれ。
全部の結果をまとめてみた。
単位はmsec。
2コアに比べて、分割数を大くしても性能の低下が少ない感じです。
スレッド(タスク)の切りかえが高速なのかもしれませんね。
READ MORE
最近はいいやつが安く買えるので、思いきってCore i7のを買ってしまった。
で、前に仕事パソコンでやった並列処理の速度を測ってみた。
新PC
Core i7 2630
クロック 2.00GHz
コア数 4
MEM: 4GB
旧PC
Core?2 Duo SL9300
クロック 1.60GHz
コア数 2
MEM: 2GB
さらにi7はハイパースレッディングで仮想コアがあるのでOSからは8つのコアに見える。
処理は 2の10000乗を10000個計算して、下2桁の合計を求めるもの。
まずは単一スレッドでの実行。
コードはこれ。(let [nums 10000]
(time
(reduce + (map (fn [x] (rem (expt 2 x) 100)) (repeat 10000 nums)))))
結果は
旧 5562 msecs
新 4251 msecs
クロックを比較すると、2.0GHzは1.6GHzの1.25倍なので所用時間が反比例するとしたら、 5562 / 1.25 = 4449 になる。 実際はもうちょっと速いけど、まあ、コア単体ではそれほど性能が上っているわけではないことがわかる。
次に、pmapを使って10000個をそれぞれ並列に処理してみる。
コード
(let [nums 10000]
(time
(reduce + (pmap (fn [x] (rem (expt 2 x) 100)) (repeat 10000 nums)))))
結果
旧 3480 msecs
新 1150 msecs
半分以下の時間になった。単一スレッドとの時間で比較しても、旧では36%減だけど、新では、73%減。
タスクマネージャの表示をキャプチャしたのが下の画像。
上は単一スレッドでの実行で、5番目だけ仕事をしてるけど、並列にすると、ちゃんと全てのコアが仕事をしているのがわかる。
また、前にも書いたとおり、上の並列処理は10000個を全部別のスレッドに割りあてていて、オーバーヘッドが大きくなってしまっている。適当なサイズに分割することで、もう少し速度が向上するはず。
以下のようにいくつかずつに分割して割り当てて実行してみた。
2分割の場合の処理がこれ。
(let [nums 10000]
(time
(reduce + (pmap #(reduce + (map (fn [x] (rem (expt 2 x) 100)) %))
(partition 5000 (repeat 10000 nums))))))
全部の結果をまとめてみた。
単位はmsec。
旧 新
1分割 5562 4251
2分割 3092 2157
10分割 3064 1132
100分割 3099 1106
1000分割 3255 1129
10000分割 3480 1150
2コアに比べて、分割数を大くしても性能の低下が少ない感じです。
スレッド(タスク)の切りかえが高速なのかもしれませんね。
Project Euler を解いているときに、素数生成とかの細かい関数を作っているのだけれど、10個以上になってきたので、まとめることにした。
あらためて見てみると、変だったり、もう少し汎用的にしたほうがよかったりするものが目について、直し始めちゃって泥沼化寸前。
そのなかで、同じような計算をたくさんしているところで気になっていたのが、CPUの使用率が50%を超えないこと。mapなんかは自動的に並列処理してくれるのだと思っていたからちょっと意外だった。黒猫本(と呼ばれているかどうかは知らない)にも、STMとかの機能の説明はあるけど、並列化するための方法については書かれていなかった。「自分でJavaのThreadを呼ばなければならんのかい!」と思っていたら、pmapというのを見つけた。
で、実際どうなのかを調べてみた。
なんか適当に時間のかかる処理ということで、適当に2のX乗をY個足す処理にした。
mapでやるとこんな感じ。
"Elapsed time: 5561.606014 msecs"
5.6秒くらい。 このときのCPUの使用率は50%。
mapをpmapに変えると、
"Elapsed time: 3480.631756 msecs"
お、速い。 3.5秒。 36%高速化。
タスクマネージャで見ると、ちゃんと100%使用率になる。
あと、そこでjavaを片方のCPUにだけ割りあてると、もとと同じく、5秒半ぐらいかかる。
さて、これで安心してはいけない。
ここの記事を見たりすると、ただ単に1つ1つ並列化すればいいというものではないらしい。
そりゃあ当然だ。細切れにすれば、その分Over headが増えるわけだからねぇ。
どんな風に分けたらいいのかなぁ。
僕のPCはデュアルコアだから、2つに分けてみると、
"Elapsed time: 3092.340227 msecs"
3.1秒。 44%高速化。 8ポイント向上。
ほかも適当にやってみると、
10分割 "Elapsed time: 3064.371031 msecs"
100分割 "Elapsed time: 3099.338324 msecs"
1000分割 "Elapsed time: 3255.111753 msecs"
今回は10分割が一番速いという結果。
並列化のための関数は、他にもfutureとかいろいろあるみたいなので、これからちょっとずつつついていこうと思っとります。
READ MORE
あらためて見てみると、変だったり、もう少し汎用的にしたほうがよかったりするものが目について、直し始めちゃって泥沼化寸前。
そのなかで、同じような計算をたくさんしているところで気になっていたのが、CPUの使用率が50%を超えないこと。mapなんかは自動的に並列処理してくれるのだと思っていたからちょっと意外だった。黒猫本(と呼ばれているかどうかは知らない)にも、STMとかの機能の説明はあるけど、並列化するための方法については書かれていなかった。「自分でJavaのThreadを呼ばなければならんのかい!」と思っていたら、pmapというのを見つけた。
で、実際どうなのかを調べてみた。
なんか適当に時間のかかる処理ということで、適当に2のX乗をY個足す処理にした。
mapでやるとこんな感じ。
(let [nums 10000]
(time
(reduce + (map (fn [x] (rem (expt 2 x) 100)) (repeat 10000 nums)))))
"Elapsed time: 5561.606014 msecs"
5.6秒くらい。 このときのCPUの使用率は50%。
mapをpmapに変えると、
(let [nums 10000]
(time
(reduce + (pmap (fn [x] (rem (expt 2 x) 100)) (repeat 10000 nums)))))
"Elapsed time: 3480.631756 msecs"
お、速い。 3.5秒。 36%高速化。
タスクマネージャで見ると、ちゃんと100%使用率になる。
あと、そこでjavaを片方のCPUにだけ割りあてると、もとと同じく、5秒半ぐらいかかる。
さて、これで安心してはいけない。
ここの記事を見たりすると、ただ単に1つ1つ並列化すればいいというものではないらしい。
そりゃあ当然だ。細切れにすれば、その分Over headが増えるわけだからねぇ。
どんな風に分けたらいいのかなぁ。
僕のPCはデュアルコアだから、2つに分けてみると、
(let [nums 10000]
(time
(reduce + (pmap #(reduce + (map (fn [x] (rem (expt 2 x) 100)) %))
(partition 5000 (repeat 10000 nums))))))
"Elapsed time: 3092.340227 msecs"
3.1秒。 44%高速化。 8ポイント向上。
ほかも適当にやってみると、
10分割 "Elapsed time: 3064.371031 msecs"
100分割 "Elapsed time: 3099.338324 msecs"
1000分割 "Elapsed time: 3255.111753 msecs"
今回は10分割が一番速いという結果。
並列化のための関数は、他にもfutureとかいろいろあるみたいなので、これからちょっとずつつついていこうと思っとります。
