トップページ

最新記事

half2の水平加算

はじめに

SIMD(Single Instruction Multiple Data)ではその名の通り複数のデータに対して同じ処理を行います.

水平加算はこの複数のデータ間での加算処理のことです.

CUDAのFP16 SIMD

CUDAではFP16変数2つに対するSIMDがあります. 特に名前がついているわけではないようですが,ここではPTXの命令型をとってf16x2と呼びます. 変数型としてはhalf2になります.

f16x2にはadd,sub,fmaなど垂直方向(?)の命令は備わっているのですが,水平方向の命令はありません. でも,何かと使うんですよね,水平方向.

で,どう実装するのが速いのか比較してみました.

結論から言うとどう実装しても変わりません.

(そもそもボトルネックになるような処理でもないですよね...)

実験構成

実装1 : シンプルに

__high2half,__low2half関数を使ってhalf2から2つのhalfを切り出し,足す.

で,これをPTXにするとどうなるかというと,上位下位に分解する命令が2回入ります.

分解は1回でいいはずなので,これを1回にするのが実装2.

実装2 : 分解処理を減らす

PTXでちょろっと.

asmにhalf,half2は直接渡せないのでreinterpret_castを駆使してshort,unsigned intで渡します.

PTXにすると思惑通り分解は1回となっています.

でもreinterpret_castが気持ち悪いので,それを改善したのが実装3.

(cuda_fp16.hppの中もreinterpret_castづくしなのでいいといえばいいのですが...)

実装3 : union

普段あまり使わないけど使えると嬉しくなるunion

PTXで見てみると分解が1回だけなのが確認できます.

実験

  • NVIDIA Geforce GTX 1080
  • CUDA 10.0.130
  • 1048576回試行

実験結果

Avg Min Max Name
1.0470us 992ns 8.8320us (実装1) simple
1.0310us 992ns 8.3200us (実装2) ptx
1.0290us 960ns 8.3840us (実装3) union

思うこと

大して変わらないじゃん.

それもそのはず,PTXからSASS(バイナリ)に落ちる段階ですべて同じコードになります.

結論

一番読みやすくてメンテナンスしやすいコードを書くといいと思うよ.

記事作成日:2019-01-14