M5Stack Tab5でSDカード読み取り速度を測定してみた

現在、Tab5-Media-PlayerのST7123対応とRGB888描画とパフォーマンス調整とUIの作り替えなどの作業を行なっています。
現状の実装だとSDカードのReadが間に合わず、それなりに画質を落とさないとフレームドロップが発生してまともに再生できません。
なので、AVIデマクサの実装を改良してある程度ファイルの読み込みを先読みしてバッファリングしておくことで、なんとか読み取り速度を改良できないかなと思ったのですが、そもそも実際にどのくらい読み取り速度が出せるのかわかってなかったのでベンチマークを取ってみました。
ベンチマークコード
ほとんどclaudeに書いてもらいました。シンプルに指定されたファイルをblock size単位で読み取っていって、最後までに読み取るのにかかった時間から速度を算出してログ出力します。
また、PCで実行すると、2回目以降はファイルシステムのキャッシュにヒットしてしまいデバイス自体の速度をうまく測定できないため、PCでの実行のみキャッシュ無効化のコードを入れています。
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
void storage_benchmark(const char *file, int block_size, void (*output)(const char *str, void *user_info), void *user_info) {
int fd = open(file, O_RDONLY);
if (fd < 0) {
output("Failed to open file", user_info);
return;
}
// fcntl(fd, F_NOCACHE, 1); // PCで実行するときのみキャッシュを無効化
// バッファを確保
uint8_t *buffer = (uint8_t *)malloc(block_size);
if (buffer == NULL) {
output("Failed to allocate buffer", user_info);
close(fd);
return;
}
// ベンチマーク開始ログ
char start_msg[256];
snprintf(start_msg, sizeof(start_msg),
"Starting benchmark: file=%s, block_size=%d",
file, block_size);
output(start_msg, user_info);
// 開始時刻を記録
struct timeval start, end;
gettimeofday(&start, NULL);
// ファイル全体を読み取り
size_t total_bytes = 0;
ssize_t bytes_read;
const size_t log_interval = 10 * 1024 * 1024; // 10MB
size_t next_log_threshold = log_interval;
while ((bytes_read = read(fd, buffer, block_size)) > 0) {
total_bytes += bytes_read;
// 10MB読み取るごとにログ出力
if (total_bytes >= next_log_threshold) {
char progress_msg[128];
snprintf(progress_msg, sizeof(progress_msg),
"Progress: %zu MB read",
total_bytes / (1024 * 1024));
output(progress_msg, user_info);
next_log_threshold += log_interval;
}
}
// 終了時刻を記録
gettimeofday(&end, NULL);
// 経過時間を計算(マイクロ秒単位)
long elapsed_usec = (end.tv_sec - start.tv_sec) * 1000000L + (end.tv_usec - start.tv_usec);
double elapsed_sec = elapsed_usec / 1000000.0;
// 読み取り速度を計算(MB/s)
double speed_mbps = (total_bytes / (1024.0 * 1024.0)) / elapsed_sec;
// 結果を文字列として出力
char result[256];
snprintf(result, sizeof(result),
"Read %zu bytes in %.3f sec (%.2f MB/s, block_size=%d)",
total_bytes, elapsed_sec, speed_mbps, block_size);
output(result, user_info);
// クリーンアップ
free(buffer);
close(fd);
}テスト環境

SDカードは、いつどこで買って何に使ってたかよくわからない3つを用意しました。あと、それに加えてRaspberry Pi用にいつも使ってる小型のUSB SSDにも比較対象として参加してもらいます。
これらのストレージを、以下の環境で先ほどの検証用コードを用いて測定します。
- M4 MacBook Air USB2.0接続 + USB2.0 SDカードリーダー
- M5Stack Tab5 USB-Aポート + USB2.0 SDカードリーダー
- M5Stack Tab5 microSDカードスロット
ブロックサイズ(ファイルを何バイトずつ読み出すか)は、512B,1KB,2KB,4KB,8KB,16KB,32KB,64KB で検証。
ファイルは/dev/urandomから50MBのファイルを作って使いました。
テスト結果
| 512B | 1KB | 2KB | 4KB | 8KB | 16KB | 32KB | 64KB | ||
|---|---|---|---|---|---|---|---|---|---|
| M4 MacBook Air | USB SSD | 2.01 MB/s | 3.97 MB/s | 7.62 MB/s | 12.68 MB/s | 15.72 MB/s | 21.82 MB/s | 28.35 MB/s | 33.72 MB/s |
| M4 MacBook Air | TOSHIBA 8G | 0.60 MB/s | 1.53 MB/s | 2.89 MB/s | 5.05 MB/s | 8.00 MB/s | 11.32 MB/s | 14.28 MB/s | 17.87 MB/s |
| M4 MacBook Air | SanDisk 16G | 0.79 MB/s | 1.51 MB/s | 2.85 MB/s | 5.08 MB/s | 8.34 MB/s | 12.17 MB/s | 15.75 MB/s | 20.25 MB/s |
| M4 MacBook Air | Buffalo 32G | 0.87 MB/s | 1.60 MB/s | 2.85 MB/s | 4.93 MB/s | 7.72 MB/s | 11.97 MB/s | 15.19 MB/s | 20.25 MB/s |
| M5StackTab5 USB | USB SSD | 2.18 MB/s | 4.09 MB/s | 7.54 MB/s | 12.63 MB/s | 16.94 MB/s | 23.53 MB/s | ||
| M5StackTab5 USB | TOSHIBA 8G | 0.88 MB/s | 1.67 MB/s | 3.09 MB/s | 5.40 MB/s | 5.40 MB/s | 5.40 MB/s | 5.40 MB/s | 5.39 MB/s |
| M5StackTab5 USB | SanDisk 16G | 0.90 MB/s | 1.62 MB/s | 3.10 MB/s | 5.66 MB/s | 9.66 MB/s | 9.66 MB/s | 9.66 MB/s | 9.64 MB/s |
| M5StackTab5 USB | Buffalo 32G | 0.97 MB/s | 1.76 MB/s | 3.14 MB/s | 5.49 MB/s | 8.80 MB/s | 14.65 MB/s | 14.65 MB/s | 14.63 MB/s |
| M5StackTab5 SD | TOSHIBA 8G | 1.46 MB/s | 1.50 MB/s | 1.52 MB/s | 1.53 MB/s | 1.53 MB/s | 1.53 MB/s | 1.53 MB/s | 1.53 MB/s |
| M5StackTab5 SD | SanDisk 16G | 1.49 MB/s | 1.53 MB/s | 1.56 MB/s | 1.57 MB/s | 1.57 MB/s | 1.57 MB/s | 1.57 MB/s | 1.57 MB/s |
| M5StackTab5 SD | Buffalo 32G | 1.72 MB/s | 1.77 MB/s | 1.80 MB/s | 1.82 MB/s | 1.82 MB/s | 1.83 MB/s | 1.83 MB/s | 1.83 MB/s |
なぜかUSB SSDで32KB Readができなかったのでそこは測定結果がないですが、今回知りたいこととあまり関係ないので深追いはしていません。
こうやって見ると、USB-Aで接続するストレージを選べば10MB/sくらいは期待してもよさそうですね。そうなると、それなりの画質で60fpsいけそうです。
Tab5-Screen-Streamerでは、10MB/s程度で通信が間に合わなくなってくるため、7MB/sを超えたらJPEG圧縮品質を落として、4MB/sを下回ったら圧縮品質を上げるように動的に調整するようにしていて、その感覚でいうとScreen Streamerと同じくらいの画質が期待できます。
あと、データの読み出しはある程度まとめて行なった方がよさそうなのも把握できます。だいたい8KBか16KBあたりがいいですかね。こまめに小さい容量のreadを繰り返すのは非効率なので、ある程度先読みしてバッファリングする必要がありそうです。
一方で、内蔵のmicroSDカードスロットを使う場合は結構厳しいですね。sdkconfigなどは調整してないため、改善できる可能性はありますが、大幅に読み出し速度を上げるのは望み薄です。
ブロックサイズに速度が依存していないのでブロックアクセスじゃないのでしょうか。このあたりはIDFのSDMMC実装を要調査ですね。
その後の話
色々調整したらSDカードの速度を改善することができましたので、以下のページにまとめました

前回、以下の記事でSDカードの読み込み速度を測定したのですが、思ったように速度が出ませんでした。 M5Stack Tab5でSDカード読み取り速度を測定してみた 色々調整することで大幅に速度が向上...




