Implement combining scattered physical pages using seperate iovecs in

PageWriteTransfer. This makes the transfer accept virtually contiguous pages,
where the offset is contiguous on either end of the current transfer, but where
the pages aren't physically contiguous. It will then add seperate iovecs for
these pages (32 at max right now). This reduces the number of IO requests
generated and allows for optimizations down the IO path (like in the physical to
virtual mapping case for example).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33526 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2009-10-11 16:52:19 +00:00
parent 303727515e
commit 7a4d60459e
+54 -23
View File
@@ -1014,10 +1014,11 @@ private:
PageWriterRun* fRun; PageWriterRun* fRun;
struct VMCache* fCache; struct VMCache* fCache;
off_t fOffset; off_t fOffset;
addr_t fPhysicalPageNumber;
uint32 fPageCount; uint32 fPageCount;
int32 fMaxPages; int32 fMaxPages;
status_t fStatus; status_t fStatus;
uint32 fVecCount;
iovec fVecs[32]; // TODO: make dynamic/configurable
}; };
@@ -1152,10 +1153,13 @@ PageWriteTransfer::SetTo(PageWriterRun* run, vm_page* page, int32 maxPages)
fRun = run; fRun = run;
fCache = page->cache; fCache = page->cache;
fOffset = page->cache_offset; fOffset = page->cache_offset;
fPhysicalPageNumber = page->physical_page_number;
fPageCount = 1; fPageCount = 1;
fMaxPages = maxPages; fMaxPages = maxPages;
fStatus = B_OK; fStatus = B_OK;
fVecs[0].iov_base = (void*)(page->physical_page_number << PAGE_SHIFT);
fVecs[0].iov_len = B_PAGE_SIZE;
fVecCount = 1;
} }
@@ -1166,23 +1170,53 @@ PageWriteTransfer::AddPage(vm_page* page)
|| (fMaxPages >= 0 && fPageCount >= (uint32)fMaxPages)) || (fMaxPages >= 0 && fPageCount >= (uint32)fMaxPages))
return false; return false;
// TODO: this makes it required to be physically contiguous even though addr_t nextBase
// we could put physically disjoint pages into the same write using = (addr_t)fVecs[fVecCount - 1].iov_base + fVecs[fVecCount - 1].iov_len;
// seperate iovecs for each page.
if ((page->physical_page_number != fPhysicalPageNumber + fPageCount if (page->physical_page_number << PAGE_SHIFT == nextBase
|| page->cache_offset != fOffset + fPageCount) && page->cache_offset == fOffset + fPageCount) {
&& (page->physical_page_number != fPhysicalPageNumber - 1 // append to last iovec
|| page->cache_offset != fOffset - 1)) { fVecs[fVecCount - 1].iov_len += B_PAGE_SIZE;
return false; fPageCount++;
return true;
} }
if (page->physical_page_number < fPhysicalPageNumber) nextBase = (addr_t)fVecs[0].iov_base - B_PAGE_SIZE;
fPhysicalPageNumber = page->physical_page_number; if (page->physical_page_number << PAGE_SHIFT == nextBase
if (page->cache_offset < fOffset) && page->cache_offset == fOffset - 1) {
// prepend to first iovec and adjust offset
fVecs[0].iov_base = (void*)nextBase;
fVecs[0].iov_len += B_PAGE_SIZE;
fOffset = page->cache_offset; fOffset = page->cache_offset;
fPageCount++;
return true;
}
fPageCount++; if ((page->cache_offset == fOffset + fPageCount
return true; || page->cache_offset == fOffset - 1)
&& fVecCount < sizeof(fVecs) / sizeof(fVecs[0])) {
// not physically contiguous or not in the right order
uint32 vectorIndex;
if (page->cache_offset < fOffset) {
// we are pre-pending another vector, move the other vecs
for (uint32 i = fVecCount; i > 0; i--)
fVecs[i] = fVecs[i - 1];
fOffset = page->cache_offset;
vectorIndex = 0;
} else
vectorIndex = fVecCount;
fVecs[vectorIndex].iov_base
= (void*)(page->physical_page_number << PAGE_SHIFT);
fVecs[vectorIndex].iov_len = B_PAGE_SIZE;
fVecCount++;
fPageCount++;
return true;
}
return false;
} }
@@ -1192,16 +1226,12 @@ PageWriteTransfer::Schedule(uint32 flags)
off_t writeOffset = (off_t)fOffset << PAGE_SHIFT; off_t writeOffset = (off_t)fOffset << PAGE_SHIFT;
size_t writeLength = fPageCount << PAGE_SHIFT; size_t writeLength = fPageCount << PAGE_SHIFT;
iovec vecs[1];
vecs->iov_base = (void*)(addr_t)(fPhysicalPageNumber << PAGE_SHIFT);
vecs->iov_len = writeLength;
if (fRun != NULL) { if (fRun != NULL) {
return fCache->WriteAsync(writeOffset, vecs, 1, writeLength, return fCache->WriteAsync(writeOffset, fVecs, fVecCount, writeLength,
flags | B_PHYSICAL_IO_REQUEST, this); flags | B_PHYSICAL_IO_REQUEST, this);
} }
status_t status = fCache->Write(writeOffset, vecs, 1, status_t status = fCache->Write(writeOffset, fVecs, fVecCount,
flags | B_PHYSICAL_IO_REQUEST, &writeLength); flags | B_PHYSICAL_IO_REQUEST, &writeLength);
SetStatus(status, writeLength); SetStatus(status, writeLength);
@@ -2202,6 +2232,7 @@ vm_page_allocate_page_run(int pageState, addr_t base, addr_t length)
break; break;
} }
} }
if (foundRun) { if (foundRun) {
// pull the pages out of the appropriate queues // pull the pages out of the appropriate queues
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
@@ -2210,11 +2241,11 @@ vm_page_allocate_page_run(int pageState, addr_t base, addr_t length)
set_page_state_nolock(&sPages[start + i], PAGE_STATE_BUSY); set_page_state_nolock(&sPages[start + i], PAGE_STATE_BUSY);
sPages[start + i].usage_count = 2; sPages[start + i].usage_count = 2;
} }
firstPage = &sPages[start]; firstPage = &sPages[start];
break; break;
} else { } else
start += i; start += i;
}
} }
T(AllocatePageRun(length)); T(AllocatePageRun(length));