はじめに
Processingで重い計算をするときに、「並列化すれば」とか「SIMD使えたら」とよく考えるので、簡単に使えたらと思い、調べた結果です。
結論
デフォルトで、SIMD有効になっているので、あとは、こちらに記載されている、条件を満たしたコードを書けばOKです。
環境
MacOS 13 (Apple M1 Pro)
Processing 4.2 (Java17で動作)
※Windows環境の場合、結果が異なるかもしれません。
SIMD環境の切り替え
※パソコンに詳しくない人はいじらないでください。
ProcessingのメニューからPreference(設定)を選択すると、ウィンドウの下の方にpreferences.txtへのリンクが表示されます。この中から、下記の行を見つけます。
run.options=
これを適当なテキストエディタで以下のように編集することで、SIMDの利用を「無効化」出来ます。
run.options=-XX:-UseSuperWord
つまり「デフォルトでオン」になっているので、コードを対応させれば、自動的にSIMD計算してくれる状態であったわけです。
なお、この設定ファイルの編集はProcessing起動時に行うと、Processing終了時に起動時の情報で上書きされるため、Processingが終了している状態で、編集をする必要があります。
比較
ざっくりと、
doubleは1.4倍
floatとintは2.7倍
byteは8.8倍
割り算は逆数取ってから、計算したほうが、やはり良さそう。
64bit長でpack演算されてる様子。
単純な積和命令でも、SIMD命令自体に置き換えると、高速化が見込めるので1.3倍になる。
byteは8個のpack演算効果プラス、SIMD命令効果がテキメン。
参考サイトよりも、JVMのバージョンが上がっているためか、より高速化(倍率)している。
メディア処理系(画像処理など)には、効果が高いので、意識していきたいです。
配列の型 | 演算 | SIMD無効[s] | SIMD有効[s] | 倍率 |
---|---|---|---|---|
double | += | 3.792 | 2.732 | 1.388 |
double | -= | 3.809 | 2.765 | 1.378 |
double | *= | 3.812 | 2.754 | 1.384 |
double | /= | 4.011 | 2.787 | 1.439 |
double | %= | - | - | - |
float | += | 3.237 | 1.212 | 2.671 |
float | -= | 3.247 | 1.224 | 2.653 |
float | *= | 3.240 | 1.213 | 2.671 |
float | /= | 3.627 | 1.204 | 3.012 |
float | %= | - | 483.779 | - |
int | += | 3.135 | 1.215 | 2.580 |
int | -= | 3.175 | 1.226 | 2.590 |
int | *= | 3.194 | 1.225 | 2.607 |
int | /= | 6.731 | 6.750 | 0.997 |
int | %= | 6.829 | 6.775 | 1.008 |
byte | += | 2.565 | 0.291 | 8.814 |
byte | -= | 2.558 | 0.291 | 8.790 |
byte | *= | 2.570 | 0.291 | 8.832 |
byte | /= | 6.606 | 6.624 | 0.997 |
byte | %= | 6.565 | 6.563 | 1.000 |
import java.util.Arrays;
static int SIZE = 1024 * 1024;
static double[] a = new double[SIZE];
static double[] b = new double[SIZE];
public static void vectorAdd() {
for (int i=0; i<a.length; i++) {
a[i] += b[i];
}
}
void setup() {
Arrays.fill(a, (double)1);
Arrays.fill(b, (double)2);
for (int i=0; i<100; i++) vectorAdd();
long t0 = System.currentTimeMillis();
for (int i=0; i<10000; i++) {
vectorAdd();
}
long t1 = System.currentTimeMillis();
System.out.printf("vector: %,d[msec]", t1 - t0);
}