Port-amd64 archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: reduce size of pv_pte
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 04/26/11 00:40, YAMAMOTO Takashi wrote:
> hi,
>
> the following patch reduces the size of pv_pte, thus pv_entry and vm_page.
> comments?
>
> YAMAMOTO Takashi
>
Hi, that's interesting. It is cutting a pv_entry from 40 bytes down to
32 bytes for 64 bit.
I've a concern about the runtime requirements because of the
PHYS_TO_VM_PAGE lookup which might be significant.
Do all amd64 machines have only a few physical memory segments?
Lars
> Index: include/pmap_pv.h
> ===================================================================
> RCS file: /cvsroot/src/sys/arch/x86/include/pmap_pv.h,v
> retrieving revision 1.2
> diff -u -p -r1.2 pmap_pv.h
> --- include/pmap_pv.h 28 Jan 2008 11:06:42 -0000 1.2
> +++ include/pmap_pv.h 25 Apr 2011 22:35:38 -0000
> @@ -44,9 +44,10 @@ struct vm_page;
> * pv_pte: describe a pte
> */
>
> +typedef paddr_t pvkey_t;
> +
> struct pv_pte {
> - struct vm_page *pte_ptp; /* PTP; NULL for pmap_kernel() */
> - vaddr_t pte_va; /* VA */
> + pvkey_t pte_key;
> };
>
> /*
> Index: x86/pmap.c
> ===================================================================
> RCS file: /cvsroot/src/sys/arch/x86/x86/pmap.c,v
> retrieving revision 1.119
> diff -u -p -r1.119 pmap.c
> --- x86/pmap.c 14 Apr 2011 16:00:21 -0000 1.119
> +++ x86/pmap.c 25 Apr 2011 22:35:38 -0000
> @@ -438,11 +438,127 @@ struct pv_hash_head {
> SLIST_HEAD(, pv_entry) hh_list;
> } pv_hash_heads[PV_HASH_SIZE];
>
> +/*
> + * to save memory, we convert a (ptp, va) tuple to an opaque type, pvkey_t.
> + * pvkey_t is logically a pointer to a pte.
> + */
> +
> +#define PVKEY_KERNEL 1
> +
> +/*
> + * pvkey_decode: decode the (ptp, va) tuple for the given pvkey.
> + */
> +
> +static void
> +pvkey_decode(const pvkey_t key, struct vm_page **ptpp, vaddr_t *vap)
> +{
> + struct vm_page *ptp;
> + vaddr_t va;
> +
> + if ((key & PVKEY_KERNEL) != 0) {
> + ptp = NULL;
> + va = key & ~PVKEY_KERNEL;
> + } else {
> + vaddr_t l2_frame;
> + vaddr_t l1_mask;
> +
> + ptp = PHYS_TO_VM_PAGE(key);
> + l2_frame = ptp->offset / PAGE_SIZE * NBPD_L2;
> + l1_mask = (key & PAGE_MASK) / sizeof(pt_entry_t) * PAGE_SIZE;
> + KASSERT((l2_frame & ~L2_FRAME) == 0);
> + KASSERT((l1_mask & L2_FRAME) == 0);
> + KASSERT((l1_mask & PAGE_MASK) == 0);
> + va = l2_frame + l1_mask;
> + }
> + KASSERT((va & PAGE_MASK) == 0);
> + *vap = va;
> + *ptpp = ptp;
> +}
> +
> +/*
> + * pvkey_encode: generate a pvkey for the given (ptp, va) tuple.
> + */
> +
> +static pvkey_t
> +pvkey_encode(struct vm_page *ptp, vaddr_t va)
> +{
> + pvkey_t key;
> +
> + KASSERT((va & PAGE_MASK) == 0);
> + if (ptp == NULL) {
> + /*
> + * kernel pmap
> + *
> + * use (va | PVKEY_KERNEL) as a key.
> + */
> + KASSERT(va >= VM_MIN_KERNEL_ADDRESS);
> + CTASSERT(sizeof(va) <= sizeof(pvkey_t));
> + key = va | PVKEY_KERNEL;
> + } else {
> + /*
> + * user pmap
> + *
> + * use the physical address of the pte as a key.
> + */
> + const paddr_t ptppa = VM_PAGE_TO_PHYS(ptp);
> +
> + KASSERT(va < VM_MIN_KERNEL_ADDRESS);
> + KASSERT(ptp->offset == ptp_va2o(va, 1));
> + CTASSERT(sizeof(paddr_t) <= sizeof(pvkey_t));
> + key = (pvkey_t)(ptppa + sizeof(pt_entry_t) * pl1_pi(va));
> + KASSERT(key < ptppa + PAGE_SIZE);
> + KASSERT((key & PVKEY_KERNEL) == 0);
> + }
> +#if defined(DEBUG)
> + /*
> + * check if the pvkey is decodable to the original tuple.
> + */
> + {
> + struct vm_page *tptp;
> + vaddr_t tva;
> +
> + pvkey_decode(key, &tptp, &tva);
> + KDASSERT(tptp == ptp);
> + KDASSERT(tva == va);
> + }
> +#endif /* defined(DEBUG) */
> + return key;
> +}
> +
> +/*
> + * pvkey_advance: calculate the pvkey for the next pte.
> + *
> + * basically the faster equivalent of
> + * pvkey_decode(key, &ptp, &va);
> + * pvkey_encode(ptp, va + PAGE_SIZE)
> + *
> + * note that pvkey_advance returns a garbage after crossing a ptp boundary.
> + * it's caller's responsibility not to use the garbage.
> + *
> + * XXX this could be micro-optimized to an uncoditional add if we adjust
> + * the pvkey encoding. is it worth?
> + */
> +
> +static pvkey_t
> +pvkey_advance(const pvkey_t key)
> +{
> + pvkey_t nextkey;
> +
> + if ((key & PVKEY_KERNEL) != 0) {
> + nextkey = key + PAGE_SIZE;
> + } else {
> + nextkey = key + sizeof(pt_entry_t);
> + }
> + return nextkey;
> +}
> +
> static u_int
> -pvhash_hash(struct vm_page *ptp, vaddr_t va)
> +pvhash_hash(const pvkey_t key)
> {
> + const u_int ptppn = key / NBPD_L2;
> + const u_int pfn = key / sizeof(pt_entry_t);
>
> - return (uintptr_t)ptp / sizeof(*ptp) + (va >> PAGE_SHIFT);
> + return ptppn + pfn;
> }
>
> static struct pv_hash_head *
> @@ -460,15 +576,14 @@ pvhash_lock(u_int hash)
> }
>
> static struct pv_entry *
> -pvhash_remove(struct pv_hash_head *hh, struct vm_page *ptp, vaddr_t va)
> +pvhash_remove(struct pv_hash_head *hh, const pvkey_t key)
> {
> struct pv_entry *pve;
> struct pv_entry *prev;
>
> prev = NULL;
> SLIST_FOREACH(pve, &hh->hh_list, pve_hash) {
> - if (pve->pve_pte.pte_ptp == ptp &&
> - pve->pve_pte.pte_va == va) {
> + if (pve->pve_pte.pte_key == key) {
> if (prev != NULL) {
> SLIST_REMOVE_AFTER(prev, pve_hash);
> } else {
> @@ -1779,7 +1894,7 @@ insert_pv(struct pmap_page *pp, struct p
>
> KASSERT(pp_locked(pp));
>
> - hash = pvhash_hash(pve->pve_pte.pte_ptp, pve->pve_pte.pte_va);
> + hash = pvhash_hash(pve->pve_pte.pte_key);
> lock = pvhash_lock(hash);
> hh = pvhash_head(hash);
> mutex_spin_enter(lock);
> @@ -1800,20 +1915,23 @@ static struct pv_entry *
> pmap_enter_pv(struct pmap_page *pp,
> struct pv_entry *pve, /* preallocated pve for us to use */
> struct pv_entry **sparepve,
> - struct vm_page *ptp,
> - vaddr_t va)
> + const pvkey_t key)
> {
> +#if defined(DEBUG)
> + struct vm_page *ptp;
> + vaddr_t va;
>
> - KASSERT(ptp == NULL || ptp->wire_count >= 2);
> - KASSERT(ptp == NULL || ptp->uobject != NULL);
> - KASSERT(ptp == NULL || ptp_va2o(va, 1) == ptp->offset);
> + pvkey_decode(key, &ptp, &va);
> + KDASSERT(ptp == NULL || ptp->wire_count >= 2);
> + KDASSERT(ptp == NULL || ptp->uobject != NULL);
> + KDASSERT(ptp == NULL || ptp_va2o(va, 1) == ptp->offset);
> +#endif /* defined(DEBUG) */
> KASSERT(pp_locked(pp));
>
> if ((pp->pp_flags & PP_EMBEDDED) == 0) {
> if (LIST_EMPTY(&pp->pp_head.pvh_list)) {
> pp->pp_flags |= PP_EMBEDDED;
> - pp->pp_pte.pte_ptp = ptp;
> - pp->pp_pte.pte_va = va;
> + pp->pp_pte.pte_key = key;
>
> return pve;
> }
> @@ -1829,8 +1947,7 @@ pmap_enter_pv(struct pmap_page *pp,
> insert_pv(pp, pve2);
> }
>
> - pve->pve_pte.pte_ptp = ptp;
> - pve->pve_pte.pte_va = va;
> + pve->pve_pte.pte_key = key;
> insert_pv(pp, pve);
>
> return NULL;
> @@ -1845,20 +1962,24 @@ pmap_enter_pv(struct pmap_page *pp,
> */
>
> static struct pv_entry *
> -pmap_remove_pv(struct pmap_page *pp, struct vm_page *ptp, vaddr_t va)
> +pmap_remove_pv(struct pmap_page *pp, const pvkey_t key)
> {
> struct pv_hash_head *hh;
> struct pv_entry *pve;
> kmutex_t *lock;
> u_int hash;
> +#if defined(DEBUG)
> + struct vm_page *ptp;
> + vaddr_t va;
>
> - KASSERT(ptp == NULL || ptp->uobject != NULL);
> - KASSERT(ptp == NULL || ptp_va2o(va, 1) == ptp->offset);
> + pvkey_decode(key, &ptp, &va);
> + KDASSERT(ptp == NULL || ptp->uobject != NULL);
> + KDASSERT(ptp == NULL || ptp_va2o(va, 1) == ptp->offset);
> +#endif /* defined(DEBUG) */
> KASSERT(pp_locked(pp));
>
> if ((pp->pp_flags & PP_EMBEDDED) != 0) {
> - KASSERT(pp->pp_pte.pte_ptp == ptp);
> - KASSERT(pp->pp_pte.pte_va == va);
> + KASSERT(pp->pp_pte.pte_key == key);
>
> pp->pp_flags &= ~PP_EMBEDDED;
> LIST_INIT(&pp->pp_head.pvh_list);
> @@ -1866,11 +1987,11 @@ pmap_remove_pv(struct pmap_page *pp, str
> return NULL;
> }
>
> - hash = pvhash_hash(ptp, va);
> + hash = pvhash_hash(key);
> lock = pvhash_lock(hash);
> hh = pvhash_head(hash);
> mutex_spin_enter(lock);
> - pve = pvhash_remove(hh, ptp, va);
> + pve = pvhash_remove(hh, key);
> mutex_spin_exit(lock);
>
> LIST_REMOVE(pve, pve_list);
> @@ -3203,7 +3341,6 @@ pmap_unmap_pte(void)
> /*
> * pmap_remove_ptes: remove PTEs from a PTP
> *
> - * => must have proper locking on pmap_master_lock
> * => caller must hold pmap's lock
> * => PTP must be mapped into KVA
> * => PTP should be null if pmap == pmap_kernel()
> @@ -3218,9 +3355,13 @@ pmap_remove_ptes(struct pmap *pmap, stru
> struct pv_entry *pve;
> pt_entry_t *pte = (pt_entry_t *) ptpva;
> pt_entry_t opte, xpte = 0;
> + pvkey_t key;
>
> KASSERT(pmap == pmap_kernel() || mutex_owned(&pmap->pm_lock));
> KASSERT(kpreempt_disabled());
> + KASSERT((startva & PAGE_MASK) == 0);
> + KASSERT((endva & PAGE_MASK) == 0);
> + KASSERT((startva & L2_FRAME) == ((endva - 1) & L2_FRAME));
>
> /*
> * note that ptpva points to the PTE that maps startva. this may
> @@ -3231,11 +3372,13 @@ pmap_remove_ptes(struct pmap *pmap, stru
> * to keep track of the number of real PTEs in the PTP).
> */
>
> - for (/*null*/; startva < endva && (ptp == NULL || ptp->wire_count > 1)
> - ; pte++, startva += PAGE_SIZE) {
> + for (key = pvkey_encode(ptp, startva);
> + startva < endva && (ptp == NULL || ptp->wire_count > 1);
> + pte++, startva += PAGE_SIZE, key = pvkey_advance(key)) {
> struct vm_page *pg;
> struct pmap_page *pp;
>
> + KASSERT(pvkey_encode(ptp, startva) == key);
> if (!pmap_valid_entry(*pte))
> continue; /* VA not mapped */
>
> @@ -3282,7 +3425,7 @@ pmap_remove_ptes(struct pmap *pmap, stru
> pp = VM_PAGE_TO_PP(pg);
> pp_lock(pp);
> pp->pp_attrs |= opte;
> - pve = pmap_remove_pv(pp, ptp, startva);
> + pve = pmap_remove_pv(pp, key);
> pp_unlock(pp);
>
> if (pve != NULL) {
> @@ -3300,7 +3443,6 @@ pmap_remove_ptes(struct pmap *pmap, stru
> /*
> * pmap_remove_pte: remove a single PTE from a PTP
> *
> - * => must have proper locking on pmap_master_lock
> * => caller must hold pmap's lock
> * => PTP must be mapped into KVA
> * => PTP should be null if pmap == pmap_kernel()
> @@ -3316,6 +3458,7 @@ pmap_remove_pte(struct pmap *pmap, struc
> struct pv_entry *pve;
> struct vm_page *pg;
> struct pmap_page *pp;
> + paddr_t key;
>
> KASSERT(pmap == pmap_kernel() || mutex_owned(&pmap->pm_lock));
> KASSERT(pmap == pmap_kernel() || kpreempt_disabled());
> @@ -3364,10 +3507,11 @@ pmap_remove_pte(struct pmap *pmap, struc
> #endif
>
> /* sync R/M bits */
> + key = pvkey_encode(ptp, va);
> pp = VM_PAGE_TO_PP(pg);
> pp_lock(pp);
> pp->pp_attrs |= opte;
> - pve = pmap_remove_pv(pp, ptp, va);
> + pve = pmap_remove_pv(pp, key);
> pp_unlock(pp);
>
> if (pve) {
> @@ -3487,6 +3631,8 @@ pmap_remove(struct pmap *pmap, vaddr_t s
> panic("pmap_remove: unmanaged PTP "
> "detected");
> #endif
> + KASSERT(ptp ==
> + pmap_find_ptp(pmap, blkendva - PAGE_SIZE, -1, 1));
> }
> xpte |= pmap_remove_ptes(pmap, ptp,
> (vaddr_t)&ptes[pl1_i(va)], va, blkendva, &pv_tofree);
> @@ -3525,8 +3671,7 @@ pmap_sync_pv(struct pv_pte *pvpte, pt_en
> pt_entry_t npte;
> bool need_shootdown;
>
> - ptp = pvpte->pte_ptp;
> - va = pvpte->pte_va;
> + pvkey_decode(pvpte->pte_key, &ptp, &va);
> KASSERT(ptp == NULL || ptp->uobject != NULL);
> KASSERT(ptp == NULL || ptp_va2o(va, 1) == ptp->offset);
> pmap = ptp_to_pmap(ptp);
> @@ -3615,7 +3760,6 @@ pmap_page_remove(struct vm_page *pg)
> struct pmap_page *pp;
> struct pv_pte *pvpte;
> struct pv_entry *killlist = NULL;
> - struct vm_page *ptp;
> pt_entry_t expect;
> lwp_t *l;
> int count;
> @@ -3631,6 +3775,7 @@ startover:
> struct pmap *pmap;
> struct pv_entry *pve;
> pt_entry_t opte;
> + struct vm_page *ptp;
> vaddr_t va;
> int error;
>
> @@ -3639,7 +3784,7 @@ startover:
> * otherwise the pmap can disappear behind us.
> */
>
> - ptp = pvpte->pte_ptp;
> + pvkey_decode(pvpte->pte_key, &ptp, &va);
> pmap = ptp_to_pmap(ptp);
> if (ptp != NULL) {
> pmap_reference(pmap);
> @@ -3659,8 +3804,7 @@ startover:
> }
>
> pp->pp_attrs |= opte;
> - va = pvpte->pte_va;
> - pve = pmap_remove_pv(pp, ptp, va);
> + pve = pmap_remove_pv(pp, pvpte->pte_key);
> pp_unlock(pp);
>
> /* update the PTP reference count. free if last reference. */
> @@ -3986,6 +4130,7 @@ pmap_enter_ma(struct pmap *pmap, vaddr_t
> int error;
> bool wired = (flags & PMAP_WIRED) != 0;
> struct pmap *pmap2;
> + pvkey_t key;
>
> KASSERT(pmap_initialized);
> KASSERT(curlwp->l_md.md_gc_pmap != pmap);
> @@ -4124,6 +4272,8 @@ pmap_enter_ma(struct pmap *pmap, vaddr_t
> goto same_pa;
> }
>
> + key = pvkey_encode(ptp, va);
> +
> /*
> * if old page is managed, remove pv_entry from its list.
> */
> @@ -4140,7 +4290,7 @@ pmap_enter_ma(struct pmap *pmap, vaddr_t
> old_pp = VM_PAGE_TO_PP(pg);
>
> pp_lock(old_pp);
> - old_pve = pmap_remove_pv(old_pp, ptp, va);
> + old_pve = pmap_remove_pv(old_pp, key);
> old_pp->pp_attrs |= opte;
> pp_unlock(old_pp);
> }
> @@ -4151,7 +4301,7 @@ pmap_enter_ma(struct pmap *pmap, vaddr_t
>
> if (new_pp) {
> pp_lock(new_pp);
> - new_pve = pmap_enter_pv(new_pp, new_pve, &new_pve2, ptp, va);
> + new_pve = pmap_enter_pv(new_pp, new_pve, &new_pve2, key);
> pp_unlock(new_pp);
> }
>
> @@ -4693,6 +4843,7 @@ pmap_update(struct pmap *pmap)
> ptp->flags |= PG_ZERO;
> pp = VM_PAGE_TO_PP(ptp);
> empty_ptps = pp->pp_link;
> + KASSERT((pp->pp_flags & PP_EMBEDDED) == 0);
> LIST_INIT(&pp->pp_head.pvh_list);
> uvm_pagefree(ptp);
> }
>
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iEYEARECAAYFAk3K/tgACgkQcxuYqjT7GRYETACfWbH1nWYgnIJjBc/ucbsbtArN
SzgAn12V24jkJA/qsjxuIxeZgneVx4Ox
=D0Di
-----END PGP SIGNATURE-----
Home |
Main Index |
Thread Index |
Old Index