From: Samuel Thibault <samuel.thibault@eu.citrix.com>
To: xen-devel@lists.xensource.com
Cc: tim.deegan@eu.citrix.com, gianluca.guida@eu.citrix.com
Subject: [PATCH] shadow: drop guest VRAM write access after some idleness
Date: Thu, 8 May 2008 12:58:20 +0100 [thread overview]
Message-ID: <20080508115820.GI4365@implementation.uk.xensource.com> (raw)
In-Reply-To: <20080502140509.GF4819@implementation.uk.xensource.com>
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.
diff -r 3bc6ad3beafc -r 98b06d404e6b xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c Fri May 02 14:59:35 2008 +0100
+++ b/xen/arch/x86/mm/shadow/common.c Thu May 08 12:50:34 2008 +0100
@@ -2871,6 +2871,8 @@ int shadow_track_dirty_vram(struct domai
unsigned long end_pfn = begin_pfn + nr;
unsigned long dirty_size = (nr + 7) / 8;
int flush_tlb = 0;
+ unsigned long i;
+ p2m_type_t t;
if (end_pfn < begin_pfn
|| begin_pfn > d->arch.p2m->max_mapped_pfn
@@ -2881,7 +2883,8 @@ int shadow_track_dirty_vram(struct domai
if ( d->dirty_vram && (!nr ||
( begin_pfn != d->dirty_vram->begin_pfn
- || end_pfn != d->dirty_vram->end_pfn )) ) {
+ || end_pfn != d->dirty_vram->end_pfn )) )
+ {
/* Different tracking, tear the previous down. */
gdprintk(XENLOG_INFO, "stopping tracking VRAM %lx - %lx\n", d->dirty_vram->begin_pfn, d->dirty_vram->end_pfn);
xfree(d->dirty_vram->sl1ma);
@@ -2890,17 +2893,16 @@ int shadow_track_dirty_vram(struct domai
d->dirty_vram = NULL;
}
- if ( !nr ) {
+ if ( !nr )
+ {
rc = 0;
goto out;
}
/* This should happen seldomly (Video mode change),
* no need to be careful. */
- if ( !d->dirty_vram ) {
- unsigned long i;
- p2m_type_t t;
-
+ if ( !d->dirty_vram )
+ {
/* Just recount from start. */
for ( i = begin_pfn; i < end_pfn; i++ )
flush_tlb |= sh_remove_all_mappings(d->vcpu[0], gfn_to_mfn(d, i, &t));
@@ -2921,10 +2923,20 @@ int shadow_track_dirty_vram(struct domai
goto out_sl1ma;
memset(d->dirty_vram->dirty_bitmap, 0, dirty_size);
+ d->dirty_vram->last_dirty = NOW();
+
/* Tell the caller that this time we could not track dirty bits. */
rc = -ENODATA;
- } else {
- int i;
+ }
+ else if (d->dirty_vram->last_dirty == -1)
+ {
+ /* still completely clean, just copy our empty bitmap */
+ rc = -EFAULT;
+ if ( copy_to_guest(dirty_bitmap, d->dirty_vram->dirty_bitmap, dirty_size) == 0 )
+ rc = 0;
+ }
+ else
+ {
#ifdef __i386__
unsigned long map_mfn = INVALID_MFN;
void *map_sl1p = NULL;
@@ -2932,26 +2944,29 @@ int shadow_track_dirty_vram(struct domai
/* Iterate over VRAM to track dirty bits. */
for ( i = 0; i < nr; i++ ) {
- p2m_type_t t;
mfn_t mfn = gfn_to_mfn(d, begin_pfn + i, &t);
struct page_info *page = mfn_to_page(mfn);
u32 count_info = page->u.inuse.type_info & PGT_count_mask;
int dirty = 0;
paddr_t sl1ma = d->dirty_vram->sl1ma[i];
- switch (count_info) {
+ switch (count_info)
+ {
case 0:
/* No guest reference, nothing to track. */
break;
case 1:
/* One guest reference. */
- if ( sl1ma == INVALID_PADDR ) {
+ if ( sl1ma == INVALID_PADDR )
+ {
/* We don't know which sl1e points to this, too bad. */
dirty = 1;
/* TODO: Heuristics for finding the single mapping of
* this gmfn */
flush_tlb |= sh_remove_all_mappings(d->vcpu[0], gfn_to_mfn(d, begin_pfn + i, &t));
- } else {
+ }
+ else
+ {
/* Hopefully the most common case: only one mapping,
* whose dirty bit we can use. */
l1_pgentry_t *sl1e;
@@ -2970,7 +2985,8 @@ int shadow_track_dirty_vram(struct domai
sl1e = maddr_to_virt(sl1ma);
#endif
- if ( l1e_get_flags(*sl1e) & _PAGE_DIRTY ) {
+ if ( l1e_get_flags(*sl1e) & _PAGE_DIRTY )
+ {
dirty = 1;
/* Note: this is atomic, so we may clear a
* _PAGE_ACCESSED set by another processor. */
@@ -2987,7 +3003,10 @@ int shadow_track_dirty_vram(struct domai
}
if ( dirty )
+ {
d->dirty_vram->dirty_bitmap[i / 8] |= 1 << (i % 8);
+ d->dirty_vram->last_dirty = NOW();
+ }
}
#ifdef __i386__
@@ -2998,6 +3017,14 @@ int shadow_track_dirty_vram(struct domai
rc = -EFAULT;
if ( copy_to_guest(dirty_bitmap, d->dirty_vram->dirty_bitmap, dirty_size) == 0 ) {
memset(d->dirty_vram->dirty_bitmap, 0, dirty_size);
+ if (d->dirty_vram->last_dirty + SECONDS(2) < NOW())
+ {
+ /* was clean for more than two seconds, try to disable guest
+ * write access */
+ for ( i = begin_pfn; i < end_pfn; i++ )
+ flush_tlb |= sh_remove_write_access(d->vcpu[0], gfn_to_mfn(d, i, &t), 1, 0);
+ d->dirty_vram->last_dirty = -1;
+ }
rc = 0;
}
}
diff -r 3bc6ad3beafc -r 98b06d404e6b xen/arch/x86/mm/shadow/multi.c
--- a/xen/arch/x86/mm/shadow/multi.c Fri May 02 14:59:35 2008 +0100
+++ b/xen/arch/x86/mm/shadow/multi.c Thu May 08 12:50:34 2008 +0100
@@ -870,6 +870,17 @@ _sh_propagate(struct vcpu *v,
}
}
+ if ( unlikely((level == 1) && d->dirty_vram
+ && d->dirty_vram->last_dirty == -1
+ && gfn_x(target_gfn) >= d->dirty_vram->begin_pfn
+ && gfn_x(target_gfn) < d->dirty_vram->end_pfn) )
+ {
+ if ( ft & FETCH_TYPE_WRITE )
+ d->dirty_vram->last_dirty = NOW();
+ else
+ sflags &= ~_PAGE_RW;
+ }
+
/* Read-only memory */
if ( p2mt == p2m_ram_ro )
sflags &= ~_PAGE_RW;
@@ -1320,8 +1331,10 @@ static inline void shadow_vram_put_l1e(s
* just hope it will remain. */
}
}
- if ( dirty )
+ if ( dirty ) {
d->dirty_vram->dirty_bitmap[i / 8] |= 1 << (i % 8);
+ d->dirty_vram->last_dirty = NOW();
+ }
}
}
diff -r 3bc6ad3beafc -r 98b06d404e6b xen/arch/x86/mm/shadow/private.h
--- a/xen/arch/x86/mm/shadow/private.h Fri May 02 14:59:35 2008 +0100
+++ b/xen/arch/x86/mm/shadow/private.h Thu May 08 12:50:34 2008 +0100
@@ -536,6 +536,7 @@ struct sh_dirty_vram {
unsigned long end_pfn;
paddr_t *sl1ma;
uint8_t *dirty_bitmap;
+ s_time_t last_dirty;
};
/**************************************************************************/
prev parent reply other threads:[~2008-05-08 11:58 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-05-02 14:05 [PATCH] shadow: track video RAM dirty bits Samuel Thibault
2008-05-04 10:58 ` Samuel Thibault
2008-05-08 11:58 ` Samuel Thibault [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20080508115820.GI4365@implementation.uk.xensource.com \
--to=samuel.thibault@eu.citrix.com \
--cc=gianluca.guida@eu.citrix.com \
--cc=tim.deegan@eu.citrix.com \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.