明日から使えるSSDのTrimのTips

# はじめに
　最近のNANDフラッシュメモリをメディアとするSolid State Drive (SSD)において、ドライブ内部のデータ断片化（フラグメンテーション）を解消してWrite性能を回復させる手段として「Trimコマンド」が有効であることが広く知られています。

　これは、データセンターやエンタープライズ向けシステムで使用されるSSDの一部を除き、ホスト（ユーザ）は自身が書き込んだデータがドライブ内のどこに記録されているかを知る方法がなく、逆にドライブはどのデータがホストにとり本当に必要なデータなのかを知る方法がないことに起因します。

　この状況をイメージで示したのが図1です。

![ホストとドライブのそれぞれが知っていることと知らないこと](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/d379ec4b-68f6-e5ae-35b5-578588c7a7d8.png "ホストとドライブのそれぞれが知っていることと知らないこと")
図1：ホストとドライブそれぞれが知っていることと知らないこと

　図1に示した「ホストが知っていること」でかつ「ドライブが知らないこと」である「あるLBAのデータが実は不要なデータである」ということをホストからドライブに通知するのが「Trimコマンド」です。

　この記事ではこの「Trimコマンド」について「どこかで役に立つ情報」をまとめます。

　よろしければ[当社技術コラムのTrimに関する記事](https://www.hagisol.co.jp/techblog/?p=1034)もご覧ください。

# まとめ

* 実は"Trim"と言うコマンドはない
* TrimしてもWrite性能が回復するとは限らない
* Windows (NTFS)はデフォルトでTrimコマンドが発行されるがLinuxは明示的に発行する必要がある

# その1：実は"Trim"というコマンドはない
　"Trim"という単語が「不要なデータが記録されたセクタ(LBA)をドライブに通知する」動作を指すものとして使われ始めた時期は未調査ですが（そのうち調べてみたい）、この記事の執筆時点（2022年10月）では、SATA (ATA Command Set: ACS)、SCSI (SCSI Block Command: SBC)、NVMeで使用されるコマンド群に、"Trim"という「コマンド」は存在しません。

　このため、**「Trimコマンド」という表現は正確ではありません**。

　……とは言え大抵は「Trimコマンド」で通じますので、正確さが必要ない場面であれば「Trimコマンド」で構わない、と私は思います。言葉はコミュニケーション手段ですから、お互いが同じことを想像できればそれで良いのです。

　そもそも、対応するコマンドの名称はACSとNVMeでは同じですがSBCとは異なります。正直わかりにくいです。ですので、**この記事でもあえて「Trimコマンド」という言葉を使います**。

　「それなら正確なコマンド名は何なんだ！」というツッコミが聞こえてきましたので、以下にSATA (ACS)、SCSI / SAS (SBC)、NVMeにおける対応コマンドをご紹介します。

　仕様書や技術文書には「Trimコマンド」の説明が以下に紹介するコマンド名で記載されている可能性がありますのでご留意ください。

## SATAの場合
　SATAで使用されるATA Command Set (ACS)<sup>[1]</sup>では、`TRIM`ビットに`1`を立てた`DATA SET MANAGEMENT`コマンドが対応します（図2）。

![SATA (ACS)のDATA SET MANAGEMENTコマンドの説明](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/9cfb25cc-763d-8b12-ee40-b81f4ab336de.png "SATA (ACS)のDATA SET MANAGEMENTコマンドの説明")
図2：SATA (ACS)のDATA SET MANAGEMENTコマンドの説明

　この`TRIM`ビットが`1`の`DATA SET MANAGEMENT`コマンドでTrimしたいLBA領域のリストをドライブに送ることで、いわゆる「Trim処理」をドライブに要求できます。

　`DATA SET MANAGEMENT`コマンドでは、指定可能な各Trim要求領域の最大サイズが65,535 (=2<sup>16</sup>-1)セクタです。512バイトセクタではおよそ32 MBです。さらに広い領域をTrimする場合は複数領域に分割する必要があります。広大な領域をTrimしたい場合は、各領域最大2<sup>64</sup>-1セクタを指定可能な`DATA SET MANAGEMENT XL`コマンドを使用する方法もあります。

## SCSIやSASの場合
　SCSIやSASで使用されるSCSI Block Command (SBC)<sup>[2]</sup>では`UNMAP`コマンドが対応します（図3）。

![SCSI (SBC)のUNMAPコマンドの説明](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/9ed04e47-9ad6-4a9d-e07a-d5994e73dc10.png "SCSI (SBC)のUNMAPコマンドの説明")
図3：SCSI (SBC)のUNMAPコマンドの説明

　この`UNMAP`コマンドでTrimしたいLBA領域のリストをドライブに送ると、いわゆる「Trim処理」をドライブに要求できます。

## NVMeの場合
　NVMe<sup>[3]</sup>の場合は`AD`ビット（`Deallocate`属性）が`1`の`Dataset Management`コマンドが対応します（図4）。

![NVMeのDataset Managementコマンドにおける属性の内容説明](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/69da5d59-a58f-1a34-b35f-bb72983a47ae.png "NVMeのDataset Managementコマンドにおける属性の内容説明")
図4：NVMeのDataset Managementコマンドにおける属性の内容説明

　この`AD`ビットが`1`の`Dataset Management`コマンドで、TrimしたいLBA領域のリストをドライブに送ると、いわゆる「Trim処理」をドライブに要求できます。

# その2：Trimすれば性能が回復する、とは限らない
　「Trimコマンドを実行したらWrite性能が回復するのか」と問われると、答えは「場合による」となります。具体的には、Trimコマンドの内容と、SSDの内部状態に依存します。

　なぜかというと、Trimコマンド処理の後にGarbage Collection (GC)が実行されるなどしてフリーブロック数が回復するまでWrite性能は回復しないからです。つまり、発行されたTrimコマンドがフリーブロック数回復の効率を上げるものでない限りWrite性能は回復しません。

　この「Trimコマンド実行」→「フリーブロック数回復」→「Write性能回復」という仕組み（関係）を理解することでTrimコマンドをより効果的に活用できます。

　繰り返しになりますが、Trimコマンドを端的に言えば「このLBA領域のデータはもうゴミですよ」とドライブに教えるものです。そして、GCは「ゴミを集めてフリーブロックを作り出す」処理です。つまり「**できるだけ多くの領域をTrimするとフリーブロックが増えやすい**」ことになります。

　「フリーブロックが増えやすい」ということは、「Write性能の回復度合いが大きくなること」および「Write性能回復までにかかる時間が（相対的に）短くなること」に繋がります。Trimコマンド実行前のSSDの内部状態にも依存しますが、できるだけ広い領域をTrimすることがポイントです。

![TrimコマンドとSSD内のNANDフラッシュメモリのブロックの状態イメージ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439683/7c397419-a96e-206c-6b6f-87b73cbc8061.png "TrimコマンドとSSD内のNANDフラッシュメモリのブロックの状態イメージ")
図5：TrimコマンドとSSD内のNANDフラッシュメモリのブロックの状態イメージ

　図5中段のように、小さい領域のみTrimしただけではフリーブロックを作るために行うGCの効率改善幅が小さく、Write性能の回復度合いも回復までにかかる時間の短縮幅も小さいです。

　これに対して、図5下段のように大きい（広い）領域をTrimすれば、GCの効率改善幅が大きくWrite性能の回復度合いと回復までにかかる時間の短縮幅が大きくなる可能性が高くなります。

　図5に示した例は説明用に簡略化した多少極端な例ですし、ホストはどのLBAのデータがどのブロックのどこに記録されているか知る手段を持たないことが多いため図5下段のような結果が必ず生まれるようにTrimコマンドを発行することはとても難しいですが、とにかく広い（大きい）領域をTrimすることで図5下段のような結果を得る可能性を高くできます。

　さらに言うと、GCはホストからのコマンド実行を妨げてかつNANDフラッシュメモリへのデータ書き込みを行うため、必要にならない限りGCを実施しないSSDも存在します。そのようなSSDでは、図5下段のように「明らかにフリーブロックになる」ブロックが発生しない限りTrimコマンドを発行してもWrite性能が回復しない可能性があります。

　GCのアルゴリズムやTrimコマンド処理後の内部処理はメーカーや製品により異なりますのでご注意ください。

# その3：Windowsではファイル削除時に自動的にTrimを発行可能
　Windows (NTFS)であれば、ファイルシステムが「ファイル削除時にそのことを（ドライブに）通知する」という設定が存在し、その有効・無効を`fsutil`というコマンドで確認・設定できます。

　設定内容に関するMicrosoftの説明は以下の通りです。

> Disables (1) or enables (0) delete notifications. Delete notifications (also known as trim or unmap) is a feature that notifies the underlying storage device of clusters that have been freed due to a file delete operation. 
>
> _Microsoftの説明ページ<sup>[4]</sup>より_

　実際にWindows 10 Pro (Version 21H2)上でNTFSボリュームの設定を確認しました。

```
PS C:\> fsutil behavior query disableDeleteNotify
NTFS DisableDeleteNotify = 0  (無効)
ReFS DisableDeleteNotify = 0  (無効)
```

　「ドライブへの通知を無効化する設定」が「無効」ですので、ドライブへの通知は「有効」になります。

# その4：Linuxでは明示的なTrim発行が必要なことも
　Linuxでは、ファイルシステムに対して明示的なTrimコマンド発行要求を必要とする場合があります。この辺りはファイルシステム依存です。

　明示的なTrimコマンド発行に使用するLinuxのコマンドは、`util-linux`パッケージに含まれる`fstrim`です。Web上には`fstrim`のman pageを含め既に多くの記事があり詳しく解説されています<sup>[5][6]</sup>ので、ここでは名称を挙げるだけに留めます。

　実際に、1 TBのNVMe SSD（Linuxのシステムドライブ、ext4）に対して`fstrim`を発行するとこんな感じでした。

```
% sudo fstrim -v /
/: 469.2 GiB (503771938816 バイト) に切り揃えました
```
　別の240 GBのSATA SSD（Linuxのシステムドライブ、ext4）に対して`fstrim`を発行するとこんな感じでした。
```
% sudo fstrim -v /
/: 87.4 GiB (93841174528 bytes) trimmed
```
　「○○バイトTrimした」と解釈できる英文が「○○バイトに切り揃えました」と訳されているのは少し気になります。`df`コマンドで各ドライブの使用サイズを確認すると15 GBと97 GBですし、[Github上のソースコード](https://github.com/util-linux/util-linux/blob/master/sys-utils/fstrim.c)を眺めても「Trimでホストからドライブに通知したサイズ」が表示されているようですが……

# まとめ
　この記事では、ホストからドライブに「あるLBAのデータは不要なデータである」ということを通知する「Trimコマンド」について、いくつかの参考情報を説明しました。

　今回説明したネタのうち「大きなLBA範囲をTrimしないとWrite性能回復効果が低い」というものは、SSDを作る側として、ユーザの皆様に上手く活用していただきたいです。というのも、フリーブロックが多いほうがSSDの内部処理的にも余裕ができ、ホストから見た性能も高くなるからです。

　NANDフラッシュメモリをメディアとするSSDを性能が高い状態で維持して使うには「余裕を持つ（保つ）」ことが重要です。「Trimコマンド」はホスト主導でこの余裕を作りだすことができる手段でありオススメです。

# References
[1] T13, _"Information technology - ATA Command Set - 4 (ACS-4)"_, Working Draft, Revision 14, October, 2016
[2] T10, _"Information technology - SCSI Block Commands - 3 (SBC-3)"_, Working Draft, Revision 21, November, 2009
[3] NVM Express, _"NVM Express(R) NVM Command Set Specification"_, Revision 1.0b, January, 2022
[4] Microsoft、_"[fsutil behavior](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/fsutil-behavior)"_、2022年10月20日閲覧
[5] @kiida、_「[LinuxのSSD設定](https://qiita.com/kiida/items/67bda4881fef5444fbe5)」_、2015年4月12日（2022年10月27日閲覧）
[6] Linux man-page project、_"[fstrim(8)](https://man7.org/linux/man-pages/man8/fstrim.8.html)"_、2022年10月27日閲覧 
 
# ライセンス表記
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="クリエイティブ・コモンズ・ライセンス" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br />この記事は<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">クリエイティブ・コモンズ 表示 - 継承 4.0 国際 ライセンス</a>の下に提供されています。