LeavaTailの日記

LeavaTailの日記

Linuxエンジニアを目指した技術者の備忘録

Raspberry Pi 4 で microSD の読み込み/書き込み性能を比較する

概要

Raspberry Pi 4 上で 6種のメーカー (Kingston, Transcend, SUNEAST, Gigastone, KIOXIA, San Disk) のSDメモリカードの読み込み/書き込み性能を比較した。 その結果、下記のような傾向を確認することができた。

  • Raspberry Pi 4 (Raspberry Pi OS) では、カタログの最大書き込み・読み込み性能に達することは難しい。
  • Raspberry Pi 4 (Raspberry Pi OS) では、ファイルシステムを介することによる書き込み性能が大きく低下するが、読み込み性能はそこまでの低下は見られなかった
  • SDメモリカードによって特性が異なり、ランダムな書き込みによって性能が大きく低下するものとそうではないものがあった

背景

SDメモリカードは、家庭用ゲーム機やデジタルカメラなど外部ストレージとして広く使われている。 SDメモリカードは、SD Associationによって定めたSD標準規格を基に様々なメーカーから販売されている。 各メーカーは、大容量化・高耐久性・省コスト化など様々な工夫によって他のメーカーとの差別化を目指している。 そのため、同じ要領のSDメモリカードでも異なる特性を持つことがある。 そこで複数のmicroSDカードの読み込み・書き込み性能を測定することで、それらの傾向を確認する。

目的

  1. カタログの最大書き込み・読み込み性能値と実測値の差を確認する
  2. ファイルシステムを介することによるオーバーヘッドを計測する
  3. microSDカードの違いによってパフォーマンスが異なることを確認する

実行環境

Raspberry Pi 4 Model B (Raspberry Pi 4) は USBフラッシュドライブ経由でRaspberry Pi OSを起動させる。 測定用のSDカードは Raspberry Pi 4の microSD card slot に挿入する。

計測環境の概要

ここで使用するRaspberry Pi 4のスペックについて、必要な情報だけ抜粋したものを下記に示す。

項目 Raspberry Pi 4
CPU Cortex-A72 (ARM v8) 1.5GHz
メモリ 4GB LPDDR4-3200
OS Raspberry Pi OS (Dec 5th 2023)
ケース 陽極酸化アルミニウム製ヒートシンクケース

今回の調査には、下記6種類の未使用のmicroSDカードを6種類を使用し、Raspberriy Pi 4上で計測する。 (カタログに記載されていないものは、空欄としている)

Canvas Select Plus microSD Transcend USD300S SUNEAST ULTIMATE PRO GIGASTONE Prime 600X EXCERIA HIGH ENDURANCE SanDisk MAX ENDURANCE
型番号 KF-C4032-7I TS32GUSD300S-A SE-MSDU1032C180 GJMX-32GU190R KEMU-A032G SDSQQVR-032G-JN3ID
スピードクラス C10 C10 C10 C10 C10 C10
UHSスピードクラス U1 U1 U1 U1 U1 U3
ビデオスピードクラス V10 V10 V10 V30
アプリケーションパフォーマンスクラス A1 A1 A1 A1
インタフェース UHS-I UHS-I UHS-I UHS-I UHS-1 UHS-1
容量 32GB 32GB 32GB 32GB 32GB 32GB
最大読み出し速度 100 MB/s 100 MB/s 98 MB/s 90 MB/s 100 MB/s 100 MB/s
最大書き込み速度 85 MB/s 90 MB/s 30MB/s 40 MB/s

RAWデバイスのパフォーマンスをベンチマークする

まずは、簡単な性能測定として、ファイルシステムと Page Cache を介さないような測定パターン "RAWデバイスに対してダイレクト I/O" でベンチマークする。ここで計測するパターンは下記の4種類とする。

  1. I/O サイズを 1 MB でシーケンシャルな書き込み
  2. I/O サイズを 1 MB でシーケンシャルな読み込み
  3. I/O サイズを 4 KB でランダムな書き込み
  4. I/O サイズを 4 KB でランダムな読み込み

これらがどのようなI/Oフローでデータアクセスするかを考える。

RAWデバイスへのアクセスによるI/Oフローの概略図

fio から I/Oサイズごとにread/writeが発行されると、VFS からブロックレイヤにリクエストを要求する。ブロックレイヤに渡された bio は ioスケジューラなどによってマージやスプリットされる。ioスケジューラからディスパッチされた ioリクエストはブロック単位に書き込み・読み込みをする。また、連続するブロックに対するアクセスはマルチブロック読み込み・書き込みコマンドとして発行することもできる。

I/O サイズを 1 MB でシーケンシャルな書き込み

sudo fio --name=write_bandwidth_test \
  --filename=/dev/mmcblk0 --filesize=16G \
  --time_based --ramp_time=2s --runtime=60 \
  --ioengine=sync --direct=1 --bs=1M --iodepth=1 numjobs=1 \
  --rw=write --fsync_on_close=1 --invalidate=1

このコマンドを10回 実行させた結果と標準偏差は次の通りとなった。

SDメモリカード 平均スループット(MB/s) スループット標準偏差 平均IOPS IOPS標準偏差
kingston 22.2 0.1 22 0
gigastone 18.6 0.6 18 0
trancend 18.1 0.1 17 0
suneast 26.3 3.2 25 3
kioxia 25.6 0.3 25 0
sandisk 33.6 0.2 33 0

これらのスループットをグラフに描画してみると、次の通りとなった。

RAWデバイスにおけるシーケンシャルな書き込み性能

一つ目に、SDメモリカードによって性能差が出ていることに注目する。 測定結果の最低値と最大値を比較すると 2倍近くの差が出ていることがわかる。 これは、SDメモリカード内の構成やファームウェアの違いによるものと考えられる。

二つ目に、書き込み性能がカタログの最大性能に届かないことにも注目する。 SDメモリカードによっては、最大書き込み速度の半分以下の測定結果となっている。 これは、一般的なPCと比べると非力な Raspberry Pi 4 の Linux OS 上で計測しているため、SDメモリカードが処理しきれるだけのデータを転送できていない可能性がありそうである。

三つ目に、subeastを除き、標準偏差が小さいことにも注目する。 SUNEAST ULTIMATE PRO の結果を除き、標準偏差は 1%程度 に収まっている。 これは、購入直後に測定しているため、SDメモリカードの状態が安定していることを示しているだろう。

I/O サイズを 1 MB でシーケンシャルな読み込み

sudo fio --name=write_bandwidth_test \
  --filename=/dev/mmcblk0 --filesize=16G \
  --time_based --ramp_time=2s --runtime=60 \
  --ioengine=sync --direct=1 --bs=1M --iodepth=1 numjobs=1 \
  --rw=read --fsync_on_close=1 --invalidate=1

このコマンドを10回 実行させた結果と標準偏差は次の通りとなった。

SDメモリカード 平均スループット(MB/s) スループット標準偏差 平均IOPS IOPS標準偏差
kingston 40.1 0.3 39 0
gigastone 39.9 0.2 39 0
trancend 41.3 0.2 41 0
suneast 41.2 0.3 40 0
kioxia 40.9 0.3 40 0
sandisk 40.5 0.3 40 0

これらのスループットをグラフに描画してみると、次の通りとなった。

RAWデバイスにおけるシーケンシャルな読み込み性能

ここでは、SDメモリカードによって性能差が出ていないことに注目する。 シーケンシャルな書き込みとは異なり、異なるSDメモリカード間の読み込み速度に大きな差が見られなかった。 これは、一般的なPCと比べると非力な Raspberry Pi 4 の Linux OS 上で計測しているため、読み込み性能が何かしらに律速している可能性がある。

I/O サイズを 4 KB でランダムな書き込み

sudo fio --name=write_bandwidth_test \
  --filename=/dev/mmcblk0 --filesize=16G \
  --time_based --ramp_time=2s --runtime=60 \
  --ioengine=sync --direct=1 --bs=4K --iodepth=1 numjobs=1 \
  --rw=randwrite --fsync_on_close=1 --invalidate=1

このコマンドを10回 実行させた結果と標準偏差は次の通りとなった。

SDメモリカード 平均スループット(MB/s) スループット標準偏差 平均IOPS IOPS標準偏差
kingston 3.7 0.0 947 3
gigastone 1.0 0.0 254 4
trancend 2.3 0.0 589 2
suneast 5.8 0.3 1489 65
kioxia 2.2 0.0 571 12
sandisk 2.5 0.0 631 2

これらのスループットをグラフに描画してみると、次の通りとなった。

RAWデバイスにおけるランダムな書き込み性能

ここでは、シーケンシャルな書き込みと傾向が異なることに注目する。 シーケンシャルな書き込みの場合、EXCERIA HIGH ENDURANCE や SanDisk MAX ENDURANCE は高めの傾向が出ていたが、ランダムな書き込みではこれらの性能地が低めの傾向となった。 これらSDメモリカードが "高耐久" を特徴としていることから、SDメモリカード側のファームウェアが小さいブロックで疎らな要求をメモリセルの高耐久性に向けて制御しているのではないかと考えられる。

I/O サイズを 4 KB でランダムな読み込み

sudo fio --name=write_bandwidth_test \
  --filename=/dev/mmcblk0 --filesize=16G \
  --time_based --ramp_time=2s --runtime=60 \
  --ioengine=sync --direct=1 --bs=4K --iodepth=1 numjobs=1 \
  --rw=randread --fsync_on_close=1 --invalidate=1

このコマンドを10回 実行させた結果と標準偏差は次の通りとなった。

SDメモリカード 平均スループット(MB/s) スループット標準偏差 平均IOPS IOPS標準偏差
Canvas Select Plus microSD 8.6 0.0 2212 3
GIGASTONE Prime 600X 7.0 0.0 1788 2
Transcend USD300S 12.0 0.0 3072 6
SUNEAST ULTIMATE PRO 9.7 0.0 2475 4
EXCERIA HIGH ENDURANCE 12.7 0.0 3240 5
SanDisk MAX ENDURANCE 6.3 0.0 1601 2

これらのスループットをグラフに描画してみると、次の通りとなった。

RAWデバイスにおけるランダムな読み込み性能

ここでも、シーケンシャルな読み込みと傾向が異なることに注目する。 シーケンシャルな読み込みの場合、全体的に性能差はほとんどなく 40MB/s まで達していたが、ランダムな読み込みの場合、SDメモリカードによって性能差が出ており、10 MB/s あたりまで性能が低下している。 SDメモリカードで使用される NAND型フラッシュメモリでは、HDDと比較してシークタイムのロスタイムは小さいため、シークによるものとは考えにくい。 細かいI/Oを大量に発行したことで Raspberry Pi 側 に負荷がかかったことにより、SDメモリカード側のコントローラの違いが顕著に表れたとも考えられる。

vfatファイルシステムのパフォーマンスをベンチマークする

次に、 Page Cache を介さないような測定パターン "vfatファイルシステムに対してダイレクト I/O" でベンチマークする。ここで計測するパターンは下記の4種類とする。

  1. I/O サイズを 1 MB でシーケンシャルな書き込み
  2. I/O サイズを 1 MB でシーケンシャルな読み込み
  3. I/O サイズを 4 KB でランダムな書き込み
  4. I/O サイズを 4 KB でランダムな読み込み

これらがどのようなI/Oフローでデータアクセスするかを考える。

vfatファイルシステムへのアクセスによるI/Oフローの概略図

fio から I/Oサイズごとにread/writeが発行されると、VFS は vfatファイルシステムにwritepages(実データ)とwrite_inode(メタデータ)を呼び出す。 vfatファイルシステムはブロックレイヤにリクエストを要求する。 ブロックレイヤに渡された bio は ioスケジューラなどによってマージやスプリットされる。 ioスケジューラからディスパッチされた ioリクエストはブロック単位に書き込み・読み込みをする。 連続するブロックに対するアクセスはマルチブロック読み込み・書き込みコマンドとして発行することもできる。

その後、一定期間経過後にメタデータの書き込みを開始する。 今回の環境ではFAT32 (クラスタサイズは16 KB) であり、想定される書き込み対象は次の通りである。

  • FAT (1つのクラスタに対して、エントリのサイズは4 B) × 2
  • ディレクトリエントリ (1つのファイルに対して、最低でも32 B)
  • FSINFO (512 B)

この計測では、ダイレクト I/O かつ メモリにも十分な空きがあるはずなので、inode の expireされるまで遅延されるだろう。 デフォルトの値が 30s であるので 一回の計測で 2回程度の書き込みとなる。

I/O サイズを 1 MB でシーケンシャルな書き込み

sudo fio --name=write_bandwidth_test \
  --directory=/$TEST_DIR --filesize=4095M \
  --time_based --ramp_time=2s --runtime=60 \
  --ioengine=sync --direct=1 --bs=1M --iodepth=1 numjobs=1 \
  --rw=write --fsync_on_close=1 --invalidate=1 

このコマンドを10回 実行させた結果と標準偏差は次の通りとなった。

SDメモリカード 平均スループット(MB/s) スループット標準偏差 平均IOPS IOPS標準偏差
kingston 18.0 0.3 17 0
gigastone 15.6 1.4 15 1
trancend 15.5 0.8 15 0
suneast 18.4 1.8 17 1
kioxia 19.9 0.1 19 0
sandisk 25.3 0.1 25 0

これらのスループットをRAWデバイスの結果と共にグラフに描画してみると、次の通りとなった。

vfatファイルシステムにおけるシーケンシャルな書き込み性能

ここでは、RAWデバイスから性能が低下していることに注目する。 RAWデバイスへの書き込みとは異なり、ファイルへの書き込みしているため実際のデータに加えて、メタデータの書き込みも発生している。 今回の環境では、1 GB のファイルは 65,536個のクラスタから構成される。 そのため、1 GB のファイルを書き込みする場合には、 256 KB + α の追加データを書き込みすることになる。 それに加えて、追加の計算量が発生することを加味すれば、これらオーバーヘッドが原因と考えることができるだろう。

I/O サイズを 1 MB でシーケンシャルな読み込み

sudo fio --name=write_bandwidth_test \
  --directory=/$TEST_DIR --filesize=4095M \
  --time_based --ramp_time=2s --runtime=60 \
  --ioengine=sync --direct=1 --bs=1M --iodepth=1 numjobs=1 \
  --rw=read --fsync_on_close=1 --invalidate=1

このコマンドを10回 実行させた結果と標準偏差は次の通りとなった。

SDメモリカード 平均スループット(MB/s) スループット標準偏差 平均IOPS IOPS標準偏差
kingston 40.3 0.5 39 0
gigastone 39.9 0.4 39 0
trancend 41.4 0.3 41 0
suneast 41.6 0.3 41 0
kioxia 40.5 0.1 40 0
sandisk 40.6 0.3 40 0

これらのスループットをRAWデバイスの結果と共にグラフに描画してみると、次の通りとなった。

vfatファイルシステムにおけるシーケンシャルな読み込み性能

ここでは、RAWデバイスの場合と同様の性能であることに注目する。 vfatファイルシステムのファイルを読み込む場合には、クラスタチェインを辿る必要がある。 しかし、この計測ではそういったオーバーヘッドは小さく、RAWデバイスの時と同様に何かしらで律速しているように見える。

I/O サイズを 4 KB でランダムな書き込み

sudo fio --name=write_bandwidth_test \
  --directory=/$TEST_DIR --filesize=4095M \
  --time_based --ramp_time=2s --runtime=60 \
  --ioengine=sync --direct=1 --bs=4K --iodepth=1 numjobs=1 \
  --rw=randwrite --fsync_on_close=1 --invalidate=1

このコマンドを10回 実行させた結果と標準偏差は次の通りとなった。

SDメモリカード 平均スループット(KB/s) スループット標準偏差 平均IOPS IOPS標準偏差
kingston 540.3 253.9 134 63
gigastone 43.0 18.5 10 4
trancend 1.3 0.0 0 0
suneast 772.9 338.7 192 84
kioxia 487.5 149.8 121 37
sandisk 717.5 113.5 179 28

これらのスループットをRAWデバイスの結果と共にグラフに描画してみると、次の通りとなった。

vfatファイルシステムにおけるランダムな書き込み性能

一つ目に、RAWデバイスから性能が大きく低下していることに注目する。 vfatファイルシステムではスパースファイルが未対応であるため、ランダムシークによって書き込まれていない領域 (ホール) に対して 0 を書き込む作業が発生する。 RAWデバイスに対する書き込みと比較して、書き込み総量が大きくなったことで、性能が低下しているのではないかと考えられる。

二つ目に、全体的に標準偏差が大きいことにも注目する。 上記の仮説と同様に、スパースファイルが未対応であるため、ランダムシークの傾向によっては ファイルサイズの2倍の書き込みが発生することもある。 そのため、ランダムシード (書き込みパターン) によって書き込み総量が変化することが原因ではないかと考えられる。

I/O サイズを 4 KB でランダムな読み込み

sudo fio --name=write_bandwidth_test \
  --directory=/$TEST_DIR --filesize=4095M \
  --time_based --ramp_time=2s --runtime=60 \
  --ioengine=sync --direct=1 --bs=4K --iodepth=1 numjobs=1 \
  --rw=randread --fsync_on_close=1 --invalidate=1

このコマンドを10回 実行させた結果と標準偏差は次の通りとなった。

SDメモリカード 平均スループット(KB/s) スループット
標準偏差
平均IOPS IOPS
標準偏差
kingston 7.7 0.0 1973 7
gigastone 5.4 0.0 1375 1
trancend 10.5 0.0 2702 5
suneast 10.4 0.1 2673 23
kioxia 10.4 0.1 2674 11
sandisk 8.6 0.0 2198 7

これらのスループットをRAWデバイスの結果と共にグラフに描画してみると、次の通りとなった。

vfatファイルシステムにおけるランダムな読み込み性能

ここでは、RAWデバイスの場合より性能が高くなるケースについて注目する。 通常であれば、RAWデバイスの計測した環境から vfatファイルシステムのレイヤーが追加されるため、オーバーヘッドの追加が想定される。 vfatファイルシステムの場合だと、ファイルの中身を読み込むためにはクラスタチェインを辿る必要がある。 しかし、SUNEAST ULTIMATE PRO と SanDisk MAX ENDURANCE については、その仮説通りとはいかなかった。 これは、ランダム読み込みで何かしらの情報をキャッシュすることで性能が向上したのではないかと考えられる。 しかし、vfatファイルシステムが持つキャッシュはクラスタチェインの連続性のみであり、read-ahead などの仕組みはダイレクトI/Oによってバイパスされているため、これらは無関係であると思われる。

変更履歴

  • 2024/02/03: 記事公開
  • 2024/03/01: 誤字修正

参考文献