RTOS檔案系統對比:LittleFS Vs. SPIFFS
阿新 • • 發佈:2020-03-15
## 概述
在RTOS上免費的檔案系統本身就不多,廣泛使用且掉電安全的就更少了。本文選取當前RTOS上比較受歡迎的兩個檔案系統 SPIFFS 和 LittleFS 做全方位的對比,以便專案上評估在RTOS上使用什麼FS。
對嵌入式裝置來說,掉電時有發生。如果檔案系統無法保證掉電安全,那麼非常有可能在某一次掉電時,裝置就變磚了。
不管是 SPIFFS 還是 LittleFS 的小型檔案系統,都號稱做到掉電安全。而常見的FAT32由於無法做到掉電安全,或者某些特供版要付費使用,更多時候是在需要Windows相容性時才會考慮。
[LittleFS 官網連結](https://github.com/ARMmbed/littlefs)
[SPIFFS 官網連結](https://github.com/pellepl/spiffs)
## 開源協議
不管是 SPIFFS 還是 LittleFS 都開源在 GitHub 中。前者是 MIT開源協議,後者是 BSD開源協議。
在文章[《瞭解常見的開源協議(BSD, GPL, LGPL,MIT)》](https://www.cnblogs.com/sadkilo/p/5962371.html) 上這麼評論 BSD開源協議
BSD程式碼鼓勵程式碼共享,但需要尊重程式碼作者的著作權。BSD由於允許使用者修改和重新發布程式碼,也允許使用或在BSD程式碼上開發商業軟體釋出和銷售,因此是對商業整合很友好的協議。
對MIT開源協議有如下總結:
MIT是和BSD一樣寬範的許可協議,作者只想保留版權,而無任何其他了限制。也就是說,你必須在你的發行版裡包含原許可協議的宣告,無論你是以二進位制釋出的還是以原始碼釋出的。
雖然從使用者的許可權來說,MIT開源協議要比BSD開源協議更少限制,但**對企業商用來說,兩者都可放心使用**。
## 社群維護情況
以GibHub上第一個提交作為專案開始時間,那麼SPIFFS專案作者是[Peter Andersson](https://github.com/pellepl),始於2013年7月4日。而LittleFS的作者是[Christopher Haster](https://github.com/geky),始於2017年2月20日。值得一提的是,LittleFS是ARM工程師折騰出來的檔案系統,最先應該是運用在ARMmbed上的。
從時間上來說,LittleFS專案要晚於SPIFFS專案。我們再看看社群當前維護情況。
SPIFFS專案在2018年沒有任何提交,在2019年只有2個提交。分析提交補丁的內容,我們發現對FS的執行流程有實質修改的最後一個提交是在2017年10月15日。換句話說,SPIFFS專案要不是已經足夠穩定到沒有任何bug,要不漸漸被遺棄。
相比與SPIFFS專案的落日餘暉,LittleFS更像冉冉升起的太陽。從2017年到文字撰稿時的2020年3月初,社群一直非常活躍,以2019年為例,共計合併了124個提交,釋放了10個版本。目前最新的版本是2.1.4,而據我與作者的溝通,其正在為2.2版本做Bug修復。
到目前為止,在GitHub的統計上,SPIFFS專案共計934個星,而LittleFS專案達到1.7K個星。
因此,SPIFFS在社群上已經不怎麼維護,而LittleFS依然活躍。持續迭代的軟體會更強大和更穩定。
## 靜態系統資源
對比靜態系統資源,我們主要比較編譯後的bin檔案的text/data/bss段的大小。
text段:存放程式碼執行語句
data段:存放已初始化的全域性變數和區域性靜態變數
bss段:未初始化的全域性變數和區域性靜態變數
這3個段的資料都是在編譯時就已經確定下來的。如果某一個軟體程式碼量非常龐大,其對應的text段也會龐大,也就意味著在執行時,需要用更多的記憶體存放程式碼語句。
我設計了下面的Shell命令統計靜態資訊:
```Bash
find -name "*.o" -exec size {} \; | awk '
BEGIN{
datasum = 0;
textsum = 0;
bsssum = 0;
};
/data/{
getline;
textsum += $1;
datasum += $2;
bsssum += $3;
};
END{
printf "text %d\ndata %d\nbss %d\n", textsum, datasum, bsssum
}
'
```
統計結果如下:
| FS | text | data | bss |
| :---: | :---: | :---: | :---: |
| littlefs | 24000 | 0 | 0 |
| spiffs | 36940 | 0 | 0 |
可以發現,SPIFFS的程式碼量比LittleFS多53%,也就意味著SPIFFS需要更多的記憶體存放程式碼。
## 實測-環境
並不是所有的對比都可以直接從程式碼上看出來,我們需要上機實測。實測是為了獲取最真實的對比資料。
不講環境和配置,直接對比SPIFFS和LittleFS,簡直是在耍流氓。因此,我們先看看實測的環境。
測試時使用 *0.3.7* 版本的SPIFFS,其配置如下:
```
phys_size = 5013504B
phys_addr = 0
phys_erase_block = 32K
log_block_szie = 64K
log_page_size = 256B
```
測試時使用 *2.1.3* 版本的LittleFS,其配置如下:
```
read_size = 256B
prog_size = 256B
block_szie = 32K or 4K
cache_size = 256B
lookahead_size = 16
```
在旺巨集16M的SPI Nor上測試,SPI Nor執行在4線讀寫命令和100MHz的SPI時鐘頻率上。用於做測試的分割槽有4896KB。
確保RTOS上並無任何無關程序在搶CPU、IO資源。
換句話說,測試在使用相同的硬體環境,無其他程序干擾的情況下進行。
## 空間利用率
檔案系統需要額外空間存放一些元資料,因此使用者可用的空間實際大小並不直接等於分割槽大小。在 4896KB 的分割槽上分別掛載SPIFFS和Littlefs兩個檔案系統,他們的可用空間是多少呢?
空的檔案系統體現不出來,我們試著往不同檔案系統中存放一些資原始檔,再觀察使用情況。
這些資原始檔在ubuntu的ext4 (塊大小為4K)中統計有2794KB的大小。以此為標準,我們看看SPIFFS和LittleFS的空間使用情況
| FS | used(KB) | total(KB) | note |
| :---: | :---: | :---: | :--- |
| SPIFFS | 2722 | 4607 | |
| LittleFS | 3680 | 4896 | block size = 32K |
| LittleFS | 2800 | 4896 | block size = 4K |
由於LittleFS的塊大小決定了檔案儲存的最小單位,因此分別統計塊大小為4K和32K的空間使用情況。當塊越大,則越有可能會出現空間浪費的情況。例如32K的塊大小,即使檔案內容只有1KB,LittleFS也會為其分配32K的空間,造成了31K的空間浪費。
從空間利用率來看,SPIFFS略優於LittleFS。
## 掉電安全和修復
檔案系統的掉電安全指在任意一時刻掉電,檔案系統依然能保證其一致性,檔案系統允許丟失掉電時沒寫完整的資料,但不能奔潰。
我們通過讀寫掉電的方式驗證掉電安全,即在讀寫壓測時隨機時間掉電,再次上電後需要保證檔案系統正常執行且已寫入的檔案資料不丟失。
SPIFFS掉電後需要呼叫```SPIFFS_check()```進行修復,否則無法保證檔案系統一致性。這就類似於ext4與e2fsck的關係。
在實測中,4896KB的空間,SPIFFS的修復竟然要5~10s,相對於一次RTOS啟動總耗時2~3s而言,簡直無法忍受。在專案中已經放棄對其的掉電壓測。
與SPIFFS相反,LittleFS在設計時就保證了掉電安全的問題,因此不需要每次掉電後執行修復工作。
而2.1.3版本的LittleFS在10W次的掉電測試中,在數萬次掉電後小概率出現檔案系統奔潰導致不能正確掛載的情況。分析良久,確認是LittleFS本身邏輯的問題。已反饋社群,預計在2.2版本解決。
總的來說,SPIFFS的掉電安全修復耗時不符合專案需求,而LittleFS目前還做不到絕對的掉電安全。比較幸運的是,LittleFS的掉電安全問題復現概率比較低,且LittleFS社群比較活躍,在發現問題後能及時提出解決方案。
## 讀寫效能
當空間使用率不同,測試的效能有可能不一樣,在SPIFFS中尤其明顯。
| IO操作 | 空閒空間 | SPIFFS | LittleFS(32K Block) | LittleFS(4K Block) |
| :---: | :---: | :---: | :---: | :---: |
| 讀 | 20% | 6095.24 KB/s | 8629.21 KB/s | 7529.41 KB/s |
| 讀 | 100% | 6564.10 KB/s | 8727.27 KB/s | 7314.29 KB/s |
| 寫 | 20% | 21.64 KB/s | 142.54 KB/s | 121.92 KB/s |
| 寫 | 100% | 128.49 KB/s | 155.37 KB/s | 127.87 KB/s |
在讀寫效能表現上,SPIFFS最差,且剩餘空間越少,SPIFFS寫效能越差。LittleFS的效能相對比較高和穩定,塊大小會直接影響到寫效能。
## 動態記憶體
動態記憶體指通過```malloc```申請分配的堆記憶體大小。不管是SPIFFS還是LittleFS都是為小系統設計的,其記憶體使用情況都經過精心設計,記憶體佔用非常小。
LittleFS會為每個開啟的檔案單獨申請一個```cache_size```的記憶體,在測試時,cache_size 為256B。為了對比的公平性,我們假設SPIFFS和LittleFS開啟相同數量的檔案情況下統計記憶體。
| LittleFS | SPIFFS |
| :---: | :---: |
| 3856 B | 3790 B |
兩者使用動態記憶體的情況相近,在最大開啟數量的情況下,SPIFFS使用動態記憶體略少。
由於SPIFFS的記憶體使用並不會隨著開啟檔案增加而增加,也就意味著,在開啟少量檔案的情況下,LittleFS會比SPIFFS更少的動態記憶體使用量。
## CPU佔用
在讀寫壓測時,統計程序使用的CPU資源百分比
| LittleFS (32K) | LittleFS (4K) | SPIFFS |
| :---: | :---: | :---: |
| 22~27 | 27~50 | 44~80 |
可以發現,在相同情況下,LittleFS的CPU佔用率會比SPIFFS少。
## 總結
本文從多個方面對比評估 LittleFS 和 SPIFFS,發現資源、效能、掉電安全和社群支援情況來說,後來者 LittleFS 已經青出