ia64/xen-unstable

changeset 17616:0ac957f9d42e

shadow: drop guest VRAM write access after some idleness

If the video RAM has been kept clean for at least 2 seconds, we can
afford taking the time to drop guest write access, which allows us to
save the dirty bit scanning entirely until we get a guest page handle.

From: Samuel Thibault <samuel.thibault@eu.citrix.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu May 08 13:15:45 2008 +0100 (2008-05-08)
parents fe625fd796f8
children b0d7780794eb
files xen/arch/x86/mm/shadow/common.c xen/arch/x86/mm/shadow/multi.c xen/arch/x86/mm/shadow/private.h
line diff
     1.1 --- a/xen/arch/x86/mm/shadow/common.c	Thu May 08 13:14:27 2008 +0100
     1.2 +++ b/xen/arch/x86/mm/shadow/common.c	Thu May 08 13:15:45 2008 +0100
     1.3 @@ -2869,6 +2869,8 @@ int shadow_track_dirty_vram(struct domai
     1.4      unsigned long end_pfn = begin_pfn + nr;
     1.5      unsigned long dirty_size = (nr + 7) / 8;
     1.6      int flush_tlb = 0;
     1.7 +    unsigned long i;
     1.8 +    p2m_type_t t;
     1.9  
    1.10      if (end_pfn < begin_pfn
    1.11              || begin_pfn > d->arch.p2m->max_mapped_pfn
    1.12 @@ -2879,7 +2881,8 @@ int shadow_track_dirty_vram(struct domai
    1.13  
    1.14      if ( d->dirty_vram && (!nr ||
    1.15               ( begin_pfn != d->dirty_vram->begin_pfn
    1.16 -            || end_pfn   != d->dirty_vram->end_pfn )) ) {
    1.17 +            || end_pfn   != d->dirty_vram->end_pfn )) )
    1.18 +    {
    1.19          /* Different tracking, tear the previous down. */
    1.20          gdprintk(XENLOG_INFO, "stopping tracking VRAM %lx - %lx\n", d->dirty_vram->begin_pfn, d->dirty_vram->end_pfn);
    1.21          xfree(d->dirty_vram->sl1ma);
    1.22 @@ -2888,17 +2891,16 @@ int shadow_track_dirty_vram(struct domai
    1.23          d->dirty_vram = NULL;
    1.24      }
    1.25  
    1.26 -    if ( !nr ) {
    1.27 +    if ( !nr )
    1.28 +    {
    1.29          rc = 0;
    1.30          goto out;
    1.31      }
    1.32  
    1.33      /* This should happen seldomly (Video mode change),
    1.34       * no need to be careful. */
    1.35 -    if ( !d->dirty_vram ) {
    1.36 -        unsigned long i;
    1.37 -        p2m_type_t t;
    1.38 -
    1.39 +    if ( !d->dirty_vram )
    1.40 +    {
    1.41          /* Just recount from start. */
    1.42          for ( i = begin_pfn; i < end_pfn; i++ )
    1.43              flush_tlb |= sh_remove_all_mappings(d->vcpu[0], gfn_to_mfn(d, i, &t));
    1.44 @@ -2919,10 +2921,20 @@ int shadow_track_dirty_vram(struct domai
    1.45              goto out_sl1ma;
    1.46          memset(d->dirty_vram->dirty_bitmap, 0, dirty_size);
    1.47  
    1.48 +        d->dirty_vram->last_dirty = NOW();
    1.49 +
    1.50          /* Tell the caller that this time we could not track dirty bits. */
    1.51          rc = -ENODATA;
    1.52 -    } else {
    1.53 -        int i;
    1.54 +    }
    1.55 +    else if (d->dirty_vram->last_dirty == -1)
    1.56 +    {
    1.57 +        /* still completely clean, just copy our empty bitmap */
    1.58 +        rc = -EFAULT;
    1.59 +        if ( copy_to_guest(dirty_bitmap, d->dirty_vram->dirty_bitmap, dirty_size) == 0 )
    1.60 +            rc = 0;
    1.61 +    }
    1.62 +    else
    1.63 +    {
    1.64  #ifdef __i386__
    1.65          unsigned long map_mfn = INVALID_MFN;
    1.66          void *map_sl1p = NULL;
    1.67 @@ -2930,26 +2942,29 @@ int shadow_track_dirty_vram(struct domai
    1.68  
    1.69          /* Iterate over VRAM to track dirty bits. */
    1.70          for ( i = 0; i < nr; i++ ) {
    1.71 -            p2m_type_t t;
    1.72              mfn_t mfn = gfn_to_mfn(d, begin_pfn + i, &t);
    1.73              struct page_info *page = mfn_to_page(mfn);
    1.74              u32 count_info = page->u.inuse.type_info & PGT_count_mask;
    1.75              int dirty = 0;
    1.76              paddr_t sl1ma = d->dirty_vram->sl1ma[i];
    1.77  
    1.78 -            switch (count_info) {
    1.79 +            switch (count_info)
    1.80 +            {
    1.81              case 0:
    1.82                  /* No guest reference, nothing to track. */
    1.83                  break;
    1.84              case 1:
    1.85                  /* One guest reference. */
    1.86 -                if ( sl1ma == INVALID_PADDR ) {
    1.87 +                if ( sl1ma == INVALID_PADDR )
    1.88 +                {
    1.89                      /* We don't know which sl1e points to this, too bad. */
    1.90                      dirty = 1;
    1.91                      /* TODO: Heuristics for finding the single mapping of
    1.92                       * this gmfn */
    1.93                      flush_tlb |= sh_remove_all_mappings(d->vcpu[0], gfn_to_mfn(d, begin_pfn + i, &t));
    1.94 -                } else {
    1.95 +                }
    1.96 +                else
    1.97 +                {
    1.98                      /* Hopefully the most common case: only one mapping,
    1.99                       * whose dirty bit we can use. */
   1.100                      l1_pgentry_t *sl1e;
   1.101 @@ -2968,7 +2983,8 @@ int shadow_track_dirty_vram(struct domai
   1.102                      sl1e = maddr_to_virt(sl1ma);
   1.103  #endif
   1.104  
   1.105 -                    if ( l1e_get_flags(*sl1e) & _PAGE_DIRTY ) {
   1.106 +                    if ( l1e_get_flags(*sl1e) & _PAGE_DIRTY )
   1.107 +                    {
   1.108                          dirty = 1;
   1.109                          /* Note: this is atomic, so we may clear a
   1.110                           * _PAGE_ACCESSED set by another processor. */
   1.111 @@ -2985,7 +3001,10 @@ int shadow_track_dirty_vram(struct domai
   1.112              }
   1.113  
   1.114              if ( dirty )
   1.115 +            {
   1.116                  d->dirty_vram->dirty_bitmap[i / 8] |= 1 << (i % 8);
   1.117 +                d->dirty_vram->last_dirty = NOW();
   1.118 +            }
   1.119          }
   1.120  
   1.121  #ifdef __i386__
   1.122 @@ -2996,6 +3015,14 @@ int shadow_track_dirty_vram(struct domai
   1.123          rc = -EFAULT;
   1.124          if ( copy_to_guest(dirty_bitmap, d->dirty_vram->dirty_bitmap, dirty_size) == 0 ) {
   1.125              memset(d->dirty_vram->dirty_bitmap, 0, dirty_size);
   1.126 +            if (d->dirty_vram->last_dirty + SECONDS(2) < NOW())
   1.127 +            {
   1.128 +                /* was clean for more than two seconds, try to disable guest
   1.129 +                 * write access */
   1.130 +                for ( i = begin_pfn; i < end_pfn; i++ )
   1.131 +                    flush_tlb |= sh_remove_write_access(d->vcpu[0], gfn_to_mfn(d, i, &t), 1, 0);
   1.132 +                d->dirty_vram->last_dirty = -1;
   1.133 +            }
   1.134              rc = 0;
   1.135          }
   1.136      }
     2.1 --- a/xen/arch/x86/mm/shadow/multi.c	Thu May 08 13:14:27 2008 +0100
     2.2 +++ b/xen/arch/x86/mm/shadow/multi.c	Thu May 08 13:15:45 2008 +0100
     2.3 @@ -870,6 +870,17 @@ static always_inline void
     2.4          }
     2.5      }
     2.6  
     2.7 +    if ( unlikely((level == 1) && d->dirty_vram
     2.8 +            && d->dirty_vram->last_dirty == -1
     2.9 +            && gfn_x(target_gfn) >= d->dirty_vram->begin_pfn
    2.10 +            && gfn_x(target_gfn) < d->dirty_vram->end_pfn) )
    2.11 +    {
    2.12 +        if ( ft & FETCH_TYPE_WRITE )
    2.13 +            d->dirty_vram->last_dirty = NOW();
    2.14 +        else
    2.15 +            sflags &= ~_PAGE_RW;
    2.16 +    }
    2.17 +
    2.18      /* Read-only memory */
    2.19      if ( p2mt == p2m_ram_ro ) 
    2.20          sflags &= ~_PAGE_RW;
    2.21 @@ -1320,8 +1331,10 @@ static inline void shadow_vram_put_l1e(s
    2.22                   * just hope it will remain. */
    2.23              }
    2.24          }
    2.25 -        if ( dirty )
    2.26 +        if ( dirty ) {
    2.27              d->dirty_vram->dirty_bitmap[i / 8] |= 1 << (i % 8);
    2.28 +            d->dirty_vram->last_dirty = NOW();
    2.29 +        }
    2.30      }
    2.31  }
    2.32  
     3.1 --- a/xen/arch/x86/mm/shadow/private.h	Thu May 08 13:14:27 2008 +0100
     3.2 +++ b/xen/arch/x86/mm/shadow/private.h	Thu May 08 13:15:45 2008 +0100
     3.3 @@ -536,6 +536,7 @@ struct sh_dirty_vram {
     3.4      unsigned long end_pfn;
     3.5      paddr_t *sl1ma;
     3.6      uint8_t *dirty_bitmap;
     3.7 +    s_time_t last_dirty;
     3.8  };
     3.9  
    3.10  /**************************************************************************/