2009/03/02(月)[SOPC][IP] MMC/SPI FatFs - f_writeベンチマーク
[SOPC][IP] MMC/SPI FatFs - f_writeベンチマーク
[SOPC][IP] MMC/SPI FatFsで紹介しているFatFsについて,コメント欄で問合せいただいたファイル書き込み速度のベンチマークをとってみました.
ベンチマーク概要
FatFsのfopen("wb"相当)で確認する
File systemを使う場合でのベンチマークをとることをテーマとする.*1
脳内シミュレーション(a.k.a.妄想)
FatFs(R0.06)ソースコードより,以下の特徴が推定できる.
- FatFsはマルチセクタライトもサポートしている模様.
- セクタ境界・クラスタ境界でクラスタ調整・更新・buffer吐き出し処理を走らせる模様.
上記を踏まえてベンチマークを取得すべきケースは以下のパターンを考えた.
- クラスタサイズでの一括書き込みが最高スループットを出すだろう
- クラスタをまたぐ,ランダムアクセスが最低速になる.
- バッファサイズ(またはセクタサイズ)をまたぐ場合も同様.
ベンチマーク対象とコード
[NiosII][ACM] 動画再生装置(お試し版)の構成で試しているため,キャッシュの影響が結構効いてくることも考えられるので,データ転送量を2Mbytesとします.
実行時間測定には,パフォーマンスカウンタを用います.カウンタを3つとして合成してあるので,測定対象を以下のように絞ります.(なんとなく時間のかかりそうなところ,短縮できそうなところに目星をつけてみたつもりです)
- 総合時間(規定サイズ・規定回数のブロック転送に要した時間.出力されたファイルの検証は行うべき)
- SPI転送待ち時間
- 書き込みデータのCRC計算
ベンチマーク部分本体
const int trans_size[] = { 512*64, 512*128, 512, 4096, 1024, 64, 256, 768, 1280, 1636, 2048, 0 } ; const int sz_write = 512*2*1024*2 ; ~~~ while (*sz) { f_unlink( fn ) ; // delete the file before test if ((res = f_open (&fp, fn, FA_WRITE|FA_OPEN_ALWAYS|FA_CREATE_ALWAYS)) != FR_OK) { return (res | 0x1000); } // size / loop i = 0 ; PERF_RESET( PERFORMANCE_COUNTER_BASE ); PERF_START_MEASURING( PERFORMANCE_COUNTER_BASE ); PERF_BEGIN( PERFORMANCE_COUNTER_BASE, 1); do { res = f_write(&fp, sdbuf[ i ], *sz, &rsz) ; if (res != FR_OK || rsz == 0) { printf ("Error : Bench-fwrite (%d/%d)\n", res, rsz); break; } i += rsz; } while (i<sz_write) ; PERF_END(PERFORMANCE_COUNTER_BASE, 1); PERF_STOP_MEASURING(PERFORMANCE_COUNTER_BASE) ; printf( "*** fwrite-size = %d ***\n", *sz ); perf_print_formatted_report( (void*)PERFORMANCE_COUNTER_BASE, alt_get_cpu_freq(), 3, "total ", "xmit","CRC" ); WAIT_SEC(5) ; f_close(&fp); sz++ ; }
データ転送部・CRC計算部の処理時間測定位置(mmc.c)
BOOL MMC_xmit_datablock(const BYTE * buff, /* 512 byte data block to be transmitted */ BYTE token /* Data/Stop token */ ) { BYTE resp, wc = 0; #ifdef _CALC_CRC PERF_BEGIN( PERFORMANCE_COUNTER_BASE, 3); WORD crc = CRC16((BYTE *) buff, 512); PERF_END(PERFORMANCE_COUNTER_BASE, 3); #endif if (MMC_wait_ready() != 0xFF) return FALSE; PERF_BEGIN( PERFORMANCE_COUNTER_BASE, 2); MMC_xmit_spi(token); /* Xmit data token */ if (token != 0xFD) { /* Is data token */ do { /* Xmit the 512 byte data block to MMC */ MMC_xmit_spi(*buff++); MMC_xmit_spi(*buff++); } while (--wc); #ifdef _CALC_CRC MMC_xmit_spi(crc >> 8); /* CRC */ MMC_xmit_spi(crc & 0xff); #else @ MMC_xmit_spi(0xFF); /* CRC (Dummy) */ @ MMC_xmit_spi(0xFF); #endif resp = MMC_rcvr_spi(); /* Reveive data response */ if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */ return FALSE; } PERF_END(PERFORMANCE_COUNTER_BASE, 2); return TRUE; }
測定結果
使用用したカードは,Transcend mini SDカード 2GBをSDアダプタに挿したものです.
- セクタあたりのバイト数は,512bytes.
- クラスタあたりのセクタ数は,32です.
- データセクタエリアの理想write回数は,4096回,128クラスタを消費します.
- FATエリアの1セクタあたりのクラスタ数:FAT16ならば1セクタに256個,FAT12なら341個を格納できます.
2MBytesのファイルがクラスタ不連続になっているかどうかの確認をしていません.個人的に使用しているSDカードで,この評価用に使っていないため,テスト用のファイルがクラスタ連続で使用しているかは未確認です.あき暮らす他の探索は先頭からのシーケンシャル探索であり,ファイルのunlink処理では空きクラスタにしているため,パフォーマンスの比較に影響は無いと考えました.
結果のまとめと考察
測定結果と主要項目一覧
転送サイズ | 総時間 | 512byte書込転送要求回数 | 着目点 |
---|---|---|---|
65536 | 4.03239 | +71 | 2クラスタ,マルチセクタCMD |
32768 | 4.92526 | +89 | 1クラスタ,マルチセクタCMD |
4096 | 4.43872 | +513 | 8セクタ連続書込み,1/8クラスタ,マルチセクタCMD |
2048 | 4.43872 | +1025 | 4セクタ連続書込み,マルチセクタCMD |
1636 | 204.466 | +1271 | 3セクタ連続書込み,100バイトコピー,クラスタ境界をまたぐ,マルチセクタ+シングルセクタCMD |
1280 | 135.29 | +1615 | 2セクタ連続書込み,256バイトコピー,マルチセクタ+シングルセクタCMD |
1024 | 7.80936 | +2049 | 1/32クラスタ,マルチセクタCMD |
768 | 199.459 | +1 | 3セクタ連続書込み,クラスタ境界をまたぐ |
512 | 13.9297 | +1 | 1/64クラスタ, 1セクタ,シングルライトコマンド |
256 | 14.0029 | +0 | 1/2セクタ,シングルライトコマンド |
64 | 14.0578 | +6 | 1/8セクタ,シングルライトコマンド |
- セクタ境界をまたがないときは,内部バッファへのコピー処理が走る\→ セクタ数の整数倍ではないモノ全てが対象.\とくに小さいものはコピー処理とループ処理で時間を消費する
- セクタ境界をまたぐと,書き込み処理が走る.\場合によってはリード処理も走る.
- DRAM間のコピー処理は効率も悪く,処理時間が延びる傾向にある
考察
転送呼び出し回数と,処理時間とが比例していないのは,MMC側の書き込みバッファがあって,連続した書き込み要求は待たされるが,完結して呼び出す分にはFLASHへの書き込みと,ソフトの走行がパラで走っている状況である,と推察する.
512の整数倍・約数を除く転送サイズでは,軒並み桁違いの遅さが目立つ.メモリコピー処理に加えて,セクタ・クラスタ境界をまたぐ処理が追加されるためと考えらる.加えて,端数はシングルセクタライトコマンドを用いるため,転送効率が悪化すると見られる.
1024byte時に中途半端な速度になっているのは,SD内のFLASH書込み待ち時間が発生しているためと考えられる.
512以下の約数では,不要なコピー処理が走らないが,シングルライトコマンドによるコマンド・レスポンス処理時間がかかるため,カードのbuffered-writeが機能しないのかもしれない.
実行結果ナマデータ
fwrite-size = 32768
Total Time: 4.92526 seconds (487789773 clock-cycles)
Section | % | Time (sec) | Time (clocks) | Occurrences |
---|---|---|---|---|
total | 100 | 4.92526 | 487789767 | 1 |
xmit | 29.9 | 1.47158 | 145743237 | 4185 |
CRC | 51.5 | 2.53474 | 251036471 | 4185 |
fwrite-size = 65536
Total Time: 4.03239 seconds (399361828 clock-cycles)
Section | % | Time (sec) | Time (clocks) | Occurrences |
---|---|---|---|---|
total | 100 | 4.03239 | 399361822 | 1 |
xmit | 36.3 | 1.46513 | 145104475 | 4167 |
CRC | 62.5 | 2.51866 | 249444181 | 4167 |
fwrite-size = 512
Total Time: 13.9297 seconds (1379575366 clock-cycles)
Section | % | Time (sec) | Time (clocks) | Occurrences |
---|---|---|---|---|
total | 100 | 13.92969 | 1379575360 | 1 |
xmit | 10.5 | 1.45782 | 144379986 | 4097 |
CRC | 19.7 | 2.74122 | 271486615 | 4097 |
fwrite-size = 4096
Total Time: 4.43872 seconds (439603921 clock-cycles)
Section | % | Time (sec) | Time (clocks) | Occurrences |
---|---|---|---|---|
total | 100 | 4.43872 | 439603915 | 1 |
xmit | 33 | 1.46360 | 144953008 | 4609 |
CRC | 64.3 | 2.85452 | 282707713 | 4609 |
fwrite-size = 1024
Total Time: 7.80936 seconds (773427070 clock-cycles)
Section | % | Time (sec) | Time (clocks) | Occurrences |
---|---|---|---|---|
total | 100 | 7.80936 | 773427064 | 1 |
xmit | 18.7 | 1.46100 | 144694759 | 6145 |
CRC | 50.8 | 3.96645 | 392831593 | 6145 |
fwrite-size = 64
Total Time: 14.0578 seconds (1392260079 clock-cycles)
Section | % | Time (sec) | Time (clocks) | Occurrences |
---|---|---|---|---|
total | 100 | 14.05777 | 1392260073 | 1 |
xmit | 10.4 | 1.46502 | 145093274 | 4102 |
CRC | 20.1 | 2.83110 | 280387313 | 4102 |
fwrite-size = 256
Total Time: 14.0029 seconds (1386825298 clock-cycles)
Section | % | Time (sec) | Time (clocks) | Occurrences |
---|---|---|---|---|
total | 100 | 14.00290 | 1386825292 | 1 |
xmit | 10.4 | 1.46295 | 144888693 | 4096 |
CRC | 20 | 2.80153 | 277459466 | 4096 |
fwrite-size = 768
Total Time: 199.459 seconds (19754119034 clock-cycles)
Section | % | Time (sec) | Time (clocks) | Occurrences |
---|---|---|---|---|
total | 100 | 199.45907 | 19754119028 | 1 |
xmit | 0.732 | 1.46015 | 144610629 | 4097 |
CRC | 1.3 | 2.59487 | 256991448 | 4097 |
fwrite-size = 1280
Total Time: 135.29 seconds (13398914257 clock-cycles)
Section | % | Time (sec) | Time (clocks) | Occurrences |
---|---|---|---|---|
total | 100 | 135.29001 | 13398914251 | 1 |
xmit | 1.08 | 1.46152 | 144747051 | 5711 |
CRC | 2.68 | 3.62365 | 358881070 | 5711 |
fwrite-size = 1636
Total Time: 204.466 seconds (20250035225 clock-cycles)
Section | % | Time (sec) | Time (clocks) | Occurrences |
---|---|---|---|---|
total | 100 | 204.46638 | 20250035219 | 1 |
xmit | 0.718 | 1.46731 | 145320005 | 5367 |
CRC | 1.66 | 3.39283 | 336020443 | 5367 |
fwrite-size = 2048
Total Time: 4.88632 seconds (483933442 clock-cycles)
Section | % | Time (sec) | Time (clocks) | Occurrences |
---|---|---|---|---|
total | 100 | 4.88632 | 483933436 | 1 |
xmit | 30 | 1.46384 | 144976116 | 5121 |
CRC | 65.3 | 3.19086 | 316018068 | 5121 |
今後の課題
SD側の応答待ち時間の計測,f_write内の分岐処理回数を付け加えれば,想像の裏づけを取ることもできるだろう.
カードの性能にも左右されるベンチマークであるため,必ずしも上記の結果どおりとはならないでしょう.カード性能を測定するベンチマークハードウェアを作るのも面白いかもしれませんね.File systemを無視して,SDのwrite buffer sizeや応答時間なんかの測定を自動的にやってくれるのがあると,実力チェックに使えて面白そうです.
実使用に耐えるかどうかを判断するためには,file system経由での(sequential|random)(read|write)も必要でしょう.
まぁ,あくまでもMMCのベンチマークということで... :p