Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/kern/subr_pool.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/kern/subr_pool.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.133.4.4 retrieving revision 1.138.4.1 diff -u -p -r1.133.4.4 -r1.138.4.1 --- src/sys/kern/subr_pool.c 2008/02/18 21:06:47 1.133.4.4 +++ src/sys/kern/subr_pool.c 2007/12/13 21:56:54 1.138.4.1 @@ -1,4 +1,4 @@ -/* $NetBSD: subr_pool.c,v 1.133.4.4 2008/02/18 21:06:47 mjf Exp $ */ +/* $NetBSD: subr_pool.c,v 1.138.4.1 2007/12/13 21:56:54 bouyer Exp $ */ /*- * Copyright (c) 1997, 1999, 2000, 2002, 2007 The NetBSD Foundation, Inc. @@ -38,7 +38,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.133.4.4 2008/02/18 21:06:47 mjf Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_pool.c,v 1.138.4.1 2007/12/13 21:56:54 bouyer Exp $"); #include "opt_ddb.h" #include "opt_pool.h" @@ -52,13 +52,13 @@ __KERNEL_RCSID(0, "$NetBSD: subr_pool.c, #include #include #include +#include #include #include #include #include #include #include -#include #include @@ -76,7 +76,11 @@ __KERNEL_RCSID(0, "$NetBSD: subr_pool.c, */ /* List of all pools */ -TAILQ_HEAD(,pool) pool_head = TAILQ_HEAD_INITIALIZER(pool_head); +LIST_HEAD(,pool) pool_head = LIST_HEAD_INITIALIZER(pool_head); + +/* List of all caches. */ +LIST_HEAD(,pool_cache) pool_cache_head = + LIST_HEAD_INITIALIZER(pool_cache_head); /* Private pool for page header structures */ #define PHPOOL_MAX 8 @@ -122,7 +126,7 @@ struct pool_item_header { SPLAY_ENTRY(pool_item_header) ph_node; /* Off-page page headers */ void * ph_page; /* this page's address */ - uint32_t ph_time; /* last referenced */ + struct timeval ph_time; /* last referenced */ uint16_t ph_nmissing; /* # of chunks in use */ uint16_t ph_off; /* start offset in page */ union { @@ -177,18 +181,10 @@ struct pool_item { * from it. */ -static struct pool pcg_normal_pool; -static struct pool pcg_large_pool; +static struct pool pcgpool; static struct pool cache_pool; static struct pool cache_cpu_pool; -/* List of all caches. */ -TAILQ_HEAD(,pool_cache) pool_cache_head = - TAILQ_HEAD_INITIALIZER(pool_cache_head); - -int pool_cache_disable; - - static pool_cache_cpu_t *pool_cache_put_slow(pool_cache_cpu_t *, int *, void *, paddr_t); static pool_cache_cpu_t *pool_cache_get_slow(pool_cache_cpu_t *, int *, @@ -629,7 +625,9 @@ void pool_init(struct pool *pp, size_t size, u_int align, u_int ioff, int flags, const char *wchan, struct pool_allocator *palloc, int ipl) { +#ifdef DEBUG struct pool *pp1; +#endif size_t trysize, phsize; int off, slack; @@ -638,7 +636,7 @@ pool_init(struct pool *pp, size_t size, * Check that the pool hasn't already been initialised and * added to the list of all pools. */ - TAILQ_FOREACH(pp1, &pool_head, pr_poollist) { + LIST_FOREACH(pp1, &pool_head, pr_poollist) { if (pp == pp1) panic("pool_init: pool %s already initialised", wchan); @@ -852,38 +850,24 @@ pool_init(struct pool *pp, size_t size, pool_init(&psppool, POOL_SUBPAGE, POOL_SUBPAGE, 0, PR_RECURSIVE, "psppool", &pool_allocator_meta, IPL_VM); #endif - - size = sizeof(pcg_t) + - (PCG_NOBJECTS_NORMAL - 1) * sizeof(pcgpair_t); - pool_init(&pcg_normal_pool, size, CACHE_LINE_SIZE, 0, 0, - "pcgnormal", &pool_allocator_meta, IPL_VM); - - size = sizeof(pcg_t) + - (PCG_NOBJECTS_LARGE - 1) * sizeof(pcgpair_t); - pool_init(&pcg_large_pool, size, CACHE_LINE_SIZE, 0, 0, - "pcglarge", &pool_allocator_meta, IPL_VM); + pool_init(&pcgpool, sizeof(pcg_t), CACHE_LINE_SIZE, 0, 0, + "cachegrp", &pool_allocator_meta, IPL_VM); } - /* Insert into the list of all pools. */ - if (__predict_true(!cold)) + if (__predict_true(!cold)) { + /* Insert into the list of all pools. */ mutex_enter(&pool_head_lock); - TAILQ_FOREACH(pp1, &pool_head, pr_poollist) { - if (strcmp(pp1->pr_wchan, pp->pr_wchan) > 0) - break; - } - if (pp1 == NULL) - TAILQ_INSERT_TAIL(&pool_head, pp, pr_poollist); - else - TAILQ_INSERT_BEFORE(pp1, pp, pr_poollist); - if (__predict_true(!cold)) + LIST_INSERT_HEAD(&pool_head, pp, pr_poollist); mutex_exit(&pool_head_lock); /* Insert this into the list of pools using this allocator. */ - if (__predict_true(!cold)) mutex_enter(&palloc->pa_lock); - TAILQ_INSERT_TAIL(&palloc->pa_list, pp, pr_alloc_list); - if (__predict_true(!cold)) + TAILQ_INSERT_TAIL(&palloc->pa_list, pp, pr_alloc_list); mutex_exit(&palloc->pa_lock); + } else { + LIST_INSERT_HEAD(&pool_head, pp, pr_poollist); + TAILQ_INSERT_TAIL(&palloc->pa_list, pp, pr_alloc_list); + } pool_reclaim_register(pp); } @@ -901,7 +885,7 @@ pool_destroy(struct pool *pp) mutex_enter(&pool_head_lock); while (pp->pr_refcnt != 0) cv_wait(&pool_busy, &pool_head_lock); - TAILQ_REMOVE(&pool_head, pp, pr_poollist); + LIST_REMOVE(pp, pr_poollist); if (drainpp == pp) drainpp = NULL; mutex_exit(&pool_head_lock); @@ -1300,11 +1284,8 @@ pool_do_put(struct pool *pp, void *v, st * be idle for some period of time before it can * be reclaimed by the pagedaemon. This minimizes * ping-pong'ing for memory. - * - * note for 64-bit time_t: truncating to 32-bit is not - * a problem for our usage. */ - ph->ph_time = time_uptime; + getmicrotime(&ph->ph_time); } pool_update_curpage(pp); } @@ -1456,7 +1437,7 @@ pool_prime_page(struct pool *pp, void *s LIST_INIT(&ph->ph_itemlist); ph->ph_page = storage; ph->ph_nmissing = 0; - ph->ph_time = time_uptime; + getmicrotime(&ph->ph_time); if ((pp->pr_roflags & PR_PHINPAGE) == 0) SPLAY_INSERT(phtree, &pp->pr_phtree, ph); @@ -1617,7 +1598,7 @@ pool_reclaim(struct pool *pp) { struct pool_item_header *ph, *phnext; struct pool_pagelist pq; - uint32_t curtime; + struct timeval curtime, diff; bool klock; int rv; @@ -1654,7 +1635,7 @@ pool_reclaim(struct pool *pp) LIST_INIT(&pq); - curtime = time_uptime; + getmicrotime(&curtime); for (ph = LIST_FIRST(&pp->pr_emptypages); ph != NULL; ph = phnext) { phnext = LIST_NEXT(ph, ph_pagelist); @@ -1664,7 +1645,8 @@ pool_reclaim(struct pool *pp) break; KASSERT(ph->ph_nmissing == 0); - if (curtime - ph->ph_time < pool_inactive_time + timersub(&curtime, &ph->ph_time, &diff); + if (diff.tv_sec < pool_inactive_time && !pa_starved_p(pp->pr_alloc)) continue; @@ -1710,7 +1692,7 @@ pool_drain_start(struct pool **ppp, uint { struct pool *pp; - KASSERT(!TAILQ_EMPTY(&pool_head)); + KASSERT(!LIST_EMPTY(&pool_head)); pp = NULL; @@ -1718,11 +1700,11 @@ pool_drain_start(struct pool **ppp, uint mutex_enter(&pool_head_lock); do { if (drainpp == NULL) { - drainpp = TAILQ_FIRST(&pool_head); + drainpp = LIST_FIRST(&pool_head); } if (drainpp != NULL) { pp = drainpp; - drainpp = TAILQ_NEXT(pp, pr_poollist); + drainpp = LIST_NEXT(pp, pr_poollist); } /* * Skip completely idle pools. We depend on at least @@ -1778,7 +1760,7 @@ pool_printall(const char *modif, void (* { struct pool *pp; - TAILQ_FOREACH(pp, &pool_head, pr_poollist) { + LIST_FOREACH(pp, &pool_head, pr_poollist) { pool_printit(pp, modif, pr); } } @@ -1805,8 +1787,10 @@ pool_print_pagelist(struct pool *pp, str #endif LIST_FOREACH(ph, pl, ph_pagelist) { - (*pr)("\t\tpage %p, nmissing %d, time %" PRIu32 "\n", - ph->ph_page, ph->ph_nmissing, ph->ph_time); + (*pr)("\t\tpage %p, nmissing %d, time %lu,%lu\n", + ph->ph_page, ph->ph_nmissing, + (u_long)ph->ph_time.tv_sec, + (u_long)ph->ph_time.tv_usec); #ifdef DIAGNOSTIC if (!(pp->pr_roflags & PR_NOTOUCH)) { LIST_FOREACH(pi, &ph->ph_itemlist, pi_list) { @@ -1893,7 +1877,7 @@ pool_print1(struct pool *pp, const char #define PR_GROUPLIST(pcg) \ (*pr)("\t\tgroup %p: avail %d\n", pcg, pcg->pcg_avail); \ - for (i = 0; i < pcg->pcg_size; i++) { \ + for (i = 0; i < PCG_NOBJECTS; i++) { \ if (pcg->pcg_objects[i].pcgo_pa != \ POOL_PADDR_INVALID) { \ (*pr)("\t\t\t%p, 0x%llx\n", \ @@ -2066,7 +2050,6 @@ pool_cache_bootstrap(pool_cache_t pc, si void *arg) { CPU_INFO_ITERATOR cii; - pool_cache_t pc1; struct cpu_info *ci; struct pool *pp; @@ -2106,12 +2089,6 @@ pool_cache_bootstrap(pool_cache_t pc, si pc->pc_refcnt = 0; pc->pc_freecheck = NULL; - if ((flags & PR_LARGECACHE) != 0) { - pc->pc_pcgsize = PCG_NOBJECTS_LARGE; - } else { - pc->pc_pcgsize = PCG_NOBJECTS_NORMAL; - } - /* Allocate per-CPU caches. */ memset(pc->pc_cpus, 0, sizeof(pc->pc_cpus)); pc->pc_ncpu = 0; @@ -2123,23 +2100,18 @@ pool_cache_bootstrap(pool_cache_t pc, si pool_cache_cpu_init1(ci, pc); } } - - /* Add to list of all pools. */ - if (__predict_true(!cold)) + + if (__predict_true(!cold)) { + mutex_enter(&pp->pr_lock); + pp->pr_cache = pc; + mutex_exit(&pp->pr_lock); mutex_enter(&pool_head_lock); - TAILQ_FOREACH(pc1, &pool_cache_head, pc_cachelist) { - if (strcmp(pc1->pc_pool.pr_wchan, pc->pc_pool.pr_wchan) > 0) - break; - } - if (pc1 == NULL) - TAILQ_INSERT_TAIL(&pool_cache_head, pc, pc_cachelist); - else - TAILQ_INSERT_BEFORE(pc1, pc, pc_cachelist); - if (__predict_true(!cold)) + LIST_INSERT_HEAD(&pool_cache_head, pc, pc_cachelist); mutex_exit(&pool_head_lock); - - membar_sync(); - pp->pr_cache = pc; + } else { + pp->pr_cache = pc; + LIST_INSERT_HEAD(&pool_cache_head, pc, pc_cachelist); + } } /* @@ -2159,7 +2131,7 @@ pool_cache_destroy(pool_cache_t pc) mutex_enter(&pool_head_lock); while (pc->pc_refcnt != 0) cv_wait(&pool_busy, &pool_head_lock); - TAILQ_REMOVE(&pool_cache_head, pc, pc_cachelist); + LIST_REMOVE(pc, pc_cachelist); mutex_exit(&pool_head_lock); /* First, invalidate the entire cache. */ @@ -2250,7 +2222,7 @@ pool_cache_cpu_init(struct cpu_info *ci) pool_cache_t pc; mutex_enter(&pool_head_lock); - TAILQ_FOREACH(pc, &pool_cache_head, pc_cachelist) { + LIST_FOREACH(pc, &pool_cache_head, pc_cachelist) { pc->pc_refcnt++; mutex_exit(&pool_head_lock); @@ -2318,12 +2290,7 @@ pool_cache_invalidate_groups(pool_cache_ pool_cache_destruct_object1(pc, object); } - if (pcg->pcg_size == PCG_NOBJECTS_LARGE) { - pool_put(&pcg_large_pool, pcg); - } else { - KASSERT(pcg->pcg_size == PCG_NOBJECTS_NORMAL); - pool_put(&pcg_normal_pool, pcg); - } + pool_put(&pcgpool, pcg); } } @@ -2463,7 +2430,7 @@ pool_cache_get_slow(pool_cache_cpu_t *cc pc->pc_emptygroups = cur; pc->pc_nempty++; } - KASSERT(pcg->pcg_avail == pcg->pcg_size); + KASSERT(pcg->pcg_avail == PCG_NOBJECTS); cc->cc_current = pcg; pc->pc_fullgroups = pcg->pcg_next; pc->pc_hits++; @@ -2534,10 +2501,8 @@ pool_cache_get_paddr(pool_cache_t pc, in object = pcg->pcg_objects[--pcg->pcg_avail].pcgo_va; if (pap != NULL) *pap = pcg->pcg_objects[pcg->pcg_avail].pcgo_pa; -#if defined(DIAGNOSTIC) pcg->pcg_objects[pcg->pcg_avail].pcgo_va = NULL; -#endif /* defined(DIAGNOSTIC) */ - KASSERT(pcg->pcg_avail <= pcg->pcg_size); + KASSERT(pcg->pcg_avail <= PCG_NOBJECTS); KASSERT(object != NULL); cc->cc_hits++; pool_cache_cpu_exit(cc, &s); @@ -2577,7 +2542,6 @@ pool_cache_put_slow(pool_cache_cpu_t *cc pcg_t *pcg, *cur; uint64_t ncsw; pool_cache_t pc; - u_int nobj; pc = cc->cc_cache; cc->cc_misses++; @@ -2607,21 +2571,17 @@ pool_cache_put_slow(pool_cache_cpu_t *cc /* * If there's a empty group, release our full * group back to the cache. Install the empty - * group and return. + * group as cc_current and return. */ + if ((cur = cc->cc_current) != NULL) { + KASSERT(cur->pcg_avail == PCG_NOBJECTS); + cur->pcg_next = pc->pc_fullgroups; + pc->pc_fullgroups = cur; + pc->pc_nfull++; + } KASSERT(pcg->pcg_avail == 0); + cc->cc_current = pcg; pc->pc_emptygroups = pcg->pcg_next; - if (cc->cc_previous == NULL) { - cc->cc_previous = pcg; - } else { - if ((cur = cc->cc_current) != NULL) { - KASSERT(cur->pcg_avail == pcg->pcg_size); - cur->pcg_next = pc->pc_fullgroups; - pc->pc_fullgroups = cur; - pc->pc_nfull++; - } - cc->cc_current = pcg; - } pc->pc_hits++; pc->pc_nempty--; mutex_exit(&pc->pc_lock); @@ -2641,20 +2601,16 @@ pool_cache_put_slow(pool_cache_cpu_t *cc * If we can't allocate a new group, just throw the * object away. */ - nobj = pc->pc_pcgsize; - if (pool_cache_disable) { - pcg = NULL; - } else if (nobj == PCG_NOBJECTS_LARGE) { - pcg = pool_get(&pcg_large_pool, PR_NOWAIT); - } else { - pcg = pool_get(&pcg_normal_pool, PR_NOWAIT); - } + pcg = pool_get(&pcgpool, PR_NOWAIT); if (pcg == NULL) { pool_cache_destruct_object(pc, object); return NULL; } +#ifdef DIAGNOSTIC + memset(pcg, 0, sizeof(*pcg)); +#else pcg->pcg_avail = 0; - pcg->pcg_size = nobj; +#endif /* * Add the empty group to the cache and try again. @@ -2687,7 +2643,9 @@ pool_cache_put_paddr(pool_cache_t pc, vo do { /* If the current group isn't full, release it there. */ pcg = cc->cc_current; - if (pcg != NULL && pcg->pcg_avail < pcg->pcg_size) { + if (pcg != NULL && pcg->pcg_avail < PCG_NOBJECTS) { + KASSERT(pcg->pcg_objects[pcg->pcg_avail].pcgo_va + == NULL); pcg->pcg_objects[pcg->pcg_avail].pcgo_va = object; pcg->pcg_objects[pcg->pcg_avail].pcgo_pa = pa; pcg->pcg_avail++; @@ -2745,7 +2703,7 @@ pool_cache_xcall(pool_cache_t pc) s = splvm(); mutex_enter(&pc->pc_lock); if (cur != NULL) { - if (cur->pcg_avail == cur->pcg_size) { + if (cur->pcg_avail == PCG_NOBJECTS) { list = &pc->pc_fullgroups; pc->pc_nfull++; } else if (cur->pcg_avail == 0) { @@ -2759,7 +2717,7 @@ pool_cache_xcall(pool_cache_t pc) *list = cur; } if (prev != NULL) { - if (prev->pcg_avail == prev->pcg_size) { + if (prev->pcg_avail == PCG_NOBJECTS) { list = &pc->pc_fullgroups; pc->pc_nfull++; } else if (prev->pcg_avail == 0) { @@ -2949,64 +2907,14 @@ pool_in_page(struct pool *pp, struct poo addr < (uintptr_t)ph->ph_page + pp->pr_alloc->pa_pagesz; } -static bool -pool_in_item(struct pool *pp, void *item, uintptr_t addr) -{ - - return (uintptr_t)item <= addr && addr < (uintptr_t)item + pp->pr_size; -} - -static bool -pool_in_cg(struct pool *pp, struct pool_cache_group *pcg, uintptr_t addr) -{ - int i; - - if (pcg == NULL) { - return false; - } - for (i = 0; i < pcg->pcg_avail; i++) { - if (pool_in_item(pp, pcg->pcg_objects[i].pcgo_va, addr)) { - return true; - } - } - return false; -} - -static bool -pool_allocated(struct pool *pp, struct pool_item_header *ph, uintptr_t addr) -{ - - if ((pp->pr_roflags & PR_NOTOUCH) != 0) { - unsigned int idx = pr_item_notouch_index(pp, ph, (void *)addr); - pool_item_bitmap_t *bitmap = - ph->ph_bitmap + (idx / BITMAP_SIZE); - pool_item_bitmap_t mask = 1 << (idx & BITMAP_MASK); - - return (*bitmap & mask) == 0; - } else { - struct pool_item *pi; - - LIST_FOREACH(pi, &ph->ph_itemlist, pi_list) { - if (pool_in_item(pp, pi, addr)) { - return false; - } - } - return true; - } -} - void pool_whatis(uintptr_t addr, void (*pr)(const char *, ...)) { struct pool *pp; - TAILQ_FOREACH(pp, &pool_head, pr_poollist) { + LIST_FOREACH(pp, &pool_head, pr_poollist) { struct pool_item_header *ph; uintptr_t item; - bool allocated = true; - bool incache = false; - bool incpucache = false; - char cpucachestr[32]; if ((pp->pr_roflags & PR_PHINPAGE) != 0) { LIST_FOREACH(ph, &pp->pr_fullpages, ph_pagelist) { @@ -3016,14 +2924,6 @@ pool_whatis(uintptr_t addr, void (*pr)(c } LIST_FOREACH(ph, &pp->pr_partpages, ph_pagelist) { if (pool_in_page(pp, ph, addr)) { - allocated = - pool_allocated(pp, ph, addr); - goto found; - } - } - LIST_FOREACH(ph, &pp->pr_emptypages, ph_pagelist) { - if (pool_in_page(pp, ph, addr)) { - allocated = false; goto found; } } @@ -3033,49 +2933,13 @@ pool_whatis(uintptr_t addr, void (*pr)(c if (ph == NULL || !pool_in_page(pp, ph, addr)) { continue; } - allocated = pool_allocated(pp, ph, addr); } found: - if (allocated && pp->pr_cache) { - pool_cache_t pc = pp->pr_cache; - struct pool_cache_group *pcg; - int i; - - for (pcg = pc->pc_fullgroups; pcg != NULL; - pcg = pcg->pcg_next) { - if (pool_in_cg(pp, pcg, addr)) { - incache = true; - goto print; - } - } - for (i = 0; i < MAXCPUS; i++) { - pool_cache_cpu_t *cc; - - if ((cc = pc->pc_cpus[i]) == NULL) { - continue; - } - if (pool_in_cg(pp, cc->cc_current, addr) || - pool_in_cg(pp, cc->cc_previous, addr)) { - struct cpu_info *ci = - cpu_lookup_byindex(i); - - incpucache = true; - snprintf(cpucachestr, - sizeof(cpucachestr), - "cached by CPU %u", - (u_int)ci->ci_cpuid); - goto print; - } - } - } -print: item = (uintptr_t)ph->ph_page + ph->ph_off; item = item + rounddown(addr - item, pp->pr_size); - (*pr)("%p is %p+%zu in POOL '%s' (%s)\n", + (*pr)("%p is %p+%zu from POOL '%s'\n", (void *)addr, item, (size_t)(addr - item), - pp->pr_wchan, - incpucache ? cpucachestr : - incache ? "cached" : allocated ? "allocated" : "free"); + pp->pr_wchan); } } #endif /* defined(DDB) */