Stefan Kempf wrote:
> Stuart Henderson wrote:
> > On 2016/03/09 20:49, Stefan Kempf wrote:
> > > Here's a diff that allocates the most commonly used amap slot sizes
> > > (between 1 and 16) using pool_get(9) instead of malloc(9). That should
> > > reduce the pressure on kernel virtual address space somewhat (on amd64
> > > at least),
> > 
> > Thanks for the useful information and diff.
> > 
> > I'm running a full ports build on i386 now with this in the kernel,
> > and will run some more of my memory-hungry jobs on amd64 tomorrow.
>  
> I looked at the diff again and unfortunately there is a bug in the
> first version. slotalloc was computed incorrectly in amap_extend()
> when using pool(9).
> 
> That code path seems to not be executed often though
> and can only be triggered with certain allocation sizes (maybe the
> i386 ports build survives even with the first diff).
> 
> But please try the one below on amd64 if possible.

There's still at least one issue with the diff. Again in amap_extend().
The slotalloc computation was still off :-(

Index: uvm/uvm_amap.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_amap.c,v
retrieving revision 1.60
diff -u -p -r1.60 uvm_amap.c
--- uvm/uvm_amap.c      6 Mar 2016 14:47:07 -0000       1.60
+++ uvm/uvm_amap.c      10 Mar 2016 18:15:17 -0000
@@ -52,8 +52,13 @@
 
 struct pool uvm_amap_pool;
 
+/* Pools for amap slots for the most common amap slot sizes */
+struct pool uvm_amap_slot_pools[UVM_AMAP_CHUNK];
+
 LIST_HEAD(, vm_amap) amap_list;
 
+static char amap_slot_pool_names[UVM_AMAP_CHUNK][13];
+
 #define MALLOC_SLOT_UNIT (2 * sizeof(int) + sizeof(struct vm_anon *))
 
 /*
@@ -151,10 +156,20 @@ pp_setreflen(int *ppref, int offset, int
 void
 amap_init(void)
 {
+       int i;
+
        /* Initialize the vm_amap pool. */
        pool_init(&uvm_amap_pool, sizeof(struct vm_amap), 0, 0, PR_WAITOK,
            "amappl", NULL);
        pool_sethiwat(&uvm_amap_pool, 4096);
+
+       for (i = 0; i < nitems(uvm_amap_slot_pools); i++) {
+               snprintf(amap_slot_pool_names[i],
+                   sizeof(amap_slot_pool_names[0]), "amapslotpl%d", i + 1);
+               pool_init(&uvm_amap_slot_pools[i], (i + 1) * MALLOC_SLOT_UNIT,
+                   0, 0, PR_WAITOK, amap_slot_pool_names[i], NULL);
+               pool_sethiwat(&uvm_amap_slot_pools[i], 4096);
+       }
 }
 
 /*
@@ -172,8 +187,13 @@ amap_alloc1(int slots, int padslots, int
        if (amap == NULL)
                return(NULL);
 
-       totalslots = malloc_roundup((slots + padslots) * MALLOC_SLOT_UNIT) /
-           MALLOC_SLOT_UNIT;
+       totalslots = slots + padslots;
+       KASSERT(totalslots > 0);
+
+       if (totalslots > UVM_AMAP_CHUNK)
+               totalslots = malloc_roundup(totalslots * MALLOC_SLOT_UNIT) /
+                   MALLOC_SLOT_UNIT;
+
        amap->am_ref = 1;
        amap->am_flags = 0;
 #ifdef UVM_AMAP_PPREF
@@ -183,8 +203,14 @@ amap_alloc1(int slots, int padslots, int
        amap->am_nslot = slots;
        amap->am_nused = 0;
 
-       amap->am_slots = malloc(totalslots * MALLOC_SLOT_UNIT, M_UVMAMAP,
-           waitf);
+       if (totalslots > UVM_AMAP_CHUNK)
+               amap->am_slots = malloc(totalslots * MALLOC_SLOT_UNIT,
+                   M_UVMAMAP, waitf);
+       else
+               amap->am_slots = pool_get(
+                   &uvm_amap_slot_pools[totalslots - 1],
+                   (waitf == M_WAITOK) ? PR_WAITOK : PR_NOWAIT);
+
        if (amap->am_slots == NULL)
                goto fail1;
 
@@ -238,7 +264,12 @@ amap_free(struct vm_amap *amap)
        KASSERT(amap->am_ref == 0 && amap->am_nused == 0);
        KASSERT((amap->am_flags & AMAP_SWAPOFF) == 0);
 
-       free(amap->am_slots, M_UVMAMAP, 0);
+       if (amap->am_maxslot > UVM_AMAP_CHUNK)
+               free(amap->am_slots, M_UVMAMAP, 0);
+       else
+               pool_put(&uvm_amap_slot_pools[amap->am_maxslot - 1],
+                   amap->am_slots);
+
 #ifdef UVM_AMAP_PPREF
        if (amap->am_ppref && amap->am_ppref != PPREF_NONE)
                free(amap->am_ppref, M_UVMAMAP, 0);
@@ -324,8 +355,12 @@ amap_extend(struct vm_map_entry *entry, 
        if (slotneed >= UVM_AMAP_LARGE)
                return E2BIG;
 
-       slotalloc = malloc_roundup(slotneed * MALLOC_SLOT_UNIT) /
-           MALLOC_SLOT_UNIT;
+       if (slotneed > UVM_AMAP_CHUNK)
+               slotalloc = malloc_roundup(slotneed * MALLOC_SLOT_UNIT) /
+                   MALLOC_SLOT_UNIT;
+       else
+               slotalloc = slotneed;
+
 #ifdef UVM_AMAP_PPREF
        newppref = NULL;
        if (amap->am_ppref && amap->am_ppref != PPREF_NONE) {
@@ -338,8 +373,12 @@ amap_extend(struct vm_map_entry *entry, 
                }
        }
 #endif
-       newsl = malloc(slotalloc * MALLOC_SLOT_UNIT, M_UVMAMAP,
-           M_WAITOK | M_CANFAIL);
+       if (slotneed > UVM_AMAP_CHUNK)
+               newsl = malloc(slotalloc * MALLOC_SLOT_UNIT, M_UVMAMAP,
+                   M_WAITOK | M_CANFAIL);
+       else
+               newsl = pool_get(&uvm_amap_slot_pools[slotalloc - 1],
+                   PR_WAITOK | PR_LIMITFAIL);
        if (newsl == NULL) {
 #ifdef UVM_AMAP_PPREF
                if (newppref != NULL) {
@@ -389,12 +428,17 @@ amap_extend(struct vm_map_entry *entry, 
        }
 #endif
 
-       /* update master values */
+       /* free */
+       if (amap->am_maxslot > UVM_AMAP_CHUNK)
+               free(oldsl, M_UVMAMAP, 0);
+       else
+               pool_put(&uvm_amap_slot_pools[amap->am_maxslot - 1],
+                   oldsl);
+
+       /* and update master values */
        amap->am_nslot = slotneed;
        amap->am_maxslot = slotalloc;
 
-       /* and free */
-       free(oldsl, M_UVMAMAP, 0);
 #ifdef UVM_AMAP_PPREF
        if (oldppref && oldppref != PPREF_NONE)
                free(oldppref, M_UVMAMAP, 0);

Reply via email to