rwbuffer: Optimize the buffer algorithm
avoid the buffer flush as much as possible Change-Id: I902f374e9540b36bd0b0c77a34cab5014a2c24fc Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com> Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
parent
e7034c102f
commit
aa57174eb9
@ -136,7 +136,6 @@ static inline void rwb_resetwrbuffer(FAR struct rwbuffer_s *rwb)
|
|||||||
|
|
||||||
rwb->wrnblocks = 0;
|
rwb->wrnblocks = 0;
|
||||||
rwb->wrblockstart = (off_t)-1;
|
rwb->wrblockstart = (off_t)-1;
|
||||||
rwb->wrexpectedblock = (off_t)-1;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -240,56 +239,160 @@ static ssize_t rwb_writebuffer(FAR struct rwbuffer_s *rwb,
|
|||||||
off_t startblock, uint32_t nblocks,
|
off_t startblock, uint32_t nblocks,
|
||||||
FAR const uint8_t *wrbuffer)
|
FAR const uint8_t *wrbuffer)
|
||||||
{
|
{
|
||||||
int ret;
|
uint32_t nwritten = nblocks;
|
||||||
|
|
||||||
/* Write writebuffer Logic */
|
/* Write writebuffer Logic */
|
||||||
|
|
||||||
rwb_wrcanceltimeout(rwb);
|
rwb_wrcanceltimeout(rwb);
|
||||||
|
|
||||||
/* First: Should we flush out our cache? We would do that if (1) we already
|
/* Is data saved in the write buffer? */
|
||||||
* buffering blocks and the next block writing is not in the same sequence,
|
|
||||||
* or (2) the number of blocks would exceed our allocated buffer capacity
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (((startblock != rwb->wrexpectedblock) && (rwb->wrnblocks)) ||
|
if (rwb->wrnblocks > 0)
|
||||||
((rwb->wrnblocks + nblocks) > rwb->wrmaxblocks))
|
|
||||||
{
|
{
|
||||||
finfo("writebuffer miss, expected: %08x, given: %08x\n",
|
off_t wrbend;
|
||||||
rwb->wrexpectedblock, startblock);
|
off_t newend;
|
||||||
|
|
||||||
/* Flush the write buffer */
|
/* Now there are five cases:
|
||||||
|
*
|
||||||
|
* 1. We update the non-overlapping region
|
||||||
|
*/
|
||||||
|
|
||||||
ret = rwb->wrflush(rwb->dev, rwb->wrbuffer, rwb->wrblockstart,
|
wrbend = rwb->wrblockstart + rwb->wrnblocks;
|
||||||
rwb->wrnblocks);
|
newend = startblock + nblocks;
|
||||||
if (ret < 0)
|
|
||||||
|
if (wrbend < startblock || rwb->wrblockstart > newend)
|
||||||
{
|
{
|
||||||
ferr("ERROR: Error writing multiple from cache: %d\n", -ret);
|
/* Nothing to do */;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rwb_resetwrbuffer(rwb);
|
/* 2. We update the entire write buffer. */
|
||||||
|
|
||||||
|
else if (rwb->wrblockstart > startblock && wrbend < newend)
|
||||||
|
{
|
||||||
|
rwb->wrnblocks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We are going to update a subset of the write buffer. Three
|
||||||
|
* more cases to consider:
|
||||||
|
*
|
||||||
|
* 3. We update a portion in the middle of the write buffer
|
||||||
|
*/
|
||||||
|
|
||||||
|
else if (rwb->wrblockstart <= startblock && wrbend >= newend)
|
||||||
|
{
|
||||||
|
FAR uint8_t *dest;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
/* Copy the data to the middle of write buffer */
|
||||||
|
|
||||||
|
offset = startblock - rwb->wrblockstart;
|
||||||
|
dest = rwb->wrbuffer + offset * rwb->blocksize;
|
||||||
|
memcpy(dest, wrbuffer, nblocks * rwb->blocksize);
|
||||||
|
|
||||||
|
nblocks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4. We upate a portion at the end of the write buffer */
|
||||||
|
|
||||||
|
else if (wrbend >= startblock && wrbend <= newend)
|
||||||
|
{
|
||||||
|
FAR uint8_t *dest;
|
||||||
|
size_t offset;
|
||||||
|
size_t ncopy;
|
||||||
|
|
||||||
|
/* Copy the data from the updating region to the end
|
||||||
|
* of the write buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
offset = rwb->wrnblocks - (wrbend - startblock);
|
||||||
|
ncopy = rwb->wrmaxblocks - offset;
|
||||||
|
if (ncopy > nblocks)
|
||||||
|
{
|
||||||
|
ncopy = nblocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest = rwb->wrbuffer + offset * rwb->blocksize;
|
||||||
|
memcpy(dest, wrbuffer, ncopy * rwb->blocksize);
|
||||||
|
|
||||||
|
rwb->wrnblocks = offset + ncopy;
|
||||||
|
wrbuffer += ncopy * rwb->blocksize;
|
||||||
|
startblock += ncopy;
|
||||||
|
nblocks -= ncopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 5. We update a portion at the beginning of the write buffer */
|
||||||
|
|
||||||
|
else /* if (rwb->wrblockstart >= startblock && wrbend >= newend) */
|
||||||
|
{
|
||||||
|
FAR uint8_t *dest;
|
||||||
|
FAR const uint8_t *src;
|
||||||
|
size_t ncopy;
|
||||||
|
|
||||||
|
DEBUGASSERT(rwb->wrblockstart >= startblock && wrbend >= newend);
|
||||||
|
|
||||||
|
/* Move the cached data to the end of the write buffer */
|
||||||
|
|
||||||
|
ncopy = rwb->wrblockstart - startblock;
|
||||||
|
if (ncopy > rwb->wrmaxblocks - rwb->wrnblocks)
|
||||||
|
{
|
||||||
|
ncopy = rwb->wrmaxblocks - rwb->wrnblocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest = rwb->wrbuffer + ncopy * rwb->blocksize;
|
||||||
|
memmove(dest, rwb->wrbuffer, ncopy * rwb->blocksize);
|
||||||
|
|
||||||
|
rwb->wrblockstart -= ncopy;
|
||||||
|
rwb->wrnblocks += ncopy;
|
||||||
|
|
||||||
|
/* Copy the data from the updating region to the beginning
|
||||||
|
* of the write buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ncopy = newend - rwb->wrblockstart;
|
||||||
|
src = wrbuffer + (nblocks - ncopy) * rwb->blocksize;
|
||||||
|
memcpy(rwb->wrbuffer, src, ncopy * rwb->blocksize);
|
||||||
|
|
||||||
|
nblocks -= ncopy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* writebuffer is empty? Then initialize it */
|
/* Use the block cache unless the buffer size is bigger than block cache */
|
||||||
|
|
||||||
if (rwb->wrnblocks == 0)
|
if (nblocks > rwb->wrmaxblocks)
|
||||||
{
|
{
|
||||||
finfo("Fresh cache starting at block: 0x%08x\n", startblock);
|
ssize_t ret = rwb->wrflush(rwb->dev, wrbuffer, startblock, nblocks);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (nblocks)
|
||||||
|
{
|
||||||
|
/* Flush the write buffer */
|
||||||
|
|
||||||
|
if (rwb->wrnblocks > 0)
|
||||||
|
{
|
||||||
|
ssize_t ret = rwb->wrflush(rwb->dev, rwb->wrbuffer,
|
||||||
|
rwb->wrblockstart, rwb->wrnblocks);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buffer the data in the write buffer */
|
||||||
|
|
||||||
|
memcpy(rwb->wrbuffer, wrbuffer, nblocks * rwb->blocksize);
|
||||||
rwb->wrblockstart = startblock;
|
rwb->wrblockstart = startblock;
|
||||||
|
rwb->wrnblocks = nblocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add data to cache */
|
if (rwb->wrnblocks > 0)
|
||||||
|
{
|
||||||
|
rwb_wrstarttimeout(rwb);
|
||||||
|
}
|
||||||
|
|
||||||
finfo("writebuffer: copying %d bytes from %p to %p\n",
|
return nwritten;
|
||||||
nblocks * rwb->blocksize, wrbuffer,
|
|
||||||
&rwb->wrbuffer[rwb->wrnblocks * rwb->blocksize]);
|
|
||||||
memcpy(&rwb->wrbuffer[rwb->wrnblocks * rwb->blocksize],
|
|
||||||
wrbuffer, nblocks * rwb->blocksize);
|
|
||||||
|
|
||||||
rwb->wrnblocks += nblocks;
|
|
||||||
rwb->wrexpectedblock = rwb->wrblockstart + rwb->wrnblocks;
|
|
||||||
rwb_wrstarttimeout(rwb);
|
|
||||||
return nblocks;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -454,7 +557,7 @@ int rwb_invalidate_writebuffer(FAR struct rwbuffer_s *rwb,
|
|||||||
/* We are going to invalidate a subset of the write buffer. Three
|
/* We are going to invalidate a subset of the write buffer. Three
|
||||||
* more cases to consider:
|
* more cases to consider:
|
||||||
*
|
*
|
||||||
* 2. We invalidate a portion in the middle of the write buffer
|
* 3. We invalidate a portion in the middle of the write buffer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
else if (rwb->wrblockstart < startblock && wrbend > invend)
|
else if (rwb->wrblockstart < startblock && wrbend > invend)
|
||||||
@ -488,7 +591,7 @@ int rwb_invalidate_writebuffer(FAR struct rwbuffer_s *rwb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3. We invalidate a portion at the end of the write buffer */
|
/* 4. We invalidate a portion at the end of the write buffer */
|
||||||
|
|
||||||
else if (wrbend > startblock && wrbend <= invend)
|
else if (wrbend > startblock && wrbend <= invend)
|
||||||
{
|
{
|
||||||
@ -496,7 +599,7 @@ int rwb_invalidate_writebuffer(FAR struct rwbuffer_s *rwb,
|
|||||||
ret = OK;
|
ret = OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 4. We invalidate a portion at the beginning of the write buffer */
|
/* 5. We invalidate a portion at the beginning of the write buffer */
|
||||||
|
|
||||||
else /* if (rwb->wrblockstart >= startblock && wrbend > invend) */
|
else /* if (rwb->wrblockstart >= startblock && wrbend > invend) */
|
||||||
{
|
{
|
||||||
@ -1005,40 +1108,14 @@ ssize_t rwb_write(FAR struct rwbuffer_s *rwb, off_t startblock,
|
|||||||
{
|
{
|
||||||
finfo("startblock=%d wrbuffer=%p\n", startblock, wrbuffer);
|
finfo("startblock=%d wrbuffer=%p\n", startblock, wrbuffer);
|
||||||
|
|
||||||
/* Use the block cache unless the buffer size is bigger than block
|
ret = nxsem_wait(&rwb->wrsem);
|
||||||
* cache.
|
if (ret < 0)
|
||||||
*/
|
|
||||||
|
|
||||||
if (nblocks > rwb->wrmaxblocks)
|
|
||||||
{
|
{
|
||||||
/* First flush the cache */
|
return (ssize_t)ret;
|
||||||
|
|
||||||
ret = nxsem_wait(&rwb->wrsem);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
return (ssize_t)ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
rwb_wrflush(rwb);
|
|
||||||
rwb_semgive(&rwb->wrsem);
|
|
||||||
|
|
||||||
/* Then transfer the data directly to the media */
|
|
||||||
|
|
||||||
ret = rwb->wrflush(rwb->dev, wrbuffer, startblock, nblocks);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Buffer the data in the write buffer */
|
|
||||||
|
|
||||||
ret = nxsem_wait(&rwb->wrsem);
|
ret = rwb_writebuffer(rwb, startblock, nblocks, wrbuffer);
|
||||||
if (ret < 0)
|
rwb_semgive(&rwb->wrsem);
|
||||||
{
|
|
||||||
return (ssize_t)ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = rwb_writebuffer(rwb, startblock, nblocks, wrbuffer);
|
|
||||||
rwb_semgive(&rwb->wrsem);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* On success, return the number of blocks that we were requested to
|
/* On success, return the number of blocks that we were requested to
|
||||||
* write. This is for compatibility with the normal return of a block
|
* write. This is for compatibility with the normal return of a block
|
||||||
|
@ -144,7 +144,6 @@ struct rwbuffer_s
|
|||||||
uint8_t *wrbuffer; /* Allocated write buffer */
|
uint8_t *wrbuffer; /* Allocated write buffer */
|
||||||
uint16_t wrnblocks; /* Number of blocks in write buffer */
|
uint16_t wrnblocks; /* Number of blocks in write buffer */
|
||||||
off_t wrblockstart; /* First block in write buffer */
|
off_t wrblockstart; /* First block in write buffer */
|
||||||
off_t wrexpectedblock; /* Next block expected */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This is the state of the read-ahead buffering */
|
/* This is the state of the read-ahead buffering */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user