Subject: amap_extend does unnecessary malloc/memcpy.
To: None <tech-kern@netbsd.org>
From: enami tsugutomo <enami@but-b.or.jp>
List: tech-kern
Date: 11/17/2001 00:12:22
Hi.

I recently found amap_extend does unnecessary malloc and memcpy.  Here
is a chagnes to allocate optimal size when extending amap with
assuming some malloc implementation and sizeof(int) and
sizeof(pointer).

Do you see any problem with this change?

Here is some benchmark; a time to build my kernel with
normal kernel:
      382.95 real       303.87 user        39.98 sys
      382.50 real       304.45 user        40.32 sys
      382.52 real       303.79 user        39.78 sys
patched kernel:
      370.48 real       298.90 user        33.52 sys
      371.88 real       297.05 user        34.53 sys
      370.66 real       299.46 user        32.58 sys

# we probably can't use realloc here since we don't want to copy
# vectors without locking.
enami.

Index: uvm_amap.c
===================================================================
RCS file: /h/cvsroot/syssrc/sys/uvm/uvm_amap.c,v
retrieving revision 1.37
diff -u -r1.37 uvm_amap.c
--- uvm_amap.c	2001/11/10 07:36:59	1.37
+++ uvm_amap.c	2001/11/16 09:25:24
@@ -291,13 +291,13 @@
 {
 	struct vm_amap *amap = entry->aref.ar_amap;
 	int slotoff = entry->aref.ar_pageoff;
-	int slotmapped, slotadd, slotneed;
+	int slotmapped, slotadd, slotneed, slotadded, slotalloc;
 #ifdef UVM_AMAP_PPREF
 	int *newppref, *oldppref;
 #endif
 	int *newsl, *newbck, *oldsl, *oldbck;
 	struct vm_anon **newover, **oldover;
-	int slotadded;
+	size_t size;
 	UVMHIST_FUNC("amap_extend"); UVMHIST_CALLED(maphist);
 
 	UVMHIST_LOG(maphist, "  (entry=0x%x, addsize=0x%x)", entry,addsize,0,0);
@@ -366,10 +366,16 @@
 	 */
 
 	amap_unlock(amap);	/* unlock in case we sleep in malloc */
+	size = slotneed * sizeof(int);
+	if (size <= MAXALLOCSAVE)
+		slotalloc = (1 << BUCKETINDX(size)) / sizeof(int);
+	else
+		slotalloc = roundup(size, PAGE_SIZE) / sizeof(int);
 #ifdef UVM_AMAP_PPREF
 	newppref = NULL;
 	if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
-		newppref = malloc(slotneed * sizeof(int), M_UVMAMAP, M_NOWAIT);
+		newppref = malloc(slotalloc * sizeof(int), M_UVMAMAP,
+		    M_NOWAIT);
 		if (newppref == NULL) {
 			/* give up if malloc fails */
 			free(amap->am_ppref, M_UVMAMAP);
@@ -377,9 +383,9 @@
 		}
 	}
 #endif
-	newsl = malloc(slotneed * sizeof(int), M_UVMAMAP, M_WAITOK);
-	newbck = malloc(slotneed * sizeof(int), M_UVMAMAP, M_WAITOK);
-	newover = malloc(slotneed * sizeof(struct vm_anon *),
+	newsl = malloc(slotalloc * sizeof(int), M_UVMAMAP, M_WAITOK);
+	newbck = malloc(slotalloc * sizeof(int), M_UVMAMAP, M_WAITOK);
+	newover = malloc(slotalloc * sizeof(struct vm_anon *),
 	    M_UVMAMAP, M_WAITOK);
 	amap_lock(amap);			/* re-lock! */
 	KASSERT(amap->am_maxslot < slotneed);
@@ -388,7 +394,7 @@
 	 * now copy everything over to new malloc'd areas...
 	 */
 
-	slotadded = slotneed - amap->am_nslot;
+	slotadded = slotalloc - amap->am_nslot;
 
 	/* do am_slots */
 	oldsl = amap->am_slots;
@@ -417,13 +423,14 @@
 		if ((slotoff + slotmapped) < amap->am_nslot)
 			amap_pp_adjref(amap, slotoff + slotmapped,
 			    (amap->am_nslot - (slotoff + slotmapped)), 1);
-		pp_setreflen(newppref, amap->am_nslot, 1, slotadded);
+		pp_setreflen(newppref, amap->am_nslot, 1,
+		    slotneed - amap->am_nslot);
 	}
 #endif
 
 	/* update master values */
 	amap->am_nslot = slotneed;
-	amap->am_maxslot = slotneed;
+	amap->am_maxslot = slotalloc;
 
 	amap_unlock(amap);
 	free(oldsl, M_UVMAMAP);