Coelacanth's Dream

AMD GPU の世代における FMA、MAD 命令の微妙な仕様と違い Part2

約 1年前に AMD GPU における、各世代の FMA, MAD 命令の性能について記事を書いたが、最近になってまた調べ直した結果、分かったことがあったため Part2 を書くことにした。
AMD GPU の世代における FMA、MAD 命令の微妙な仕様と違い | Coelacanth’s Dream

AMD GPU アーキテクチャにおいて、初期の GCN から Polaris1x /VegaM までを含む GFX6-8 では FMA の処理が MAD の 4倍遅く、Vega, Navi の世代である GFX9-10 では FMA も MAD も同じ処理性能であり、RDNA 2 /GFX10.3 では MAD をサポートせず、MUL と ADD 2つに分けて処理するため遅くなり、FMA を使う方が速くなるとされる。

       /*        |---------------------------------- Performance & Availability --------------------------------|
        *        |MAD/MAC/MADAK/MADMK|MAD_LEGACY|MAC_LEGACY|    FMA     |FMAC/FMAAK/FMAMK|FMA_LEGACY|PK_FMA_F16,|Best choice
        * Arch   |    F32,F16,F64    | F32,F16  | F32,F16  |F32,F16,F64 |    F32,F16     | F32,F16  |PK_FMAC_F16|F16,F32,F64
        * ------------------------------------------------------------------------------------------------------------------
        * gfx6,7 |     1 , - , -     |  1 , -   |  1 , -   |1/4, - ,1/16|     - , -      |  - , -   |   - , -   | - ,MAD,FMA
        * gfx8   |     1 , 1 , -     |  1 , -   |  - , -   |1/4, 1 ,1/16|     - , -      |  - , -   |   - , -   |MAD,MAD,FMA
        * gfx9   |     1 , 1 , -     |  1 , -   |  1 , -   | 1 , 1 ,1/16|     - , -      |  - , 1   |   2 , -   |FMA,MAD,FMA
        * gfx10  |     1 , 1 , -     |  1 , -   |  1 , -   | 1 , 1 ,1/16|     1 , 1      |  - , -   |   2 , 2   |FMA,MAD,FMA
        * gfx10.3|     - , - , -     |  - , -   |  - , -   | 1 , 1 ,1/16|     1 , 1      |  1 , -   |   2 , 2   |  all FMA
        *
        * Tahiti, Hawaii, Carrizo, Vega20: FMA_F32 is full rate, FMA_F64 is 1/4
        *
        * gfx8 prefers MAD for F16 because of MAC/MADAK/MADMK.
        * gfx9 and newer prefer FMA for F16 because of the packed instruction.
        * gfx10 and older prefer MAD for F32 because of the legacy instruction.
        */

Index

FMA と MAD の性能違い

AMD GPU アーキテクチャのバージョンを示す GPUID と、そのアーキテクチャでサポートしている機能について、LLVM では llvm-project/AMDGPU.td に記述されている。
そこで FMA命令が MAD命令 (MUL + ADD) と同速で処理できるかというのは FeatureFastFMAF32 という機能名で管理されている。
それを辿ると、上記の GFX6-8 世代は MAD の方が遅い、というのはだいぶざっくりとした説明で、実際には GFX6-8 世代の一部は FMA と MAD の処理性能が同じであることが分かる。
Tahiti (gfx600), Hawaii (gfx702), Hawaii Pro (gfx701), Carrizo (gfx801) が該当し、それらは同時に FP64演算を FP32 の半分のレートで実行する HalfRate64Ops もサポートしている。
Hawaii (gfx702) だけ HalfRate64Ops をサポートしていないとしているが、LLVM 内の AMD GPU ユーザーガイド llvm-project/AMDGPUUsage.rst によると製品によって Hawaii /Pro を分けているため、コンシューマ向けでは FP64演算性能を抑えるための方策ではないかと思われる。
FeatureFastFMAF32Vega (GFX9) から世代全体でサポートするようになり、これは上記の説明と一致する。

そして、GFX6-8 世代で FeatureFastFMAF32 をサポートする AMD GPUアーキテクチャでは、HalfRate64Ops も(ほぼ) 同時にサポートするというのが性能に関係すると思われる。
AMD が公開している AMD GPU の ISA (Instruction Set Architecture) ドキュメントには、FMA命令 V_FMA_F32 の概要部分に Only for double-precision parts. という記述がある。

Fused single-precision multiply-add. Only for double-precision parts.

これが、倍精度 (FP64) 演算ユニットでのみ V_FMA_F32 が実行可能という意味ならば、FeatureFastFMAF32HalfRate64Ops が同時にサポートされることと、コンシューマ向け AMD GPUアーキテクチャでは倍精度演算ユニットを減らしているため、FMA が MAD より遅くなることにも納得がいく。
ただ 4倍遅い、という具体的な数字については不明。ドキュメント内ではそこまで言及はしていなかった。
コンシューマ向けでは FP32:FP64 = 16:1 という比率になっているはずだが、どういう実装と計算式なのか。

Vega (GFX9) では単精度演算ユニットでも V_FMA_F32 を実行可能となるよう改良され、FMA と MAD の処理性能が同じになったのだと思われる。
また、今まで見落としていたが、Hot Chips 29 (2017) における Vega アーキテクチャ の発表でこの点に触れており、Full rate IEEE compliant FMA32 としてアピールされている。

FMA と MAD の精度違い

FMA も MAD の計算精度について、MAD は乗算の結果を、掛けた値と同じビット数に丸めてから加算の処理を行なうが、 FMA は乗算の結果を掛けた値の倍のビット長で保持してから加算を行なうため、FMA の方が計算精度が高くなる。
参考: 科学技術計算向け演算能力が引き上げられたGPUアーキテクチャ「Fermi」 (2) 科学技術計算向けのさまざまな工夫 | マイナビニュース

Vega (GFX9) から ISAドキュメントでは FMA と MAD の計算精度、丸め誤差 ULP (Unit in the Last Place) についても記述するようになり、V_MAD_F32 は 1ULP、V_FMA_F32 は 0.5ULP としている。
IEEE-754 では丸め誤差 0.5ULP を正しい結果としており、V_FMA_F32 がそれに準拠した命令となる。

参考リンク