このブログは、株式会社フィックスターズのエンジニアが、あらゆるテーマについて自由に書いているブログです。
メモリ事業部のoshioです。
普段は次世代SSDの開発に関わっていて、Write/Readのピーク性能やFTL(Flash Translation Layer)について興味があります。
今回はNVMe ver. 1.2で追加された少し変わった機能、HMBについて紹介します。
最近のSSDは内部にDRAMを積んでおり、Write/Readのバッファに使ったり、FTLのデータを置いたりして高速にデータの読み書きができるようになっています。
しかし、スマートフォンやタブレット、ラップトップ向けのSSDはChipサイズやコストを優先し、DRAMを積んでいないモデルもあります。DRAM-lessのSSDは内部のわずかなSRAMと、アクセスが遅いNAND Flashでやりくりする必要があり、性能面(特に広域ランダムアクセス)では劣っていました。
その課題を解決するべく、DRAM-lessのSSDが、Host機器のDRAMを間借りし、バッファとして使用できるような規格がNVMe ver. 1.2からオプションで追加されました。
それがHMB (Host Memory Buffer) です。
HMBサポートのSSDを探していたところ、シリコンパワーの製品がAmazonで売っていたので入手しました。
P32A80の256GBです。
https://www.silicon-power.com/web/jp/product-PCIe_Gen3x2_P32A80
Seq.Read 1600MB/s、Seq.Write 1000MB/s で、PCIe Gen3 2Laneでは一般的な性能が出るようですが、ランダムアクセスについては記載がありません。
保証を気にせずラベルを剥がしてコントローラを確認すると、Marvellの88NV1160というDRAM-lessコントローラでした。
https://www.marvell.com/storage/ssd/88nv11xx/
ubuntu 18.04のLinuxマシンにセカンダリとして挿してHMBをSSDに割り当てます。
HMBサイズはNVMeドライバのモジュールパラメータ max_host_mem_size_mb で変更可能で、dmesgを見るとどれだけ割り当てたのかわかります。NVMeドライバのデフォルトだと、最大で128MiBをHMBに割り当てます。
シリコンパワーのSSDを繋いでdmesgを見ると、ドライバ上限である128MiBを割り当てていました。
$ dmesg | grep nvme
[ 1.462920] nvme nvme0: allocated 128 MiB host memory buffer.
割り当てるサイズを変更する場合は、一度ドライバをunloadし、load時にパラメータで最大サイズを指定します。
64MiBに減らす例です。
$ sudo modprobe -r nvme
$ sudo modprobe nvme max_host_mem_size_mb=64
dmesgを見ると64MiBになっています。
[ 3649.335642] nvme nvme0: pci function 0000:01:00.0
[ 3649.441592] nvme nvme0: allocated 64 MiB host memory buffer.
Identifyコマンドで得られる情報の中に、HMPRE(Host Memory Buffer Preferred Size)という、SSD側が推奨するHMBサイズがあります。
$ sudo nvme id-ctrl /dev/nvme0 -H | grep -2 hmpre
cctemp : 393
mtfa : 0
hmpre : 61440
hmmin : 2048
tnvmcap : 0
hmpreは4KiB単位の値と規格で決まっていて、61440ということは240MiBを分けてくれ、と言っていることになります。
(hmminというのは、HMB機能を有効するために必要な最低サイズで、このSSDは8MiBだと言っています。)
今回は
の3パターンを試してみることにします。
計測環境はubuntu 18.04 (Linux 4.15.0-23-generic x86_64)、ツールはfio-3.1を使いました。
予めSSDの全領域にSeq.Writeをしてから、1GiB範囲~238GiB範囲(ほぼ全域)のRandom Readを計測しました。以下のスクリプトです。
#!/bin/bash
for r in 1 2 4 8 `seq 16 16 237` 238
do
f=`printf "%03d" $r`
echo $f
sudo fio --name="$f" \
--filename=/dev/nvme0n1 \
--rw=randread \
--bs=4k \
--direct=1 \
--ioengine=libaio \
--iodepth=16 \
--numjobs=8 \
--group_reporting \
--runtime=10 \
--size="$r"g \
--output rr-"$f".log
done
結果を見ると、そもそもIOPSの絶対値が微妙な性能なのですが、今回はHMBサイズの違いに着目します。
HMB OFFだと、1GiB範囲が20KIOPS、アクセス範囲を広げると10Kを切ってまっ平らなグラフです。遅いですね。
HMBを128MiB割り当てた場合は、1GiB範囲が58KIOPSまでアップし、128GiB範囲までは50KIOPSくらいを維持しています。
このことから、このSSD(Marvellのコントローラ)は、HMBにFTLのデータをキャッシュしており、128MiBだと128GiB範囲をカバーするデータしかキャッシュできてなさそう、ということがわかります。それ以上の広域ランダムアクセスを行うとFTLデータのスラッシングが発生し、性能がガタ落ちになるようです。
SSDの要求どおり240MiBを割り当てると、おそらく全域のFTLデータがHMB領域に展開できているようで、アクセス範囲を広げても一切性能低下がありません。すごい!
なぜかピーク性能も128MiBのときの58KIOPSから73KIOPSくらいまで上がっていますが、これはFTLのキャッシュの仕組みが不要になり、キャッシュラインの検索や追い出しといった処理がなくなった差分かと思います。
Random Writeも、Readと同様にアクセス範囲を広げながら計測しました。
各計測前に、全領域のDeallocateを実行し、それまでの論物を吹き飛ばして条件をそろえました。(本当はFomartNVMコマンドを打ちたいのですが、このSSDは非サポートでした)
スクリプトを以下に載せます。sleep 10というのは、SSDを冷ましてあげたいという気持ちがこめられています。
#!/bin/bash
for r in 1 2 4 8 `seq 16 16 237` 238
do
# Deallocate
sudo nvme dsm /dev/nvme0n1 -n 1 -d 1 -s 0 -b 500118192
f=`printf "%03d" $r`
echo $f
sudo fio --name="$f" \
--filename=/dev/nvme0n1 \
--rw=randwrite \
--bs=4k \
--direct=1 \
--ioengine=libaio \
--iodepth=16 \
--numjobs=8 \
--group_reporting \
--runtime=10 \
--size="$r"g \
--output rw-"$f".log
sleep 10
done
Random Readと違ってHMBを割り当てても性能が変化していません。ということは、このMarvellのコントローラは、Write時に更新したFTLデータをHMBには置いていないのでは、と思われます。
HMBには更新されていない、CleanなFTLデータをキャッシュし、DirtyなデータはSSD内部のSRAMに置いてすぐNAND Flashに不揮発化しているのでしょう。(推測ですが…)
Write時にHMBが活かせないということは、Write/Readが混在するようなパターンにも効き目がないと思い、Write/Read 50% Mixも実施してみました。
HMB OFFは1GiB範囲は90KIOPS以上出るものの、1GiB範囲を超えると急激に性能が低下します。
HMB 128MiBと240MiBは性能に差がなく、45GiB範囲くらいまではゆるやかに性能が低下し、それ以降200GiB範囲くらいまではHMB OFFに負けてしまっています。
Read時にHMBに置いたFTLデータもすぐにWriteで更新されてDirtyになり、HMB側のFTLはinvalidateされ、HMBにデータを転送するレイテンシが無駄にかかってしまっているように見えます。(これも推測ですが…)
Marvellのコントローラを載せたシリコンパワーのDRAM-less SSDは、HMBを割り当てるとその分だけ広域Random Read性能がアップします。
ただし、Writeには効果がないようで、CleanなFTLデータのキャッシュとしてHMBを利用していると思われます。
Write処理もHMBを活かして高速化してほしいところですが、HMBにDirtyなデータをたくさん置くと、何か致命的なエラーが発生した際に失うデータも大きくなるというトレードオフがあるため、このコントローラは安全側に倒した設計をしているのでしょう。
まだまだサポートしている製品がほとんどないHMB機能ですが、その分今後が楽しみですね。
それでは。
コンピュータビジョンセミナーvol.2 開催のお知らせ - ニュース一覧 - 株式会社フィックスターズ in Realizing Self-Driving Cars with General-Purpose Processors 日本語版
[…] バージョンアップに伴い、オンラインセミナーを開催します。 本セミナーでは、...
【Docker】NVIDIA SDK Managerでエラー無く環境構築する【Jetson】 | マサキノート in NVIDIA SDK Manager on Dockerで快適なJetsonライフ
[…] 参考:https://proc-cpuinfo.fixstars.com/2019/06/nvidia-sdk-manager-on-docker/ […]...
Windowsカーネルドライバを自作してWinDbgで解析してみる① - かえるのほんだな in Windowsデバイスドライバの基本動作を確認する (1)
[…] 参考:Windowsデバイスドライバの基本動作を確認する (1) - Fixstars Tech Blog /proc/cpuinfo ...
2021年版G検定チートシート | エビワークス in ニューラルネットの共通フォーマット対決! NNEF vs ONNX
[…] ONNX(オニキス):Open Neural Network Exchange formatフレームワーク間のモデル変換ツー...
YOSHIFUJI Naoki in CUDAデバイスメモリもスマートポインタで管理したい
ありがとうございます。別に型にこだわる必要がないので、ユニバーサル参照を受けるよ...