From 80e89abc73b34fc5e6520edc451a9f132bfac576 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Wed, 6 Nov 2013 17:55:06 -0800 Subject: [PATCH] kernel - Remove most buffer_map contention on 64-bit systems * Set BKVASIZE to MAXBSIZE (65536) on 64-bit systems. This has the effect of always reserving a maximal amount of KVM for each buffer cache buffer. * The change removes most buffer_map interactions once the system caches have stabilized. * The change removes the need to defragment the buffer cache. * Significant performance improvement for HAMMER1 and HAMMER2 which use larger buffers and were hitting degenerate fragmentation issues before this change. * But also results in lower buffer data density when buffering data for smaller files, so may have a slight detrimental effect on UFS and on the amount of time dirty data can be cached before being flushed to disk. * NOTE: The 64K limit is for normal buffers and is unrelated to the physical cluster buffer (pbuf) limit of 128KB (MAXPHYS). --- sys/cpu/i386/include/param.h | 11 +++++++++-- sys/cpu/x86_64/include/param.h | 4 ++-- sys/kern/vfs_bio.c | 9 +++++++-- sys/platform/pc64/x86_64/machdep.c | 12 +++++------- sys/sys/param.h | 13 +++++++++---- 5 files changed, 32 insertions(+), 17 deletions(-) diff --git a/sys/cpu/i386/include/param.h b/sys/cpu/i386/include/param.h index d6547ce984..5c0d1b40dd 100644 --- a/sys/cpu/i386/include/param.h +++ b/sys/cpu/i386/include/param.h @@ -124,8 +124,15 @@ #define MAXPHYS (128 * 1024) /* max raw I/O transfer size */ #define MAXDUMPPGS (MAXPHYS/PAGE_SIZE) -#define IOPAGES 2 /* pages of i/o permission bitmap */ -#define UPAGES 4 /* pages of u-area */ +#define IOPAGES 2 /* pages of i/o permission bitmap */ +#define UPAGES 4 /* pages of u-area */ + +/* + * 32-bit machines do not have enough KVA, improve buffer cache + * density at the cost of higher defragmentation and buffer_map + * handling overheads. + */ +#define BKVASIZE 16384 /* override 64K default */ /* * Ceiling on amount of swblock kva space, can be changed via diff --git a/sys/cpu/x86_64/include/param.h b/sys/cpu/x86_64/include/param.h index 15a489dc47..61a0b621c1 100644 --- a/sys/cpu/x86_64/include/param.h +++ b/sys/cpu/x86_64/include/param.h @@ -146,8 +146,8 @@ #define MAXPHYS (128 * 1024) /* max raw I/O transfer size */ #define MAXDUMPPGS (MAXPHYS/PAGE_SIZE) -#define IOPAGES 2 /* pages of i/o permission bitmap */ -#define UPAGES 4 /* pages of u-area */ +#define IOPAGES 2 /* pages of i/o permission bitmap */ +#define UPAGES 4 /* pages of u-area */ /* * Ceiling on amount of swblock kva space, can be changed via diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 3c2e1e21c1..25b1a74f32 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -2141,12 +2141,16 @@ restart: * If we are overcomitted then recover the buffer and its * KVM space. This occurs in rare situations when multiple * processes are blocked in getnewbuf() or allocbuf(). + * + * (We don't have to recover the KVM space if + * BKVASIZE == MAXBSIZE) */ if (bufspace >= hibufspace) flushingbufs = 1; if (flushingbufs && bp->b_kvasize != 0) { bp->b_flags |= B_INVAL; - bfreekva(bp); + if (BKVASIZE != MAXBSIZE) + bfreekva(bp); brelse(bp); goto restart; } @@ -2164,7 +2168,8 @@ restart: */ if (bp->b_refs) { bp->b_flags |= B_INVAL; - bfreekva(bp); + if (BKVASIZE != MAXBSIZE) + bfreekva(bp); brelse(bp); goto restart; } diff --git a/sys/platform/pc64/x86_64/machdep.c b/sys/platform/pc64/x86_64/machdep.c index bd49c2af6d..04e51e6c13 100644 --- a/sys/platform/pc64/x86_64/machdep.c +++ b/sys/platform/pc64/x86_64/machdep.c @@ -390,20 +390,18 @@ again: * * nbuf is an int, make sure we don't overflow the field. * - * On 64-bit systems fragmentation can create serious performance - * loss due to the large number of buffers the system is likely - * going to maintain. The easiest solution is to create a KVA - * section that is twice as big as the nominal buffer cache size, - * hence the multiplication by 2 below. + * On 64-bit systems we always reserve maximal allocations for + * buffer cache buffers and there are no fragmentation issues, + * so the KVA segment does not have to be excessively oversized. */ if ((vm_size_t)(v - firstaddr) != size) panic("startup: table size inconsistency"); kmem_suballoc(&kernel_map, &clean_map, &clean_sva, &clean_eva, - ((vm_offset_t)nbuf * BKVASIZE * 2) + + ((vm_offset_t)(nbuf + 16) * BKVASIZE) + (nswbuf * MAXPHYS) + pager_map_size); kmem_suballoc(&clean_map, &buffer_map, &buffer_sva, &buffer_eva, - ((vm_offset_t)nbuf * BKVASIZE * 2)); + ((vm_offset_t)(nbuf + 16) * BKVASIZE)); buffer_map.system_map = 1; kmem_suballoc(&clean_map, &pager_map, &pager_sva, &pager_eva, ((vm_offset_t)nswbuf * MAXPHYS) + pager_map_size); diff --git a/sys/sys/param.h b/sys/sys/param.h index 148f171f4a..2743508ebc 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -207,11 +207,16 @@ * the KVM memory reserved for the buffer cache and will wind * up with too-few buffers. * - * The default is 16384, roughly 2x the block size used by a - * normal UFS filesystem. + * By default we now use maximally-sized reservations. But on + * 32-bit machines we reduce this 16KB. Maximally-sized + * reservations greatly reduces defragmentation and buffer_map + * messing around and is more SMP-friendly. */ -#define MAXBSIZE 65536 /* must be power of 2 */ -#define BKVASIZE 16384 /* must be power of 2 */ +#define MAXBSIZE 65536 /* must be power of 2 */ +#ifndef BKVASIZE +#define BKVASIZE MAXBSIZE /* must be power of 2 */ +#endif + #define BKVAMASK (BKVASIZE-1) #define MAXFRAG 8 -- 2.41.0