数値取っておいてなんなんですが、ちょっと気になることはあるので、適正な値かどうかはちょっと微妙故にこっそり公開。(ぉ
あ、ベンチ系に詳しい人はソースコードに突っ込みよろしくお願いします。^^;
# ちょっと自分も気になっているところがあるけれども…
ちなみに、なんで Java かっていうと、
- Linux では Cレベルでの Thread の作り方が分からなかったから。 fork 何それおいしいの?
- VC と GCC じゃ、Cソースコードの最適化度合いが違う -> メインルーチンぐらいは asm でコードを書かなきゃいけない -> めんどい (ぉ
というわけで、Javaりました。 なもんで、以下目安で。^^;
環境1 - メインマシン
CPU | Athlon 64 x2 4400+ |
---|---|
Mem | 6GB - DDR2 800 DualChannel |
OS | WinXP x64 SP2 |
Java | 1.6.0_07 32bit版 |
テスト内容
以下の(悲惨な)Javaのコードを各環境で実行。 コマンドライン引数より1つ数値を与えることにより、その数値分のスレッドが生成されます。
で、最後のスレッドが終了するまでの時間を計測しました。
import java.util.Date; public class Bench extends Thread { static final int TIMES = 0x8000; static final int ARRAY_SIZE = 100000; int m_nRand; int m_nResult; int m_nID; public Bench(int nID) { m_nID = nID; m_nRand = (int)(Math.random() * 0x1000); } private int rand() { // えせ乱数 return m_nRand = ((m_nRand * 0x654321) | (m_nRand << 16) ^ (m_nRand >> 7)) & 0x7fffffff; } public void run() { Date dateStart = new Date(); System.out.println("thread " + m_nID + " start..."); int[] anArray = new int[ARRAY_SIZE]; for(int n = 0; n < TIMES; ++n) { for(int a = 0; a < ARRAY_SIZE; ++a) { int r1 = rand(); int r2 = rand(); int r3 = rand(); int r4 = rand(); // 適当に演算 anArray[a] += ((r1 + r2 * r4) | (r3 >> (r4 & 0x06))) ^ r1; anArray[a] &= 0x7fffffff; } } // 何の結果かわからないけど、結果算出 for(int i = 0; i < ARRAY_SIZE; ++i) { m_nResult += anArray[i]; } Date dataEnd = new Date(); System.out.println("thread " + m_nID + " end / " + (dataEnd.getTime() - dateStart.getTime()) + "ms"); } public static void main(String[] str) { int nThreadCount = Integer.parseInt(str[0]); Bench[] anTests = new Bench[nThreadCount]; for(int i = 0; i < nThreadCount; ++i) anTests[i] = new Bench(i); Date pcStart = new Date(); for(int i = 0; i < nThreadCount; ++i) anTests[i].start(); for(int i = 0; i < nThreadCount; ++i) { try { anTests[i].join(); // コレはひどい } catch(InterruptedException e) {} } Date pcEnd = new Date(); System.out.println((pcEnd.getTime() - pcStart.getTime()) + "ms"); } };
Dual Core / Dual CPU は、モロに特性が出てて面白いなぁ とまず思った俺。(ぉ
コアが2つあるわけですから、スレッド2つまでであればパフォーマンス落ちないということがグラフからはっきりわかりますね。 (ちょっとあがってる気もするけれど、JavaVM が勝手に "大人の事情" な何かをやってるとする:ぉ)
で、下2つのパフォーマンスが良かったCPU(Athlon 4400+ と ATOMね)だけを抜き出してみます。
ATOM すげー。超すげー。 一番処理速度が速いじゃないですか! なんでかスレッドが増える度の処理速度が安定していませんけれども(ぉ)、それでも大変早い。
そして4スレッド目から5スレッド目に一気に右肩上がりな所をみると、ハイパースレッディングってのはまぁ効果があるとみて良いのかもしれません。 一時期「いみねぇよアレ」とか言われてましたけれどもそんなことはないのかも。(2スレッド目から3スレッド目にかけて極端な右肩上がり *ではない* のが謎ですけども…)
そして2スレッドまでの様子を見る限り、コア単位の処理速度ってのは「Athlon 64 XP 4400+」とほぼ同じなのかも。 8ワット でココまで処理できるって凄いですなー。Athlon 64 XP 4400+ は、確か 65ワット ぐらい消費するはずなのに…(ぉ
ところで。
冒頭でも解説したとおり、Athlon 4400+ は、ウチのメインマシンなんですよね。 新入りの ATOM 君の方がパフォーマンス高いんですよね。
ね。
ね。
ね。
…どうしようかしら。(ぉ orz
と言ったものの
あのソースコードで凄い気になってることがあるんです。
1万個のintの配列作ってるじゃないですか。すなわち40KBの配列。 これが8スレッドになると、合計320KBも食うことになるわけですけど、これ CPU のキャッシュに乗るの? みたいな。
Pen3 でも L2 で 512KB ぐらいは乗っていたような気がするので、大丈夫だとは思うんですが…… もしあふれていたら、このベンチマーク「メモリバスベンチ」になりかねない…と。 キャッシュから外れるんだ。メモリにアクセスするしかないじゃない。
というわけで、ちょっとこのベンチは間違ったかなぁ…と(ぉ ^^;
そもそも、JavaVM上で走らせている以上、んなこと気にするレベルじゃねーだろ話もあったり無かったりも……
うーん、もうちょっとベンチの内容を再考するかしら……