dio: don't zero out the pages array inside struct dio
Intel reported a performance regression caused by the following commit: commit848c4dd515
Author: Zach Brown <zach.brown@oracle.com> Date: Mon Aug 20 17:12:01 2007 -0700 dio: zero struct dio with kzalloc instead of manually This patch uses kzalloc to zero all of struct dio rather than manually trying to track which fields we rely on being zero. It passed aio+dio stress testing and some bug regression testing on ext3. This patch was introduced by Linus in the conversation that lead up to Badari's minimal fix to manually zero .map_bh.b_state in commit:6a648fa721
It makes the code a bit smaller. Maybe a couple fewer cachelines to load, if we're lucky: text data bss dec hex filename 3285925 568506 13046165159047
4eb887 vmlinux 3285797 568506 1304616 5158919 4eb807 vmlinux.patched I was unable to measure a stable difference in the number of cpu cycles spent in blockdev_direct_IO() when pushing aio+dio 256K reads at ~340MB/s. So the resulting intent of the patch isn't a performance gain but to avoid exposing ourselves to the risk of finding another field like .map_bh.b_state where we rely on zeroing but don't enforce it in the code. Zach surmised that zeroing out the page array was what caused most of the problem, and suggested the approach taken in the attached patch for resolving the issue. Intel re-tested with this patch and saw a 0.6% performance gain (the original regression was 0.5%). [akpm@linux-foundation.org: add comment] Signed-off-by: Jeff Moyer <jmoyer@redhat.com> Acked-by: Zach Brown <zach.brown@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
fac046ad0b
commit
23aee091d8
|
@ -104,22 +104,6 @@ struct dio {
|
|||
unsigned cur_page_len; /* Nr of bytes at cur_page_offset */
|
||||
sector_t cur_page_block; /* Where it starts */
|
||||
|
||||
/*
|
||||
* Page fetching state. These variables belong to dio_refill_pages().
|
||||
*/
|
||||
int curr_page; /* changes */
|
||||
int total_pages; /* doesn't change */
|
||||
unsigned long curr_user_address;/* changes */
|
||||
|
||||
/*
|
||||
* Page queue. These variables belong to dio_refill_pages() and
|
||||
* dio_get_page().
|
||||
*/
|
||||
struct page *pages[DIO_PAGES]; /* page buffer */
|
||||
unsigned head; /* next page to process */
|
||||
unsigned tail; /* last valid page + 1 */
|
||||
int page_errors; /* errno from get_user_pages() */
|
||||
|
||||
/* BIO completion state */
|
||||
spinlock_t bio_lock; /* protects BIO fields below */
|
||||
unsigned long refcount; /* direct_io_worker() and bios */
|
||||
|
@ -131,6 +115,28 @@ struct dio {
|
|||
int is_async; /* is IO async ? */
|
||||
int io_error; /* IO error in completion path */
|
||||
ssize_t result; /* IO result */
|
||||
|
||||
/*
|
||||
* Page fetching state. These variables belong to dio_refill_pages().
|
||||
*/
|
||||
int curr_page; /* changes */
|
||||
int total_pages; /* doesn't change */
|
||||
unsigned long curr_user_address;/* changes */
|
||||
|
||||
/*
|
||||
* Page queue. These variables belong to dio_refill_pages() and
|
||||
* dio_get_page().
|
||||
*/
|
||||
unsigned head; /* next page to process */
|
||||
unsigned tail; /* last valid page + 1 */
|
||||
int page_errors; /* errno from get_user_pages() */
|
||||
|
||||
/*
|
||||
* pages[] (and any fields placed after it) are not zeroed out at
|
||||
* allocation time. Don't add new fields after pages[] unless you
|
||||
* wish that they not be zeroed.
|
||||
*/
|
||||
struct page *pages[DIO_PAGES]; /* page buffer */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1151,10 +1157,16 @@ __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
|
|||
}
|
||||
}
|
||||
|
||||
dio = kzalloc(sizeof(*dio), GFP_KERNEL);
|
||||
dio = kmalloc(sizeof(*dio), GFP_KERNEL);
|
||||
retval = -ENOMEM;
|
||||
if (!dio)
|
||||
goto out;
|
||||
/*
|
||||
* Believe it or not, zeroing out the page array caused a .5%
|
||||
* performance regression in a database benchmark. So, we take
|
||||
* care to only zero out what's needed.
|
||||
*/
|
||||
memset(dio, 0, offsetof(struct dio, pages));
|
||||
|
||||
/*
|
||||
* For block device access DIO_NO_LOCKING is used,
|
||||
|
|
Loading…
Reference in New Issue