From a6f01b7d6edb95f8a385955cc17d52d8df263c4a Mon Sep 17 00:00:00 2001 From: robekras Date: Sun, 16 Jan 2022 20:50:01 +0100 Subject: [PATCH 1/2] Update lfs.c This should fix the performance issue if a new seek position belongs to currently cached data. This avoids unnecessary rereads of file data. --- lfs.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lfs.c b/lfs.c index e165e54..15543a8 100644 --- a/lfs.c +++ b/lfs.c @@ -3091,6 +3091,21 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file, return npos; } + // Get the difference between new and current file position + // If new position is after the current file position + // If new position belongs to the currently cached data + // Set new file position, + // and update also the block related position + int offset = npos - file->pos; + if (offset > 0) { + if ((file->off + offset) < lfs->cfg->block_size) { + file->pos = npos; + file->off += offset; + + return npos; + } + } + // write out everything beforehand, may be noop if rdonly int err = lfs_file_flush(lfs, file); if (err) { From 425dc810a5fa42bc6680a910a7e4ef982eaf75d6 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 10 Apr 2022 01:28:08 -0500 Subject: [PATCH 2/2] Modified robekras's optimization to avoid flush for all seeks in cache The basic idea is simple, if we seek to a position in the currently loaded cache, don't flush the cache. Notably this ensures that seek is always as fast or faster than just reading the data. This is a bit tricky since we need to check that our new block and offset match the cache, fortunately we can skip the block check by reevaluating the block index for both the current and new positions. Note this only works whene reading, for writing we need to always flush the cache, or else we will lose the pending write data. --- lfs.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/lfs.c b/lfs.c index 15543a8..a5309e4 100644 --- a/lfs.c +++ b/lfs.c @@ -3091,17 +3091,23 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file, return npos; } - // Get the difference between new and current file position - // If new position is after the current file position - // If new position belongs to the currently cached data - // Set new file position, - // and update also the block related position - int offset = npos - file->pos; - if (offset > 0) { - if ((file->off + offset) < lfs->cfg->block_size) { - file->pos = npos; - file->off += offset; - + // if we're only reading and our new offset is still in the file's cache + // we can avoid flushing and needing to reread the data + if ( +#ifndef LFS_READONLY + !(file->flags & LFS_F_WRITING) +#else + true +#endif + ) { + int oindex = lfs_ctz_index(lfs, &(lfs_off_t){file->pos}); + lfs_off_t noff = npos; + int nindex = lfs_ctz_index(lfs, &noff); + if (oindex == nindex + && noff >= file->cache.off + && noff < file->cache.off + file->cache.size) { + file->pos = npos; + file->off = noff; return npos; } }