JMF602搭載SSDのプチフリのメカニズムについて(1)

JMicron社製のJMF602コントローラを搭載したSSDをシステムドライブとして利用すると、「プチフリ」と呼ばれる現象が発生することがあります。プチフリとは、SSDに対して書き込みが発生した際に、マウスムーブ以外の一切の操作が受け付けられない状態が数秒〜数十秒続くという現象です。これは、該当するSSDを用いた全ての環境に発生するわけではなく、使用に耐えないレベルで発生することも、ほとんど体感できないこともあります。
今回の記事では、この現象がどのような場合に発生するのか、そのメカニズムを解析してみました。

まず、以下のベンチマーク結果を見てください。CrystalDiskMarkのRandom 4KBと、HD Tune Pro 3.5の4KBのRandom Writeの結果です。使用しているSSDはBuffaloのSHD-NSUM30(MLC,30GB,SATA)、OSはWindows XPチップセットはAMD780G(SB700)です。なお、ファイルシステムNTFSパーティションアラインメントはデフォルトのままです。

CrystalDiskMarkの結果では、書き込み速度は2.006MB/s、IOPSに直すと501になり、これは3.5インチHDDとほぼ同等です。それに比べて、HD Tuneではなんと書き込み速度は0.019MB/s、IOPSでは4と、信じがたいほど低い数値になっています。HD Tuneの結果をよく見ると、書き込み時間は、700ms、900ms、それらと比べるとほとんど0msの3カ所に分布しています。わずか4KBの書き込みにもかかわらず、700msとか900msもの時間を要しているのは明らかに異常です。他のSSDやHDDではこのような現象は起こらないため、プチフリはこの異常に遅い書き込み時間に起因すると考えるのが自然です。

これらの700msや900msといった異常に悪いレスポンスが一体どのような条件で発生するのか気になったので、いろいろと実験してみました。以下では、その解析の内容について述べたいのですが、その前にNANDフラッシュにデータを書き込む際の原理と、レスポンスを悪くする原因であるブロックコピーについて解説しておきたいと思います。

NANDフラッシュ内のデータ単位−ページ、ブロック

NANDフラッシュは、DRAMと異なり、書き込みと消去の方法に制限があります。
まず、「書き込み」は「ページ」という単位で行われます。SLCの場合、ページ内の任意のセルを"1"から"0"に立ち下げることでデータを書き込みます。MLCの場合は、"11"になっているセルを"00","01","10"のいずれかの状態にします。
一方、「消去」は「ブロック」という単位で行われます。消去が行われると、ブロック内の全てのセルがSLCの場合"1"に、MLCの場合"11"になります。注意するべきなのは、書き込みの場合は任意のセルのみを立ち下げることができましたが、消去の場合は有無を言わさず全てのセルが"1"または"11"になってしまうことです。
この枠組みがあるため、一度データが書かれたところに、データを上書きすることはできません。なぜなら、0から1に立ち上げなければならないセルが一つでもあったら、ブロック全体を消去する必要があるためです。そこで、データを上書きするためには、後述するダイナミックウェアレベリングという仕組みを用います。
なお、「ページ」の大きさは、MLCの場合4KB、SLCの場合2KBであることが多いようです。それに対し、「ブロック」の大きさは、MLCの場合512KB、SLCの場合128KBまたは256KBであることが多く、ページに対してかなり大きな単位になります。

マルチチャンネルアクセスによる高速化

NANDフラッシュを用いたSSDは、複数枚のNANDフラッシュに対し同時に読み書きを行うことで高性能を実現しています。
MLCFLASHは、1枚では読み込み20MB/s程度、書き込み10MB/s程度の性能しか出ません。JMF602の場合8チャンネル同時に読み書きを行うことで、読み込み150MB/s程度、書き込み90MB/s程度の性能となるようです。
この仕組みがあるため、SSD全体のページ・ブロックサイズは、FLASH1枚のサイズとチャンネル数を掛け算したものとなります。例えば、JMF602搭載のMLCタイプのSSDの場合、ページサイズは4KB×8=32KB、ブロックサイズは512KB×8=4MBとなります。

予備領域を用いたデータの上書き−ダイナミックウェアレベリング

NANDフラッシュ製品には、必ず予備領域が設けられています。
予備領域の意味は2つあります。1つは、セルの破損に対応するためです。NANDフラッシュのセルは、製造過程および使用中の双方において、破損が発生することがあります。破損が発生するセルの数は完全に確率論の問題なので、個体ごとに有効なブロック数が異なります。そこで、予備ブロックを数%設け、OSから認識されるディスクサイズが一定になるようにしています。JSMonitorでは、使用可能な総ブロック数(Good Block Count)と予備ブロック数(System Block Count)を取得することができます。同じ型番の製品でも総ブロック数には個体差がありますが、総ブロック数から予備ブロック数を引くと全て同じ数になっています。
もう1つが、これから述べるダイナミックウェアレベリングに使用するためです。
HDDは、OSが使用できる論理アドレスと物理上の位置が一致しています。すなわち、論理アドレスが若いほどデータが外周にあることを示しています。それに対し、SSDなどのNANDフラッシュ製品は、内部のデータの並びがシャッフルされています。これは、後述するウェアレベリングという仕組みを実現するためです。
NANDフラッシュは、書き込みを行うたびにセルが物理的に破損していき、最終的には壊れてしまいます。そのため、特定の場所だけに書き込みが集中すると、他は平気なのにその部分だけ破損が生じてしまうかもしれません。そこで、SSDをはじめとするNANDフラッシュ製品は、ウェアレベリングという仕組みを用いてできるだけ書き換え回数(=消去回数)を平均化します。
以下では、OSから扱うことのできるファイルシステム上のアドレスを「論理アドレス」、NANDフラッシュ製品内部のアドレスを「物理アドレス」と呼びます。OSが論理アドレス上の位置を指定して読み書きを行うと、コントローラチップがそれを物理アドレスに変換して実際の読み書きを行います。この仕組みを、アドレス変換と呼びます。

この図は、NANDフラッシュ製品のアドレス変換を簡単に図示したものです。このストレージは8つのブロックを持ち、そのうち3つを予備ブロックとしています(赤いブロックが予備ブロックを表します)。なお、1ブロックには4ページが含まれるものとし、簡単のため、1ページ=1KBとします。
このストレージは、OSからは全ブロック数から予備ブロック数を引いた5ブロック分、すなわち1KB×4ページ×5ブロック=20KBしか認識できません。また、赤い矢印が、論理アドレス物理アドレスの対応関係を表しています。論理アドレス上の最初の4KBが1番目のブロックに、次の4KBは3番目のブロックに…というように、実際のデータが書き込まれています。この場合、4KB単位でデータがシャッフルされています。

さて、このストレージの論理アドレスの3KBめにデータを書き込むことを考えてみます(図の緑の四角)。先ほど述べたとおり、Block1には既にデータが書き込まれています。そのため、直接Block1を書き換えることはできません。そこで、Block1ではなく、予備ブロック中の消去回数が最も少ないBlock5の、対応するページの位置にデータを書き込みます。この「消去回数が最も少ない」ブロックに書き込むというのがミソで、この方法がダイナミックウェアレベリングと呼ばれています。

それだけだと中途半端に1ページだけが更新された状態になってしまうので、今度はBlock1の残りの部分を全てコピーします(ブロックコピー)。

コピーが終了したら、アドレス変換テーブルを書き換え、論理アドレス上の最初の4KBがBlock5に対応するようにします。最後に、Block1を消去します。Block1の消去回数は1増えて、301になります。

以上のように、OSはわずか1KBの書き換えを行っただけなのに、ストレージ内部では合計で4KB(1ブロック分)の書き込みが行われてしまいます。実際のSSDの場合は問題はもっと深刻で、このままの実装だと、最悪の場合では、512Byteの書き込みしかしていないのに、1ブロック分(最大4MB)の書き込みが行われてしまいます。
実際には、それではパフォーマンスの面でも寿命の面でもよろしくないので、JMicronは予備ブロックの一部をシステムデータとし、見かけのパフォーマンスを稼いでいます。長くなってしまったので、肝心のその部分の解説は次回に回します。