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);