[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] Added prediction of where to find the last writable PTE for a given page;



ChangeSet 1.1236.32.14, 2005/03/21 12:01:36+00:00, mafetter@xxxxxxxxxxxxxxxx

        Added prediction of where to find the last writable PTE for a given 
page;
        greatly speeds up promotion of a page to be used as a page table.
        
        Removed some broken concepts of write protecting PDEs and higher level
        entries.  To write protect a page, all we need to do is write protect 
all
        L1 entries that point at it.
        
        Fixed a bug with translated IO pages; gotta check that MFNs are really 
backed
        by RAM before we go looking in the frame_table for them...
        
        Signed-off-by: michael.fetterman@xxxxxxxxxxxx



 arch/x86/audit.c         |   12 +-
 arch/x86/mm.c            |    2 
 arch/x86/shadow.c        |  237 +++++++++++++++++++++++++++++++----------------
 include/asm-x86/mm.h     |    9 +
 include/asm-x86/shadow.h |   94 ++++++++++++------
 include/xen/perfc.h      |    1 
 include/xen/perfc_defn.h |    7 +
 7 files changed, 248 insertions(+), 114 deletions(-)


diff -Nru a/xen/arch/x86/audit.c b/xen/arch/x86/audit.c
--- a/xen/arch/x86/audit.c      2005-04-05 12:14:01 -04:00
+++ b/xen/arch/x86/audit.c      2005-04-05 12:14:01 -04:00
@@ -333,22 +333,26 @@
                 smfn = a->smfn;
                 page = &frame_table[smfn];
 
-                adjust(pfn_to_page(gmfn), 0);
-
                 switch ( a->gpfn_and_flags & PGT_type_mask ) {
+                case PGT_writable_pred:
+                    break;
                 case PGT_snapshot:
+                    adjust(pfn_to_page(gmfn), 0);
                     break;
                 case PGT_l1_shadow:
+                    adjust(pfn_to_page(gmfn), 0);
                     adjust_l1_page(smfn);
                     if ( page->u.inuse.type_info & PGT_pinned )
                         adjust(page, 0);
                     break;
                 case PGT_hl2_shadow:
+                    adjust(pfn_to_page(gmfn), 0);
                     adjust_hl2_page(smfn);
                     if ( page->u.inuse.type_info & PGT_pinned )
                         adjust(page, 0);
                     break;
                 case PGT_l2_shadow:
+                    adjust(pfn_to_page(gmfn), 0);
                     adjust_l2_page(smfn);
                     if ( page->u.inuse.type_info & PGT_pinned )
                         adjust(page, 0);
@@ -619,6 +623,7 @@
                         scan_for_pfn_in_mfn(d, xmfn, a->smfn);
                         break;
                     case PGT_snapshot:
+                    case PGT_writable_pred:
                         break;
                     default:
                         BUG();
@@ -834,6 +839,9 @@
                                page->count_info);
                         errors++;
                     }
+                    break;
+                case PGT_writable_pred:
+                    // XXX - nothing to check?
                     break;
 
                 default:
diff -Nru a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c 2005-04-05 12:14:01 -04:00
+++ b/xen/arch/x86/mm.c 2005-04-05 12:14:01 -04:00
@@ -268,7 +268,7 @@
     if ( unlikely(shadow_mode_enabled(d)) )
     {
         shadow_lock(d);
-        shadow_remove_all_write_access(d, PGT_l1_shadow, PGT_l1_shadow, gpfn, 
gmfn);
+        shadow_remove_all_write_access(d, gpfn, gmfn);
     }
 
     res = get_page_and_type(&frame_table[gmfn], d, PGT_ldt_page);
diff -Nru a/xen/arch/x86/shadow.c b/xen/arch/x86/shadow.c
--- a/xen/arch/x86/shadow.c     2005-04-05 12:14:00 -04:00
+++ b/xen/arch/x86/shadow.c     2005-04-05 12:14:00 -04:00
@@ -48,7 +48,6 @@
 shadow_promote(struct domain *d, unsigned long gpfn, unsigned long gmfn,
                unsigned long new_type)
 {
-    unsigned long min_type, max_type;
     struct pfn_info *page = pfn_to_page(gmfn);
     int pinned = 0, okay = 1;
 
@@ -61,20 +60,11 @@
     }
 
     if ( unlikely(page_is_page_table(page)) )
-    {
-        min_type = shadow_max_pgtable_type(d, gpfn) + PGT_l1_shadow;
-        max_type = new_type;
-    }
-    else
-    {
-        min_type = PGT_l1_shadow;
-        max_type = PGT_l1_shadow;
-    }
-    FSH_LOG("shadow_promote gpfn=%p gmfn=%p nt=%p min=%p max=%p",
-            gpfn, gmfn, new_type, min_type, max_type);
+        return 1;
 
-    if ( (min_type <= max_type) &&
-         !shadow_remove_all_write_access(d, min_type, max_type, gpfn, gmfn) )
+    FSH_LOG("shadow_promote gpfn=%p gmfn=%p nt=%p", gpfn, gmfn, new_type);
+
+    if ( !shadow_remove_all_write_access(d, gpfn, gmfn) )
         return 0;
 
     // To convert this page to use as a page table, the writable count
@@ -1737,114 +1727,192 @@
     return 0;
 }
 
+#define GPFN_TO_GPTEPAGE(_gpfn) ((_gpfn) / (PAGE_SIZE / sizeof(l1_pgentry_t)))
+static inline unsigned long
+predict_writable_pte_page(struct domain *d, unsigned long gpfn)
+{
+    return __shadow_status(d, GPFN_TO_GPTEPAGE(gpfn), PGT_writable_pred);
+}
+
+static inline void
+increase_writable_pte_prediction(struct domain *d, unsigned long gpfn, 
unsigned long prediction)
+{
+    unsigned long score = prediction & PGT_score_mask;
+    int create = (score == 0);
+
+    // saturating addition
+    score = (score + (1u << PGT_score_shift)) & PGT_score_mask;
+    score = score ? score : PGT_score_mask;
+
+    prediction = (prediction & PGT_mfn_mask) | score;
+
+    //printk("increase gpfn=%p pred=%p create=%d\n", gpfn, prediction, create);
+    set_shadow_status(d, GPFN_TO_GPTEPAGE(gpfn), 0, prediction, 
PGT_writable_pred);
+
+    if ( create )
+        perfc_incr(writable_pte_predictions);
+}
+
+static inline void
+decrease_writable_pte_prediction(struct domain *d, unsigned long gpfn, 
unsigned long prediction)
+{
+    unsigned long score = prediction & PGT_score_mask;
+    ASSERT(score);
+
+    // divide score by 2...  We don't like bad predictions.
+    //
+    score = (score >> 1) & PGT_score_mask;
+
+    prediction = (prediction & PGT_mfn_mask) | score;
+
+    //printk("decrease gpfn=%p pred=%p score=%p\n", gpfn, prediction, score);
+
+    if ( score )
+        set_shadow_status(d, GPFN_TO_GPTEPAGE(gpfn), 0, prediction, 
PGT_writable_pred);
+    else
+    {
+        delete_shadow_status(d, GPFN_TO_GPTEPAGE(gpfn), 0, PGT_writable_pred);
+        perfc_decr(writable_pte_predictions);
+    }
+}
+
 static u32 remove_all_write_access_in_ptpage(
-    struct domain *d, unsigned long pt_mfn, unsigned long readonly_mfn)
+    struct domain *d, unsigned long pt_pfn, unsigned long pt_mfn,
+    unsigned long readonly_gpfn, unsigned long readonly_gmfn,
+    u32 max_refs_to_find, unsigned long prediction)
 {
     unsigned long *pt = map_domain_mem(pt_mfn << PAGE_SHIFT);
     unsigned long match =
-        (readonly_mfn << PAGE_SHIFT) | _PAGE_RW | _PAGE_PRESENT;
+        (readonly_gmfn << PAGE_SHIFT) | _PAGE_RW | _PAGE_PRESENT;
     unsigned long mask = PAGE_MASK | _PAGE_RW | _PAGE_PRESENT;
     int i;
-    u32 count = 0;
+    u32 found = 0;
     int is_l1_shadow =
         ((frame_table[pt_mfn].u.inuse.type_info & PGT_type_mask) ==
          PGT_l1_shadow);
 
-    for (i = 0; i < L1_PAGETABLE_ENTRIES; i++)
+#define MATCH_ENTRY(_i) (((pt[_i] ^ match) & mask) == 0)
+
+    // returns true if all refs have been found and fixed.
+    //
+    int fix_entry(int i)
     {
-        if ( unlikely(((pt[i] ^ match) & mask) == 0) )
-        {
-            unsigned long old = pt[i];
-            unsigned long new = old & ~_PAGE_RW;
+        unsigned long old = pt[i];
+        unsigned long new = old & ~_PAGE_RW;
 
-            if ( is_l1_shadow &&
-                 !shadow_get_page_from_l1e(mk_l1_pgentry(new), d) )
-                BUG();
+        if ( is_l1_shadow && !shadow_get_page_from_l1e(mk_l1_pgentry(new), d) )
+            BUG();
+        found++;
+        pt[i] = new;
+        if ( is_l1_shadow )
+            put_page_from_l1e(mk_l1_pgentry(old), d);
 
-            count++;
-            pt[i] = new;
+#if 0
+        printk("removed write access to pfn=%p mfn=%p in smfn=%p entry %x "
+               "is_l1_shadow=%d\n",
+               readonly_gpfn, readonly_gmfn, pt_mfn, i, is_l1_shadow);
+#endif
 
-            if ( is_l1_shadow )
-                put_page_from_l1e(mk_l1_pgentry(old), d);
+        return (found == max_refs_to_find);
+    }
 
-            FSH_LOG("removed write access to mfn=%p in smfn=%p entry %x "
-                    "is_l1_shadow=%d",
-                    readonly_mfn, pt_mfn, i, is_l1_shadow);
-        }
+    if ( MATCH_ENTRY(readonly_gpfn & (L1_PAGETABLE_ENTRIES - 1)) &&
+         fix_entry(readonly_gpfn & (L1_PAGETABLE_ENTRIES - 1)) )
+    {
+        perfc_incrc(remove_write_fast_exit);
+        increase_writable_pte_prediction(d, readonly_gpfn, prediction);
+        unmap_domain_mem(pt);
+        return found;
+    }
+ 
+    for (i = 0; i < L1_PAGETABLE_ENTRIES; i++)
+    {
+        if ( unlikely(MATCH_ENTRY(i)) && fix_entry(i) )
+            break;
     }
 
     unmap_domain_mem(pt);
 
-    return count;
+    return found;
+#undef MATCH_ENTRY
 }
 
 int shadow_remove_all_write_access(
-    struct domain *d, unsigned min_type, unsigned max_type,
-    unsigned long gpfn, unsigned long gmfn)
+    struct domain *d, unsigned long readonly_gpfn, unsigned long readonly_gmfn)
 {
     int i;
     struct shadow_status *a;
-    unsigned long sl1mfn = __shadow_status(d, gpfn, PGT_l1_shadow);
-    u32 count = 0;
-    u32 write_refs;
+    u32 found = 0, fixups, write_refs;
+    unsigned long prediction, predicted_gpfn, predicted_smfn;
 
     ASSERT(spin_is_locked(&d->arch.shadow_lock));
-    ASSERT(gmfn);
+    ASSERT(VALID_MFN(readonly_gmfn));
 
     perfc_incrc(remove_write_access);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.