與 ext2 相比,Ext4 表現出意外的寫入延遲差異
我有一個在嵌入式系統上執行的對延遲敏感的應用程序,我發現在同一物理設備上寫入 ext4 分區和 ext2 分區之間存在一些差異。具體來說,我看到在記憶體映射上執行許多小更新時會出現間歇性延遲,但僅限於 ext4。我已經嘗試了一些通過使用不同選項安裝 ext4 來提高性能(尤其是延遲變化)的常用技巧,並確定了這些安裝選項:
mount -t ext4 -o remount,rw,noatime,nodiratime,user_xattr,barrier=1,data=ordered,nodelalloc /dev/mmcblk0p6 /media/mmc/data
barrier=0
似乎沒有提供任何改進。對於 ext2 分區,使用以下標誌:
/dev/mmcblk0p3 on /media/mmc/data2 type ext2 (rw,relatime,errors=continue)
這是我正在使用的測試程序:
#include <stdio.h> #include <cstring> #include <cstdio> #include <string.h> #include <stdint.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <stdint.h> #include <cstdlib> #include <time.h> #include <stdio.h> #include <signal.h> #include <pthread.h> #include <unistd.h> #include <errno.h> #include <stdlib.h> uint32_t getMonotonicMillis() { struct timespec time; clock_gettime(CLOCK_MONOTONIC, &time); uint32_t millis = (time.tv_nsec/1000000)+(time.tv_sec*1000); return millis; } void tune(const char* name, const char* value) { FILE* tuneFd = fopen(name, "wb+"); fwrite(value, strlen(value), 1, tuneFd); fclose(tuneFd); } void tuneForFasterWriteback() { tune("/proc/sys/vm/dirty_writeback_centisecs", "25"); tune("/proc/sys/vm/dirty_expire_centisecs", "200"); tune("/proc/sys/vm/dirty_background_ratio", "5"); tune("/proc/sys/vm/dirty_ratio", "40"); tune("/proc/sys/vm/swappiness", "0"); } class MMapper { public: const char* _backingPath; int _blockSize; int _blockCount; bool _isSparse; int _size; uint8_t *_data; int _backingFile; uint8_t *_buffer; MMapper(const char *backingPath, int blockSize, int blockCount, bool isSparse) : _backingPath(backingPath), _blockSize(blockSize), _blockCount(blockCount), _isSparse(isSparse), _size(blockSize*blockCount) { printf("Creating MMapper for %s with block size %i, block count %i and it is%s sparse\n", _backingPath, _blockSize, _blockCount, _isSparse ? "" : " not"); _backingFile = open(_backingPath, O_CREAT | O_RDWR | O_TRUNC, 0600); if(_isSparse) { ftruncate(_backingFile, _size); } else { posix_fallocate(_backingFile, 0, _size); fsync(_backingFile); } _data = (uint8_t*)mmap(NULL, _size, PROT_READ | PROT_WRITE, MAP_SHARED, _backingFile, 0); _buffer = new uint8_t[blockSize]; printf("MMapper %s created!\n", _backingPath); } ~MMapper() { printf("Destroying MMapper %s\n", _backingPath); if(_data) { msync(_data, _size, MS_SYNC); munmap(_data, _size); close(_backingFile); _data = NULL; delete [] _buffer; _buffer = NULL; } printf("Destroyed!\n"); } void writeBlock(int whichBlock) { memcpy(&_data[whichBlock*_blockSize], _buffer, _blockSize); } }; int main(int argc, char** argv) { tuneForFasterWriteback(); int timeBetweenBlocks = 40*1000; //2^12 x 2^16 = 2^28 = 2^10*2^10*2^8 = 256MB int blockSize = 4*1024; int blockCount = 64*1024; int bigBlockCount = 2*64*1024; int iterations = 25*40*60; //25 counts simulates 1 layer for one second, 5 minutes here uint32_t startMillis = getMonotonicMillis(); int measureIterationCount = 50; MMapper mapper("sparse", blockSize, bigBlockCount, true); for(int i=0; i<iterations; i++) { int block = rand()%blockCount; mapper.writeBlock(block); usleep(timeBetweenBlocks); if(i%measureIterationCount==measureIterationCount-1) { uint32_t elapsedTime = getMonotonicMillis()-startMillis; printf("%i took %u\n", i, elapsedTime); startMillis = getMonotonicMillis(); } } return 0; }
相當簡單的測試案例。我不指望非常準確的時機,我對總體趨勢更感興趣。在執行測試之前,我通過執行以下操作確保系統處於相當穩定的狀態,幾乎沒有發生磁碟寫入活動:
watch grep -e Writeback: -e Dirty: /proc/meminfo
幾乎沒有磁碟活動。這也可以通過在 的輸出中看到等待列中的 0 或 1 來驗證
vmstat 1
。我還在執行測試之前立即執行同步。請注意也提供給 vm 子系統的積極回寫參數。當我在 ext2 分區上執行測試時,前 100 批 50 次寫入產生了一個不錯的 2012 毫秒,標準偏差為 8 毫秒。當我在 ext4 分區上執行相同的測試時,我看到平均為 2151 毫秒,但標準偏差為 409 毫秒。我主要關心的是延遲的變化,所以這很令人沮喪。ext4 分區測試的實際時間如下所示:
{2372, 3291, 2025, 2020, 2019, 2019, 2019, 2019, 2019, 2020, 2019, 2019, 2019, 2019, 2020, 2021, 2037, 2019, 2021, 2021, 2020, 2152, 2020, 2021, 2019, 2019, 2020, 2153, 2020, 2020, 2021, 2020, 2020, 2020, 2043, 2021, 2019, 2019, 2019, 2053, 2019, 2020, 2023, 2020, 2020, 2021, 2019, 2022, 2019, 2020, 2020, 2020, 2019, 2020, 2019, 2019, 2021, 2023, 2019, 2023, 2025, 3574, 2019, 3013, 2019, 2021, 2019, 3755, 2021, 2020, 2020, 2019, 2020, 2020, 2019, 2799, 2020, 2019, 2019, 2020, 2020, 2143, 2088, 2026, 2017, 2310, 2020, 2485, 4214, 2023, 2020, 2023, 3405, 2020, 2019, 2020, 2020, 2019, 2020, 3591}
不幸的是,我不知道 ext2 是否是最終解決方案的一個選項,所以我試圖了解文件系統之間的行為差異。我很可能至少可以控制用於掛載 ext4 系統並對其進行調整的標誌。
- noatime/nodiratime 似乎沒有太大影響
- barrier=0/1 似乎無關緊要
- nodelalloc 有點幫助,但在消除延遲變化方面做得還不夠。
- ext4 分區只有大約 10% 已滿。
感謝您對這個問題的任何想法!
一個詞:日記。
http://www.thegeekstuff.com/2011/05/ext2-ext3-ext4/
當您談論嵌入式即時通訊時,假設您有某種形式的快閃記憶體?快閃記憶體上的日誌記錄 ext4 的性能非常高。推薦使用 Ext2。
如果您必須使用 ext4,這裡有一篇關於禁用日誌和調整 fs 以實現無日誌的好文章:http: //fenidik.blogspot.com/2010/03/ext4-disable-journal.html