littlefs-project / littlefs

A little fail-safe filesystem designed for microcontrollers
BSD 3-Clause "New" or "Revised" License
5.15k stars 793 forks source link

Do open duration depends on number of files in folder ? #721

Open Antatip opened 2 years ago

Antatip commented 2 years ago

Hello,

I am new to littlefs and file systems in general. I am making benchmarks of it using STM32WB55 and a 16M SPI flash.

I noticed that open time depends on the number of files in a folder : A single file in a folder can be opened in 18ms (with the best settings I found)

When my folder contains 50 files :

root
└─── sounds
│  └── allelujah.mp3
│  └── alf.mp3
│  └── boom.mp3
│   ...
│   ...
│   └── zzz.mp3

I can open it in ~450ms.

So I tried putting each file in a folder :

root
└─── sounds
│   └── allelujah
│   │   └── s.mp3
│   └── alf
│   │   └── s.mp3
│   └── boom
│   │   └── s.mp3
│   ...
│   ...
│   └── zzz
│   │   └── s.mp3

In that case, one file opens in 240ms

Then I put every folder in alphabetical folders :

root
└─── sounds
│   └── a
│   │   └── allelujah
│   │   │  └── s.mp3
│   │   └── alf
│   │   │  └── s.mp3
│   └── b
│   │   └── boom
│   │   │  └── s.mp3
│   ...
│   ...
│   └── z
│   │   └── zzz
│   │   │  └── s.mp3

Here, file opens in around 150ms.

Settings

LFS v2.5.0

fileSystem_config.read = device_flash_sector_device_read;
fileSystem_config.prog = device_flash_sector_device_prog;
fileSystem_config.erase = device_flash_sector_device_erase;
fileSystem_config.sync = device_flash_sector_device_sync;

I tried using block read/write/erase callbacks but I get a LFS_ERR_NOSPC error after creating ~100 files so I use the sector functions (driver w25qxx).

Sync just returns 0.

fileSystem_config.read_size = 64;
fileSystem_config.prog_size = 32;
fileSystem_config.block_size = 4096; // Using sectors instead of blocks
fileSystem_config.block_count = 4096;
fileSystem_config.block_cycles =  500;
fileSystem_config.cache_size = 256;
fileSystem_config.lookahead_size = 1024; // waiting a nice open time before finding the best value

Questions

Are those the standard durations ? If so, any idea of performance improvements ? If not, What am I doing wrong ?

PS : Why are folders a lot quicker to find than files ?

geky commented 2 years ago

Yes, this is one limitation of littlefs currently, though I do have plans to improve the performance by changing the current directory from a linked-list into a B-tree (the directory entries are currently stored in sorted order to make this change possible).

Though this has been low-priority since I was surprised to not hear this being a big issue for users. Though perhaps that is just due to more pressing performance issues.

Then I put every folder in alphabetical folders :

Sounds like a good workaround to me. I believe git uses a similar directory structure in its object store for similar reasons (ls .git/objects).

I tried using block read/write/erase callbacks but I get a LFS_ERR_NOSPC error after creating ~100 files so I use the sector functions (driver w25qxx).

This is correct. Unfortunately the names of sectors/blocks/pages/clusters is inconsistent between different types of storage, so littlefs uses the term block for everything.

PS : Why are folders a lot quicker to find than files ?

That is curious. I think it's caused by the extra space inline files take up. Are some of your files smaller than the cache size and ~1/8th the erase block? These get stored inline in the directory to avoid using a whole block. These probably take up more space than the directory entry, meaning more directory blocks in the parent directory that need to be scanned during lookup.

Antatip commented 2 years ago

Hi,

Thank you very much.

My files can go from a few bytes up to 8k. I did measure this (with buffer size comparison and before any optimizations) :

image

More than 150ms is still a little bit too much for low energy consumption, so I think I will switch to SPIFFS for the moment.

I made that choice by measuring each file system I know and I got this :

image

Maybe this will help, I also ran performance tests on read and write (each point is measured in a freshly formatted file system, poor granularity but useful for comparison) :

image

image

Appart from that, thank you for LittleFs which is easy to setup and try out.

geky commented 2 years ago

Thanks for sharing your results. These are quite interesting. The comparison of open times across filesystems is quite surprising, I would have expected both FAT and SPIFFS to also grow linearly.

I suspect has more to do with caching than the on-disk data structure. Better caching strategies is also one area littlefs could improve on.

Out of curiosity what is the FAT cluster size? Do you know how much cache is being provided to FAT and SPIFFS?

It would be interesting to see a comparison with cache_size = block_size = 4096, though this would come with a RAM cost.

Antatip commented 2 years ago

The ST implementation of FAT requires to read or write entire clusters so it is not linear. For write time, you must erase the cluster so it takes even more time. I guess ST implementation is pretty standard.

FAT can go from 512 to 4096 bytes per clusters.

About caching :

It would be interesting to see a comparison with cache_size = block_size = 4096, though this would come with a RAM cost.

Do you mean in LittleFS ? I did measure this a few weeks ago, I did not go up to sector size because the difference was not significant enough :

image