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->wrblockstart = (off_t)-1;
|
||||
rwb->wrexpectedblock = (off_t)-1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -240,56 +239,160 @@ static ssize_t rwb_writebuffer(FAR struct rwbuffer_s *rwb,
|
||||
off_t startblock, uint32_t nblocks,
|
||||
FAR const uint8_t *wrbuffer)
|
||||
{
|
||||
int ret;
|
||||
uint32_t nwritten = nblocks;
|
||||
|
||||
/* Write writebuffer Logic */
|
||||
|
||||
rwb_wrcanceltimeout(rwb);
|
||||
|
||||
/* First: Should we flush out our cache? We would do that if (1) we already
|
||||
* 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
|
||||
*/
|
||||
/* Is data saved in the write buffer? */
|
||||
|
||||
if (((startblock != rwb->wrexpectedblock) && (rwb->wrnblocks)) ||
|
||||
((rwb->wrnblocks + nblocks) > rwb->wrmaxblocks))
|
||||
if (rwb->wrnblocks > 0)
|
||||
{
|
||||
finfo("writebuffer miss, expected: %08x, given: %08x\n",
|
||||
rwb->wrexpectedblock, startblock);
|
||||
off_t wrbend;
|
||||
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,
|
||||
rwb->wrnblocks);
|
||||
if (ret < 0)
|
||||
wrbend = rwb->wrblockstart + rwb->wrnblocks;
|
||||
newend = startblock + nblocks;
|
||||
|
||||
if (wrbend < startblock || rwb->wrblockstart > newend)
|
||||
{
|
||||
ferr("ERROR: Error writing multiple from cache: %d\n", -ret);
|
||||
return ret;
|
||||
/* Nothing to do */;
|
||||
}
|
||||
|
||||
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->wrnblocks = nblocks;
|
||||
}
|
||||
|
||||
/* Add data to cache */
|
||||
if (rwb->wrnblocks > 0)
|
||||
{
|
||||
rwb_wrstarttimeout(rwb);
|
||||
}
|
||||
|
||||
finfo("writebuffer: copying %d bytes from %p to %p\n",
|
||||
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;
|
||||
return nwritten;
|
||||
}
|
||||
#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
|
||||
* 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)
|
||||
@ -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)
|
||||
{
|
||||
@ -496,7 +599,7 @@ int rwb_invalidate_writebuffer(FAR struct rwbuffer_s *rwb,
|
||||
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) */
|
||||
{
|
||||
@ -1005,40 +1108,14 @@ ssize_t rwb_write(FAR struct rwbuffer_s *rwb, off_t startblock,
|
||||
{
|
||||
finfo("startblock=%d wrbuffer=%p\n", startblock, wrbuffer);
|
||||
|
||||
/* Use the block cache unless the buffer size is bigger than block
|
||||
* cache.
|
||||
*/
|
||||
|
||||
if (nblocks > rwb->wrmaxblocks)
|
||||
ret = nxsem_wait(&rwb->wrsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* First flush the cache */
|
||||
|
||||
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);
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Buffer the data in the write buffer */
|
||||
|
||||
ret = nxsem_wait(&rwb->wrsem);
|
||||
if (ret < 0)
|
||||
{
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
|
||||
ret = rwb_writebuffer(rwb, startblock, nblocks, wrbuffer);
|
||||
rwb_semgive(&rwb->wrsem);
|
||||
}
|
||||
ret = rwb_writebuffer(rwb, startblock, nblocks, wrbuffer);
|
||||
rwb_semgive(&rwb->wrsem);
|
||||
|
||||
/* On success, return the number of blocks that we were requested to
|
||||
* 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 */
|
||||
uint16_t wrnblocks; /* Number of blocks in write buffer */
|
||||
off_t wrblockstart; /* First block in write buffer */
|
||||
off_t wrexpectedblock; /* Next block expected */
|
||||
#endif
|
||||
|
||||
/* This is the state of the read-ahead buffering */
|
||||
|
Loading…
x
Reference in New Issue
Block a user