Skip to content

increase hint size in lfs_dir_traverse#1181

Open
zain-noman wants to merge 1 commit intolittlefs-project:masterfrom
zain-noman:cache_dir_traverse
Open

increase hint size in lfs_dir_traverse#1181
zain-noman wants to merge 1 commit intolittlefs-project:masterfrom
zain-noman:cache_dir_traverse

Conversation

@zain-noman
Copy link
Copy Markdown

Hi, I was noticing an issue where the number of read calls was too high. One of the functions that was causing this was lfs_dir_traverse. It was issuing read calls for each tag it read. From the comments in pull request 621, i concluded that the sequential reads could be reduced by increasing the hint size.

I compared the number of reads before and after changing the hint size and noticed a significant reduction (from 379K to 79K). The results are compiled in the attached excel file. These results were collected using the following script

#include "lfs.h"
#include "lfs_rambd.h"
#include <stdio.h>

int readCount = 0;
int bytesRead = 0;

int read_with_count(const struct lfs_config *c, lfs_block_t block,
    lfs_off_t off, void *buffer, lfs_size_t size)
{
    readCount++;
    bytesRead += size;
    return lfs_rambd_read(c,block,off,buffer,size);
}

int main()
{
    struct lfs_rambd_config bdCfg = {
        .read_size = 1,
        .prog_size = 1,
        .erase_size = 256,
        .erase_count = 32768
    };
    lfs_rambd_t bd;
    
    lfs_t lfs;
    struct lfs_config lfsCfg = {
        .context =  &bd,
        .read = read_with_count,
        .prog = lfs_rambd_prog,
        .erase = lfs_rambd_erase,
        .sync = lfs_rambd_sync,
        .read_size = 1,
        .prog_size = 1,
        .block_size = 256,
        .block_count = 32768,
        .block_cycles = -1,
        .cache_size = 256,
        .lookahead_size = 4096
    };

    lfs_rambd_create(&lfsCfg,&bdCfg);
    lfs_format(&lfs, &lfsCfg);
    lfs_mount(&lfs, &lfsCfg);

    char fileData1[72];
    for (int i = 0; i < sizeof(fileData1); i++)
    {
        fileData1[i] = i;
    }

    lfs_mkdir(&lfs,"myDir");

    printf("iteration,bytesRead,readCount\n");
    int maxReadCount = 0;
    for (int i = 0; i < 120; i++)
    {
        lfs_file_t testFile;
        char fileName[100];
        sprintf(fileName,"myDir/test%d",i);
        lfs_file_open(&lfs,&testFile,fileName,LFS_O_RDWR|LFS_O_CREAT);
           
        for (int i = 0; i < 900; i++)
        {
            readCount = 0;
            bytesRead = 0;
            lfs_file_write(&lfs,&testFile,fileData1,sizeof(fileData1));
            
            if ((i%30)==0)
                lfs_file_sync(&lfs,&testFile);
            
            // if (readCount > maxReadCount){
            //     maxReadCount = readCount;
                printf("%d,%d,%d\n", i*900 + i, bytesRead, readCount);
            // }
        }
        
        lfs_file_close(&lfs,&testFile);
    }
    lfs_unmount(&lfs);    
}

cache_dir_traverse.xlsx

@geky-bot
Copy link
Copy Markdown
Collaborator

Tests passed ✓, Code: 17136 B (+0.0%), Stack: 1448 B (+0.0%), Structs: 812 B (+0.0%)
Code Stack Structs Coverage
Default 17136 B (+0.0%) 1448 B (+0.0%) 812 B (+0.0%) Lines 2439/2600 lines (-0.0%)
Readonly 6234 B (+0.0%) 448 B (+0.0%) 812 B (+0.0%) Branches 1288/1624 branches (-0.0%)
Threadsafe 17988 B (+0.0%) 1448 B (+0.0%) 820 B (+0.0%) Benchmarks
Multiversion 17208 B (+0.0%) 1448 B (+0.0%) 816 B (+0.0%) Readed 29073115434 B (+0.2%)
Migrate 18800 B (+0.0%) 1752 B (+0.0%) 816 B (+0.0%) Proged 1482895246 B (+0.0%)
Error-asserts 17956 B (+0.0%) 1440 B (+0.0%) 812 B (+0.0%) Erased 1568921600 B (+0.0%)

@geky geky added enhancement performance needs minor version new functionality only allowed in minor versions labels Mar 11, 2026
@geky
Copy link
Copy Markdown
Member

geky commented Mar 11, 2026

Hi @zain-noman, thanks for creating a PR, sorry about the late response.

On one hand, I'm unlikely to merge this sort of change right now due to the current feature-freeze that allows focusing on littlefs3 (#1111, unstable). On the other hand, the main motivation for littlefs3 is performance, so this would be a good thing to consider.

Let me see if I can run it in our current benchmarks (may take a while).


Copying the raw numbers here (not a big issue, but .csvs are a bit easier when you don't have excel):

              before   after
read calls:   379139   79918 (-78.9%)
read bytes: 10749289 9723289 (-9.5%)

Some aimless thoughts:

  • The main concern is if this forces lfs_dir_traverse to read the full block when it does not need to. Mdir compaction is already a significant bottleneck, and involves nested lfs_dir_traverse "calls" (the emulated stack in this function). If cache_size/block_size is significantly higher (4KiB? 128KiB?), this risks worse performance.

  • I wonder if the same result can be emulated by setting read_size to a larger value. This would force a larger byte/call ratio while avoiding the full block reads. Though it may be a cludge.

  • NOR flash is surprisingly cheap for many small reads, there's really just the overhead of sending the address. But you're also seeing savings in total bytes read, which is interesting.

@geky geky removed the enhancement label Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs minor version new functionality only allowed in minor versions performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants