「偽共有」によって導入されたパフォーマンスの低下を再現するために、Java で次のテスト クラスを作成しました。
基本的に、配列の「サイズ」を 4 からはるかに大きな値 (たとえば 10000) に微調整して、「偽共有現象」をオンまたはオフにすることができます。具体的には、サイズ = 4 の場合、異なるスレッドが同じキャッシュ ライン内の値を更新する可能性が高くなり、キャッシュ ミスがより頻繁に発生します。理論的には、テスト プログラムは、サイズ = 4 よりもサイズ = 10000 の方がはるかに高速に実行されるはずです。
2 つの異なるマシンで同じテストを複数回実行しました。
マシン A: Intel® Core™ i5-3210M プロセッサー (2 コア、4 スレッド) Windows 7 64 ビット搭載の Lenovo X230 ラップトップ
サイズ = 4 => 5.5 秒
サイズ = 10000 => 5.4 秒
マシン B: Dell OptiPlex 780、Intel® Core™2 Duo プロセッサ E8400 (2 コア) Windows XP 32 ビット搭載
サイズ = 4 => 14.5 秒
サイズ = 10000 => 7.2 秒
後で他のいくつかのマシンでテストを実行しましたが、明らかに偽共有は特定のマシンでのみ顕著になり、そのような違いを生む決定的な要因を理解できませんでした.
誰か親切にこの問題を見て、このテスト クラスで導入された偽共有が特定のマシンでのみ顕著になった理由を説明できますか?
public class FalseSharing {
interface Oper {
int eval(int value);
}
//try tweak the size
static int size = 4;
//try tweak the op
static Oper op = new Oper() {
@Override
public int eval(int value) {
return value + 2;
}
};
static int[] array = new int[10000 + size];
static final int interval = (size / 4);
public static void main(String args[]) throws InterruptedException {
long start = System.currentTimeMillis();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Array index:" + 5000);
for (int j = 0; j < 30; j++) {
for (int i = 0; i < 1000000000; i++) {
array[5000] = op.eval(array[5000]);
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Array index:" + (5000 + interval));
for (int j = 0; j < 30; j++) {
for (int i = 0; i < 1000000000; i++) {
array[5000 + interval] = op.eval(array[5000 + interval]);
}
}
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Array index:" + (5000 + interval * 2));
for (int j = 0; j < 30; j++) {
for (int i = 0; i < 1000000000; i++) {
array[5000 + interval * 2] = op.eval(array[5000 + interval * 2]);
}
}
}
});
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Array index:" + (5000 + interval * 3));
for (int j = 0; j < 30; j++) {
for (int i = 0; i < 1000000000; i++) {
array[5000 + interval * 3] = op.eval(array[5000 + interval * 3]);
}
}
}
});
t1.start();
t2.start();
t3.start();
t4.start();
t1.join();
t2.join();
t3.join();
t4.join();
System.out.println("Finished!" + (System.currentTimeMillis() - start));
}
}