日記/2008-09-17/gcc-4.x の SIMD 命令サポート その2
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
] [
リンク元
]
開始行:
* gcc-4.x の SIMD 命令サポート その2 [#ae8cd212]
新しいマシンを買い,Linux マシンが Celeron D にグレードア...
というわけで,今回は SSE/SSE2 について.
** SSE レジスタ [#a1f8ecee]
SSE では 128 ビット長の''専用''レジスタを 8 本新設してい...
つまり,[[前回>日記/2008-09-03/gcc-4.x での SIMD 命令サポ...
で,レジスタの中身ですが,SSE レジスタ 1 本に
- SSE では 32bit 単精度 (float) 型を 4 本
- SSE2 では 64bit 倍精度 (double) 型を 2 本
を格納し,SIMD 演算を行うことができます.
** 参考文献 [#n4e9b777]
#af_amazon(4789833429,right)
参考となる書籍など.
- gcc-4.3 の info
-- SIMD 命令の gcc 上の取扱いについて書いてあります.
- [http://developer.intel.com/products/processor/manuals/...
-- インテルの web サイトにある,IA-32 アーキテクチャのマ...
- [http://www.amazon.co.jp/dp/4789833429 x86アセンブラ入...
-- CQ 出版社から出ている本.もちろん日本語です.
#clear
** おおまかな枠組み [#ea83c11a]
前回と一緒で
+ SIMD のレジスタにあった型の変数を定義して
+ ビルトイン関数で演算を記述
+ -mXXX オプションを付けてコンパイル
です.
** プログラム例 [#gee400c0]
前回と同様にベンチマークを兼ねてプログラムを作ってみまし...
#ref(benchmark.c)
お題も前回と同じく積和演算です.
** 型宣言 [#ud57c751]
まずは SSE での「単精度 x 4 本」の構成の変数の型宣言から.
typedef float v4sf __attribute__ ((vector_size(16))) __a...
前回と違っておしりに
__attribute__((aligned(16)))
なんて属性がついてますね.
これは
> 変数を 16 で割り切れるアドレスに割り当てよ
という属性です.
これは,実は SSE レジスタのロード・ストア時においてこの様...
この制限を無視するとどうなるかというと,Segmentation faul...
ARM や MIPS などの変数のアラインメントと似たような感じで...
ここで 1 つ注意.この aligned(16) 属性は
v4sf a;
のような変数の宣言では有効に機能しますが
v4sf *a = malloc ( sizeof(v4sf) );
のような動的メモリ割り当てではうまく働きません.また
float a[2];
*(v4sf *)&a[0] = b;
のようなキャストもだめです.
つまり,既に割り当てられている領域を「16 で割り切れるアド...
ついでに「倍精度 x 2」の型宣言.
typedef double v2df __attribute__ ((vector_size(16))) __...
制限・注意は v4sf 型と一緒です.
** SSE/SSE2 命令 [#l1921250]
まずは v4sf 型について.
これらは SSE 命令セットに属します.
:v4sf __builtin_ia32_addps (v4sf a, v4sf b)|
v4sf 型に対する SIMD の足し算です.a + b の結果を返します.
:v4sf __builtin_ia32_mulps (v4sf a, v4sf b)|
v4sf 型に対する SIMD 掛け算です.a * b の結果を返します.
v2df 型について.これらは SSE2 命令セットです.
:v2df __builtin_ia32_addpd (v2df a, v2df b)|
v2df 型に対する SIMD 足し算.a + b の結果を返します.
:v2df __builtin_ia32_mulpd (v2df a, v2df b)|
v2df 型に対する SIMD 掛け算.a * b の結果を返します.
これらの明示的なビルトイン関数以外にも例えば
v2sf a = { 1.0, 2.0, 3.0, 4.0 };
のような代入文でも SSE 命令が使用されます.
つまり,単なる代入においても右辺と左辺の変数領域は 16 で...
うっかりすると忘れてしまうので注意しましょう.
** ベンチマーク環境 [#nd849a52]
結果に先立って,ベンチマーク環境について書いときます.
$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 15
model : 4
model name : Intel(R) Celeron(R) CPU 2.66GHz
stepping : 9
cpu MHz : 2667.096
cache size : 256 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 5
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtr...
acpi mmx fxsr sse sse2 ss ht tm pbe lm constant_tsc pebs...
lahf_lm
bogomips : 5340.17
clflush size : 64
power management:
** ベンチマーク結果 [#ucd2bcab]
まずは最適化オプションなしでこんな感じ.
$ gcc -msse2 benchmark.c
$ ./a.out
SSE double: 9.620000 3998000.000000
norm double: 20.890000 3998000.000000
SSE float: 4.910000 3998000.000000
norm float: 20.560000 3998000.000000
中央のカラムが演算にかかった CPU 時間で,単位は秒です.
最適化オプションを付けてみましょう.
$ gcc -msse2 -O2 benchmark.c
$ ./a.out
SSE double: 2.680000 3998000.000000
norm double: 4.910000 3998000.000000
SSE float: 1.070000 3998000.000000
norm float: 4.760000 3998000.000000
かなり違いますね.
ループ展開もしてみましょう.
$ gcc -msse2 -O2 -funroll-loops benchmark.c
imai@JR0BAK:~/progs/sse$ ./a.out
SSE double: 2.380000 3998000.000000
norm double: 4.850000 3998000.000000
SSE float: 1.060000 3998000.000000
norm float: 4.670000 3998000.000000
ちょっぴり速くなりましたが,3DNow! のときのように劇的な効...
ループ展開したことで SSE/SSE2 の演算では多くの SSE レジス...
にもかかわらずあまり速度が上がってないのは,実は SSE/SSE2...
最後の例で SSE/SSE2 と x87 の速度を比較すると,SSE/SSE2 ...
- 単精度で 4.4 倍
- 倍精度で 2.0 倍
のスピードアップが図られたことになります.
終了行:
* gcc-4.x の SIMD 命令サポート その2 [#ae8cd212]
新しいマシンを買い,Linux マシンが Celeron D にグレードア...
というわけで,今回は SSE/SSE2 について.
** SSE レジスタ [#a1f8ecee]
SSE では 128 ビット長の''専用''レジスタを 8 本新設してい...
つまり,[[前回>日記/2008-09-03/gcc-4.x での SIMD 命令サポ...
で,レジスタの中身ですが,SSE レジスタ 1 本に
- SSE では 32bit 単精度 (float) 型を 4 本
- SSE2 では 64bit 倍精度 (double) 型を 2 本
を格納し,SIMD 演算を行うことができます.
** 参考文献 [#n4e9b777]
#af_amazon(4789833429,right)
参考となる書籍など.
- gcc-4.3 の info
-- SIMD 命令の gcc 上の取扱いについて書いてあります.
- [http://developer.intel.com/products/processor/manuals/...
-- インテルの web サイトにある,IA-32 アーキテクチャのマ...
- [http://www.amazon.co.jp/dp/4789833429 x86アセンブラ入...
-- CQ 出版社から出ている本.もちろん日本語です.
#clear
** おおまかな枠組み [#ea83c11a]
前回と一緒で
+ SIMD のレジスタにあった型の変数を定義して
+ ビルトイン関数で演算を記述
+ -mXXX オプションを付けてコンパイル
です.
** プログラム例 [#gee400c0]
前回と同様にベンチマークを兼ねてプログラムを作ってみまし...
#ref(benchmark.c)
お題も前回と同じく積和演算です.
** 型宣言 [#ud57c751]
まずは SSE での「単精度 x 4 本」の構成の変数の型宣言から.
typedef float v4sf __attribute__ ((vector_size(16))) __a...
前回と違っておしりに
__attribute__((aligned(16)))
なんて属性がついてますね.
これは
> 変数を 16 で割り切れるアドレスに割り当てよ
という属性です.
これは,実は SSE レジスタのロード・ストア時においてこの様...
この制限を無視するとどうなるかというと,Segmentation faul...
ARM や MIPS などの変数のアラインメントと似たような感じで...
ここで 1 つ注意.この aligned(16) 属性は
v4sf a;
のような変数の宣言では有効に機能しますが
v4sf *a = malloc ( sizeof(v4sf) );
のような動的メモリ割り当てではうまく働きません.また
float a[2];
*(v4sf *)&a[0] = b;
のようなキャストもだめです.
つまり,既に割り当てられている領域を「16 で割り切れるアド...
ついでに「倍精度 x 2」の型宣言.
typedef double v2df __attribute__ ((vector_size(16))) __...
制限・注意は v4sf 型と一緒です.
** SSE/SSE2 命令 [#l1921250]
まずは v4sf 型について.
これらは SSE 命令セットに属します.
:v4sf __builtin_ia32_addps (v4sf a, v4sf b)|
v4sf 型に対する SIMD の足し算です.a + b の結果を返します.
:v4sf __builtin_ia32_mulps (v4sf a, v4sf b)|
v4sf 型に対する SIMD 掛け算です.a * b の結果を返します.
v2df 型について.これらは SSE2 命令セットです.
:v2df __builtin_ia32_addpd (v2df a, v2df b)|
v2df 型に対する SIMD 足し算.a + b の結果を返します.
:v2df __builtin_ia32_mulpd (v2df a, v2df b)|
v2df 型に対する SIMD 掛け算.a * b の結果を返します.
これらの明示的なビルトイン関数以外にも例えば
v2sf a = { 1.0, 2.0, 3.0, 4.0 };
のような代入文でも SSE 命令が使用されます.
つまり,単なる代入においても右辺と左辺の変数領域は 16 で...
うっかりすると忘れてしまうので注意しましょう.
** ベンチマーク環境 [#nd849a52]
結果に先立って,ベンチマーク環境について書いときます.
$ cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 15
model : 4
model name : Intel(R) Celeron(R) CPU 2.66GHz
stepping : 9
cpu MHz : 2667.096
cache size : 256 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 5
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtr...
acpi mmx fxsr sse sse2 ss ht tm pbe lm constant_tsc pebs...
lahf_lm
bogomips : 5340.17
clflush size : 64
power management:
** ベンチマーク結果 [#ucd2bcab]
まずは最適化オプションなしでこんな感じ.
$ gcc -msse2 benchmark.c
$ ./a.out
SSE double: 9.620000 3998000.000000
norm double: 20.890000 3998000.000000
SSE float: 4.910000 3998000.000000
norm float: 20.560000 3998000.000000
中央のカラムが演算にかかった CPU 時間で,単位は秒です.
最適化オプションを付けてみましょう.
$ gcc -msse2 -O2 benchmark.c
$ ./a.out
SSE double: 2.680000 3998000.000000
norm double: 4.910000 3998000.000000
SSE float: 1.070000 3998000.000000
norm float: 4.760000 3998000.000000
かなり違いますね.
ループ展開もしてみましょう.
$ gcc -msse2 -O2 -funroll-loops benchmark.c
imai@JR0BAK:~/progs/sse$ ./a.out
SSE double: 2.380000 3998000.000000
norm double: 4.850000 3998000.000000
SSE float: 1.060000 3998000.000000
norm float: 4.670000 3998000.000000
ちょっぴり速くなりましたが,3DNow! のときのように劇的な効...
ループ展開したことで SSE/SSE2 の演算では多くの SSE レジス...
にもかかわらずあまり速度が上がってないのは,実は SSE/SSE2...
最後の例で SSE/SSE2 と x87 の速度を比較すると,SSE/SSE2 ...
- 単精度で 4.4 倍
- 倍精度で 2.0 倍
のスピードアップが図られたことになります.
ページ名:
-->