NVMe HMB機能を使ってみた

2018年6月28日

メモリ事業部のoshioです。

普段は次世代SSDの開発に関わっていて、Write/Readのピーク性能やFTL(Flash Translation Layer)について興味があります。

今回はNVMe ver. 1.2で追加された少し変わった機能、HMBについて紹介します。

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を購入してみた

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/

Linuxマシンに接続

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だと言っています。)

今回は

  1. 全くHMBを割り当てない
  2. 128MiB割り当てる(Linuxドライバのデフォルト上限だけ分けてあげる)
  3. 240MiB割り当てる(このSSDの要求を満額のむ)

の3パターンを試してみることにします。

計測環境はubuntu 18.04 (Linux 4.15.0-23-generic x86_64)、ツールはfio-3.1を使いました。

4K Random Read

予め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のキャッシュの仕組みが不要になり、キャッシュラインの検索や追い出しといった処理がなくなった差分かと思います。

4K Random Write

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に不揮発化しているのでしょう。(推測ですが…)

Random Write/Read Mix

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機能ですが、その分今後が楽しみですね。

それでは。

Tags

About Author

oshio

Leave a Comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

Recent Comments

Social Media