LinuxのSSD向けのコード
相変らずkosakiさんの記事は(面白い&&ためになる)なぁ
今月号のkernel watchにあった記事で、
最近のATAコマンドでは、接続先デバイスがSSDかどうかの情報を取得できるようになっており、それに対応した改善が入りました。
http://www.atmarkit.co.jp/flinux/rensai/watch2009/watch01b.html
1点目は、シークを削減するために入っていたI/Oスケジューラ(注6)です。これはリクエストを受け取ってもすぐさまI/Oを発行せず、しばらく後続I/Oを待つことがあります。しかし、デバイスがNon-rotating mediaだった場合(注7)は、この待ち処理をスキップし、レイテンシを改善しています。
とあったので、手元にチェックアウトしているコードを見てみた。
それっぽいキーワードでgrepしているとblock/以下に幾つか記述を発見。blk-core.cにも若干あったがこれはunplug時の挙動とrequestを組み上げるところだった。cfqのコードには以下のような記述があった。
static void cfq_arm_slice_timer(struct cfq_data *cfqd) { struct cfq_queue *cfqq = cfqd->active_queue; struct cfq_io_context *cic; unsigned long sl; /* * SSD device without seek penalty, disable idling. But only do so * for devices that support queuing, otherwise we still have a problem * with sync vs async workloads. */ if (blk_queue_nonrot(cfqd->queue) && cfqd->hw_tag) return;
以下、通常のdeviceのときの処理が続く。
コメントにもある通り、block deviceがnonrot(回転デバイスではない)かつハードウェアでキューイングが可能なときには即座に処理を投げるような動作になるようだ。
USBメモリデバイスなんかだとnonrotではあるけど、hw_tagは無さそうなのでこのコードの対象にはならないかもしれない。まっとうなSSDが対象という感じだろうか。
ちなみに、blk_queue_nonrotはマクロで、include/linux/blkdev.hに
#define blk_queue_nonrot(q) test_bit(QUEUE_FLAG_NONROT, &(q)->queue_flags)
と定義されている。
SSDを使うときはnoopにした方が速いんじゃないかと思っていたが、こういう対応コードが入ったのならCFQのままでも良いかもしれないな。そもそもCFQは結構複雑な事をやっているので、全編を理解しているとは言い難いのだけど。
ちなみに、もう一つのSSD向け最適化として挙げられていたDISCARDを使うようになるコードは、ファイルシステムからはbtrfsが使っているだけのようだ。まあ、unlink(2)とはかなりギャップがあるし、既存のコードに突っ込むには難しいのかもしれない。