This example provides comparison between different types of storage in terms of speed under various configurable (from menuconfig) conditions
Currently these mediums and file-systems are supported:
- SPI Flash
- Raw access
- FATFS
- SPIFFS
- LittleFS
- SDMMC/SDSPI card
- Raw access
- FATFS
- LittleFS
### Comparison scheme
For each filesystem, four sets of benchmarks are run:
- Target size R/W
- More than target size R/W (about target_size x 1.2)
- Less than target size R/W (about target_size / 1.2)
- Tiny size (255 bytes)
Some filesystems are also tested in two modes:
- New file - new file gets created every time
- Normal - the old file gets overwritten each time (`O_TRUNC`)
Every benchmark (except SPIFFS ones) is run multiple times (can be configuredd) for better accuracy, as the results often vary between runs.
We recommend using at least `100` runs, but default is set to `10` for convenience.
### Disclaimer
While this benchmark tries to give objective results, they may vary by significant amount with different settings, especially for filesystem with large amount of compile time configuration options such as LittleFS.
By default, this example uses 4 line SD mode, utilizing 6 pins: CLK, CMD, D0 - D3. It is possible to use 1-line mode (CLK, CMD, D0) by changing "SD/MMC bus width" in the example configuration menu (see `CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_1`).
Note that even if card's D3 line is not connected to the ESP chip, it still has to be pulled up, otherwise the card will go into SPI protocol mode.
### Note about GPIO2 (ESP32 only)
GPIO2 pin is used as a bootstrapping pin, and should be low to enter UART download mode. One way to do this is to connect GPIO0 and GPIO2 using a jumper, and then the auto-reset circuit on most development boards will pull GPIO2 low along with GPIO0, when entering download mode.
- Some boards have pulldown and/or LED on GPIO2. LED is usually ok, but pulldown will interfere with D0 signals and must be removed. Check the schematic of your development board for anything connected to GPIO2.
### Note about GPIO12 (ESP32 only)
GPIO12 is used as a bootstrapping pin to select output voltage of an internal regulator which powers the flash chip (VDD_SDIO). This pin has an internal pulldown so if left unconnected it will read low at reset (selecting default 3.3V operation). When adding a pullup to this pin for SD card operation, consider the following:
- For boards which don't use the internal regulator (VDD_SDIO) to power the flash, GPIO12 can be pulled high.
- For boards which use 1.8V flash chip, GPIO12 needs to be pulled high at reset. This is fully compatible with SD card operation.
- On boards which use the internal regulator and a 3.3V flash chip, GPIO12 must be low at reset. This is incompatible with SD card operation.
* In most cases, external pullup can be omitted and an internal pullup can be enabled using a `gpio_pullup_en(GPIO_NUM_12);` call. Most SD cards work fine when an internal pullup on GPIO12 line is enabled. Note that if ESP32 experiences a power-on reset while the SD card is sending data, high level on GPIO12 can be latched into the bootstrapping register, and ESP32 will enter a boot loop until external reset with correct GPIO12 level is applied.
* Another option is to burn the flash voltage selection efuses. This will permanently select 3.3V output voltage for the internal regulator, and GPIO12 will not be used as a bootstrapping pin. Then it is safe to connect a pullup resistor to GPIO12. This option is suggested for production use.
The following command can be used to program flash voltage selection efuses **to 3.3V**:
This command will burn the `XPD_SDIO_TIEH`, `XPD_SDIO_FORCE`, and `XPD_SDIO_REG` efuses. With all three burned to value 1, the internal VDD_SDIO flash voltage regulator is permanently enabled at 3.3V. See the technical reference manual for more details.
`espefuse.py` has a `--do-not-confirm` option if running from an automated flashing script.
See [the document about pullup requirements](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/sd_pullup_requirements.html) for more details about pullup support and compatibility of modules and development boards.
This only applies when `Test SD card` setting in `Performance Benchmark Example Configuration` is enabled.
On ESP32-P4, Slot 1 of the SDMMC peripheral is connected to GPIO pins using GPIO matrix. This allows arbitrary GPIOs to be used to connect an SD card. In this example, GPIOs can be configured in two ways:
1. Using menuconfig: Run `idf.py menuconfig` in the project directory and open `Performance Benchmark Example Configuration` menu.
2. In the source code: See the initialization of `sdmmc_slot_config_t slot_config` structure in the example code.
If pins selected correspond with default pins used for ESP32-P4 SDMMC (i.e. SD card slot is connected to them), possibly an additional setting up needs to be done.
These pins are able to connect to an ultra high-speed SD card (UHS-I) which requires 1.8V switching (instead of the regular 3.3V). This means the user has to provide an external LDO power supply to use them, or to enable and configure an internal LDO via `idf.py menuconfig` -> `SD/MMC Example Configuration` -> `SD power supply comes from internal LDO IO`.
When using different GPIO pins this is not required and `SD power supply comes from internal LDO IO` setting can be disabled.
LittleFS offers many other compile time configuration options which need to be set in it's component config.
These setting will have effect on it's performance.
#### Note about FATFS
To achieve the best performance the cluster should match with the target size, and be as high as possible.
However the higher the cluster size the more space will be wasted by partially filled clusters.
Keep in mind that the cluster size needs to be a multiple of sector size for SPI-flash that's 4096 and for SD-Card it's 512.
Also, the size of the storage medium determines maximum cluster size, for that reason this example uses 2MB of flash just for the filesystem (4MB by default, for smaller cluster sizes (16k) around 1MB should be enough.
I (302) example: Starting benchmark test with target size 65536 bytes
I (302) example: Internal flash test
I (302) example: Mountig WL layer...
I (622) example: WL layer mounted
[SPI Flash raw write ] (100x) 96.610 ms 64.00 kB 0.647 MB/s
[SPI Flash raw read ] (100x) 8.076 ms 64.00 kB 7.739 MB/s
I (11242) example: WL layer unmounted
I (11242) example: Mounting FATFS partition, with cluster size 65536 bytes
W (11242) vfs_fat_spiflash: f_mount failed (13)
I (11252) vfs_fat_spiflash: Formatting FATFS partition, allocation unit size=65536
I (11672) vfs_fat_spiflash: Mounting again
I (11672) example: FATFS mounted to /spiflash
[SPI FATFS (new file): write target size ] (100x) 1053.682 ms 64.00 kB 0.059 MB/s
[SPI FATFS (new file): read target size ] (100x) 8.124 ms 64.00 kB 7.694 MB/s
[SPI FATFS (new file): write more than target size ] (100x) 1259.972 ms 76.80 kB 0.060 MB/s
[SPI FATFS (new file): read more than target size ] (100x) 10.728 ms 76.80 kB 6.991 MB/s
[SPI FATFS (new file): write less than target size ] (100x) 850.835 ms 53.33 kB 0.061 MB/s
[SPI FATFS (new file): read less than target size ] (100x) 7.156 ms 53.33 kB 7.278 MB/s
[SPI FATFS (new file): write tiny size ] (100x) 1.180 ms 0.25 kB 0.206 MB/s
[SPI FATFS (new file): read tiny size ] (100x) 0.585 ms 0.25 kB 0.416 MB/s
I (510282) example: FATFS partition unmounted
I (510282) example: Mounting SPIFFS partition...
W (510282) SPIFFS: mount failed, -10025. formatting...
I (530862) example: SPIFFS mounted to /spiflash
[SPI SPIFFS (new file): write target size ] (1x) 464.198 ms 64.00 kB 0.135 MB/s
[SPI SPIFFS (new file): read target size ] (1x) 137.664 ms 64.00 kB 0.454 MB/s
[SPI SPIFFS (new file): write more than target size ] (1x) 555.745 ms 76.80 kB 0.135 MB/s
[SPI SPIFFS (new file): read more than target size ] (1x) 146.080 ms 76.80 kB 0.513 MB/s
[SPI SPIFFS (new file): write less than target size ] (1x) 390.201 ms 53.33 kB 0.133 MB/s
[SPI SPIFFS (new file): read less than target size ] (1x) 128.494 ms 53.33 kB 0.405 MB/s
[SPI SPIFFS (new file): write tiny size ] (1x) 0.050 ms 0.25 kB 4.864 MB/s
[SPI SPIFFS (new file): read tiny size ] (1x) 0.412 ms 0.25 kB 0.590 MB/s
I (534762) example: SPIFFS partition unmounted
I (534762) example: Mounting LittleFS partition...
E (534772) esp_littlefs: /IDF/examples/storage/perf_benchmark/managed_components/joltwallet__littlefs/src/littlefs/lfs.c:1366:error: Corrupted dir pair at {0x0, 0x1}
W (534782) esp_littlefs: mount failed, (-84). formatting...
I (534862) example: LittleFS mounted to /spiflash
[SPI LittleFS (new file): write target size ] (100x) 946.405 ms 64.00 kB 0.066 MB/s
[SPI LittleFS (new file): read target size ] (100x) 28.988 ms 64.00 kB 2.156 MB/s
[SPI LittleFS (new file): write more than target size ] (100x) 1176.518 ms 76.80 kB 0.064 MB/s
[SPI LittleFS (new file): read more than target size ] (100x) 39.843 ms 76.80 kB 1.882 MB/s
[SPI LittleFS (new file): write less than target size ] (100x) 821.555 ms 53.33 kB 0.063 MB/s
[SPI LittleFS (new file): read less than target size ] (100x) 25.848 ms 53.33 kB 2.015 MB/s
[SPI LittleFS (new file): write tiny size ] (100x) 0.043 ms 0.25 kB 5.635 MB/s
[SPI LittleFS (new file): read tiny size ] (100x) 0.036 ms 0.25 kB 6.685 MB/s
I (899232) esp_littlefs: Using SD card handle 0x3ffd8880 for LittleFS mount
W (899242) esp_littlefs: SD card is too big (sector=512, count=122142720; total=62537072640 bytes), throttling to maximum possible 8388607 blocks
E (899262) esp_littlefs: /IDF/examples/storage/perf_benchmark/managed_components/joltwallet__littlefs/src/littlefs/lfs.c:1366:error: Corrupted dir pair at {0x0, 0x1}
W (899272) esp_littlefs: mount failed, (-84). formatting...
I (901892) esp_littlefs: SD card formatted!
I (901932) example: LittleFS mounted to /sdcard
I (901932) example: SD card mounted - LittleFS
[SD LittleFS (new file): write target size ] (100x) 2723.682 ms 64.00 kB 0.023 MB/s
[SD LittleFS (new file): read target size ] (100x) 235.108 ms 64.00 kB 0.266 MB/s
[SD LittleFS (new file): write more than target size ] (100x) 3312.231 ms 76.80 kB 0.023 MB/s
[SD LittleFS (new file): read more than target size ] (100x) 402.211 ms 76.80 kB 0.186 MB/s
[SD LittleFS (new file): write less than target size ] (100x) 2311.122 ms 53.33 kB 0.023 MB/s
[SD LittleFS (new file): read less than target size ] (100x) 226.808 ms 53.33 kB 0.230 MB/s
[SD LittleFS (new file): write tiny size ] (100x) 17.263 ms 0.25 kB 0.014 MB/s
[SD LittleFS (new file): read tiny size ] (100x) 0.348 ms 0.25 kB 0.699 MB/s
A fatal error occurred: Failed to connect to Espressif device: Invalid head of packet (0x34)
```
Disconnect the SD card D0/MISO line from GPIO2 and try uploading again. Read "Note about GPIO2" above.
### Card fails to initialize with `sdmmc_init_sd_scr: send_scr (1) returned 0x107` error
Check connections between the card and the ESP32. For example, if you have disconnected GPIO2 to work around the flashing issue, connect it back and reset the ESP32 (using a button on the development board, or by pressing Ctrl-T Ctrl-R in IDF Monitor).
### Card fails to initialize with `sdmmc_check_scr: send_scr returned 0xffffffff` error
Connections between the card and the ESP32 are too long for the frequency used. Try using shorter connections, or try reducing the clock speed of SD interface.