Optimized writing of zeroes to files. Instead of allocating a small buffer

on the fly, clearing and writing it each time, we now use an iovec with 32
identical entries pointing to a clear page that we prepare once at
initialization. This speeds up clear_image in low memory situations
dramatically.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35304 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2010-01-26 21:30:50 +00:00
parent cef3da793a
commit 64a9bd15c8
1 changed files with 32 additions and 34 deletions

View File

@ -106,7 +106,12 @@ static void add_to_iovec(iovec* vecs, uint32 &index, uint32 max, addr_t address,
static struct cache_module_info* sCacheModule; static struct cache_module_info* sCacheModule;
static const uint8 kZeroBuffer[4096] = {};
static const uint32 kZeroVecCount = 32;
static const size_t kZeroVecSize = kZeroVecCount * B_PAGE_SIZE;
static addr_t sZeroPage; // physical address
static iovec sZeroVecs[kZeroVecCount];
// #pragma mark - // #pragma mark -
@ -624,22 +629,6 @@ write_to_file(file_cache_ref* ref, void* cookie, off_t offset, int32 pageOffset,
addr_t buffer, size_t bufferSize, bool useBuffer, size_t lastReservedPages, addr_t buffer, size_t bufferSize, bool useBuffer, size_t lastReservedPages,
size_t reservePages) size_t reservePages)
{ {
size_t chunkSize = 0;
if (!useBuffer) {
// we need to allocate a zero buffer
// TODO: use smaller buffers if this fails
chunkSize = min_c(bufferSize, B_PAGE_SIZE);
buffer = (addr_t)malloc(chunkSize);
if (buffer == 0)
return B_NO_MEMORY;
memset((void*)buffer, 0, chunkSize);
}
iovec vec;
vec.iov_base = (void*)buffer;
vec.iov_len = bufferSize;
push_access(ref, offset, bufferSize, true); push_access(ref, offset, bufferSize, true);
ref->cache->Unlock(); ref->cache->Unlock();
vm_page_unreserve_pages(lastReservedPages); vm_page_unreserve_pages(lastReservedPages);
@ -648,20 +637,21 @@ write_to_file(file_cache_ref* ref, void* cookie, off_t offset, int32 pageOffset,
if (!useBuffer) { if (!useBuffer) {
while (bufferSize > 0) { while (bufferSize > 0) {
if (bufferSize < chunkSize) size_t written = min_c(bufferSize, kZeroVecSize);
chunkSize = bufferSize;
status = vfs_write_pages(ref->vnode, cookie, offset + pageOffset, status = vfs_write_pages(ref->vnode, cookie, offset + pageOffset,
&vec, 1, 0, &chunkSize); sZeroVecs, kZeroVecCount, B_PHYSICAL_IO_REQUEST, &written);
if (status < B_OK) if (status != B_OK)
break; return status;
if (written == 0)
return B_ERROR;
bufferSize -= chunkSize; bufferSize -= written;
pageOffset += chunkSize; pageOffset += written;
} }
free((void*)buffer);
} else { } else {
iovec vec;
vec.iov_base = (void*)buffer;
vec.iov_len = bufferSize;
status = vfs_write_pages(ref->vnode, cookie, offset + pageOffset, status = vfs_write_pages(ref->vnode, cookie, offset + pageOffset,
&vec, 1, 0, &bufferSize); &vec, 1, 0, &bufferSize);
} }
@ -1090,6 +1080,18 @@ file_cache_init_post_boot_device(void)
extern "C" status_t extern "C" status_t
file_cache_init(void) file_cache_init(void)
{ {
// allocate a clean page we can use for writing zeroes
vm_page_reserve_pages(1, VM_PRIORITY_SYSTEM);
vm_page* page = vm_page_allocate_page(PAGE_STATE_CLEAR);
vm_page_unreserve_pages(1);
sZeroPage = (addr_t)page->physical_page_number * B_PAGE_SIZE;
for (uint32 i = 0; i < kZeroVecCount; i++) {
sZeroVecs[i].iov_base = (void*)sZeroPage;
sZeroVecs[i].iov_len = B_PAGE_SIZE;
}
register_generic_syscall(CACHE_SYSCALLS, file_cache_control, 1, 0); register_generic_syscall(CACHE_SYSCALLS, file_cache_control, 1, 0);
return B_OK; return B_OK;
} }
@ -1296,16 +1298,12 @@ file_cache_write(void* _cacheRef, void* cookie, off_t offset,
} }
// NULL buffer -- use a dummy buffer to write zeroes // NULL buffer -- use a dummy buffer to write zeroes
// TODO: This is not particularly efficient!
iovec vec;
vec.iov_base = (void*)kZeroBuffer;
vec.iov_len = sizeof(kZeroBuffer);
size_t size = *_size; size_t size = *_size;
while (size > 0) { while (size > 0) {
size_t toWrite = min_c(size, vec.iov_len); size_t toWrite = min_c(size, kZeroVecSize);
size_t written = toWrite; size_t written = toWrite;
status_t error = vfs_write_pages(ref->vnode, cookie, offset, &vec, status_t error = vfs_write_pages(ref->vnode, cookie, offset,
1, 0, &written); sZeroVecs, kZeroVecCount, B_PHYSICAL_IO_REQUEST, &written);
if (error != B_OK) if (error != B_OK)
return error; return error;
if (written == 0) if (written == 0)