GeForce RTX 5090 で FP64 エミュレーションを測る

cuBLAS 13 の固定小数点エミュレーション(尾崎スキーム系)を、FP64 を意図的に削られたコンシューマ GPU で実測した記録。測定日 2026-10-04

8.22×最大スループット向上 (n=16384, narrow range)
5.81×wide dynamic range でも
1.719native FP64 の上限 TFLOPS
14.124エミュレーションの TFLOPS
結論を一行で。このカードでは FP64 エミュレーションは native FP64 より速いだけでなく、精度も高い。native は累積丸めで相対誤差 4.0e-15 程度まで劣化するが、エミュレーションは整数で厳密に積和して最後に一度だけ丸めるため、正しく丸めた厳密値に一致する(相対誤差 0 または 1 ULP)。

なぜ測る価値があるのか

GeForce の倍精度は仕様上 FP32 の 1/64 に制限されている。一方で INT8 テンソルコアは3桁 TOPS ある。CUDA 13.0 Update 2 で cuBLAS に入った固定小数点エミュレーションは、FP64 の積を整数の列に分解して INT8 テンソルコアで厳密に計算する——つまり潤沢な資源で枯渇した資源を代替する。

公開されている測定値はデータセンター GPU(native FP64 が速い機種)が中心で、そこでの利得は控えめに見える。しかし FP64 を削られたコンシューマ機では前提が逆であり、倍率が大きくなるはずだ。その実測値がほとんど見当たらないので、自分で測った。

測定環境

GPU / driver
NVIDIA GeForce RTX 5090, 617.14, 32607 MiB, 575.00 W, 3090 MHz
CPU
Intel64 Family 6 Model 198 Stepping 2, GenuineIntel
OS
Windows 10.0.26200
cuBLAS version (cublasGetVersion)
130202
CUDA DLL source
C:\shogi\fukauraou_v940
Python / NumPy
3.13.14 / 2.4.4
CUDA Toolkit もコンパイラも入れていない。TensorRT 版将棋エンジンの配布物に同梱されていた cublas64_13.dll と cudart64_13.dll を Python の ctypes から直接叩いている。DLL は読み取りのみで、エンジン側には一切変更を加えていない。

native FP64 とエミュレーションの比較

nnative FP64
TFLOPS
emulated, easy
TFLOPS
emulated, hard
TFLOPS
speedup
easy
speedup
hard
rel.err
native
rel.err
emu easy
rel.err
emu hard
20481.4825.4944.6303.71×3.13×1.47e-1500
40961.6569.9927.0236.03×4.24×2.19e-1500
81921.68713.7049.8088.12×5.81×2.29e-151.15e-160
163841.71914.1249.5328.22×5.55×3.98e-151.34e-161.34e-16
03.166.339.4912.715.820484096819216384matrix size n (n x n x n DGEMM)TFLOPS
native FP64 emulated, narrow range (easy) emulated, wide range (hard)
Throughput of cublasDgemm. Native FP64 is flat near the 1/64-rate ceiling; emulation scales with problem size.

読み方。native FP64 は行列サイズを変えても 1.48–1.72 TFLOPS で張り付いている。これがレート制限の壁。エミュレーション側は n とともに伸び、大きい行列ほど差が開く。入力の指数レンジが広い «hard» では必要マンティッサビットが増えるため利得は下がるが、それでも 5.8× を保っている。

精度は中央値より最悪値の方が差が大きい

n=16384相対誤差 中央値相対誤差 最悪値
native FP643.98e-154.31e-13
emulated (ADP)1.34e-164.44e-15

中央値では 30 倍の差だが、最悪値では 97 倍開く。native FP64 の誤差は n 項の総和にわたる累積なので、打ち消しが起きた要素で大きく悪化する。固定小数点エミュレーションは整数で厳密に積和して最後に一度だけ丸めるため、この種の最悪ケースを構造的に持たない。条件数を2乗する正規方程式のような用途では、この最悪値の差がそのまま効いてくる。

エミュレーション戦略の影響

CUBLAS_EMULATION_STRATEGY は performant(エミュレーションが得と判断したときだけ使う)と eager(積極的に使う)を取る。native がここまで遅いカードでは performant でも常にエミュレーションが選ばれるため、差は出なかった。

CUBLAS_EMULATION_STRATEGYinputTFLOPSrel.err (median)
performanteasy13.6341.17e-16
performanthard9.7670
eagereasy13.6881.17e-16
eagerhard9.7700

マンティッサビットと速度・精度のトレードオフ

既定では ADP(automatic dynamic precision)が入力から必要ビット数を自動決定する。CUBLAS_FIXEDPOINT_EMULATION_MANTISSA_BIT_COUNT で固定すると、速度と精度を直接交換できる。

mantissa bitsTFLOPS easyTFLOPS hardrel.err easyrel.err hard
895.39798.0991.30e-041.18e-03
1295.28598.6071.30e-041.18e-03
1660.85062.7574.88e-071.14e-05
2060.93362.4404.88e-071.14e-05
2441.92043.0621.77e-095.63e-08
2842.59943.1931.77e-095.63e-08
3230.14631.1049.12e-122.34e-10
4022.73223.3282.98e-149.89e-13
4817.79318.3081.61e-165.59e-15
5317.77518.3671.61e-165.59e-15
022.144.266.388.41108121620242832404853CUBLAS_FIXEDPOINT_EMULATION_MANTISSA_BIT_COUNTTFLOPS
easy hard
Throughput falls as more mantissa bits are requested: more bits means more INT8 slices per FP64 product.
1e-161e-131e-111e-81e-51e-38121620242832404853CUBLAS_FIXEDPOINT_EMULATION_MANTISSA_BIT_COUNTrelative error (median)
easy hard
Accuracy against the exactly-rounded product. Points at zero error are clamped to the bottom of the log axis.
ADP は無料ではない。同じ n=8192 で ADP は 13.704 TFLOPS、マンティッサを 48 bit に固定すると 17.793 TFLOPS で 1.30 倍速い。精度はそれぞれ 1.15e-16 と 1.61e-16、どちらも約 1 ULP で実用上同じ(しかも native の 2.29e-15 より一桁良い)。ADP は必要ビット数を決めるために入力を走査するぶんを払っている。入力のレンジが既知なら、固定した方が得だ。

階段状のプラトーが実装を露出させている。要求ビット数を増やしても値が動かない区間が並ぶのは、ビット数が離散的なスライス数に切り上げられているためだ。INT8 のスライスを何枚積むかという内部構造が、外から観測できてしまっている。

電力と電力効率

25 秒間 DGEMM を連続投入し、その間 nvidia-smi を 200 ms 間隔でサンプリングした。立ち上がりの 3 秒は定常状態から除外。

modesustained
TFLOPS
mean board
power
GFLOP/s
per watt
efficiency
vs native
SM clockpeak
temp
native1.716221 W7.81.00×2883 MHz55 °C
adp14.446567 W25.53.29×2195 MHz70 °C
mant4818.516570 W32.54.19×2181 MHz74 °C
mant08147.476575 W256.433.08×2490 MHz76 °C

native FP64 は電力枠を使い切れない。575 W の枠に対して 221 W しか引かず、SM クロックは 2883 MHz と高いまま張り付く。稼働しているダイ面積が小さすぎて、電力ではなくクロックで律速されているということだ。エミュレーション側は INT8 テンソルコアを動かすため 575 W まで上がり(電力上限に張り付く)、クロックは 2490 MHz に下がる。つまりこの技術は使われずに余っていた電力枠をスループットに変換している。

結果として、FP64 相当の精度を保ったまま電力効率が 4.2 倍になる。消費電力は 2.6 倍に増えるが、仕事量が 10.8 倍になるためだ。

測定方法

この結果が言っていないこと

再現手順

git clone https://github.com/soy-tuber/fp64-emulation-rtx5090
cd fp64-emulation-rtx5090

# CUDA 13.0u2 以降の cublas64_13.dll / cudart64_13.dll があるディレクトリ
set FP64EMU_CUDA_DIR=C:\path\to\cuda13\dlls

python run_all.py        # 全モードを掃引し results/*.json を作る
python make_report.py    # docs/index.html を生成する

個別に1モードだけ測る場合:

set CUBLAS_EMULATE_DOUBLE_PRECISION=1
python dgemm_bench.py --sizes 16384 --dists easy,hard --label emu

生データ

参考