xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Olaf Hering <olaf@aepfle.de>
To: xen-devel@lists.xensource.com
Subject: [PATCH 01 of 10] xenpaging: use flat index for pagefile and page-in requests
Date: Mon, 30 Jan 2012 16:59:24 +0100	[thread overview]
Message-ID: <2d71d8bca0f15d353d28.1327939164@probook.site> (raw)
In-Reply-To: <patchbomb.1327939163@probook.site>

# HG changeset patch
# User Olaf Hering <olaf@aepfle.de>
# Date 1327937786 -3600
# Node ID 2d71d8bca0f15d353d28f5a42cc0c4e21002e8d5
# Parent  39df93acd4089eaae138e1decf49aec39fb19417
xenpaging: use flat index for pagefile and page-in requests

This change is based on an idea by <hongkaixing@huawei.com> and
<bicky.shi@huawei.com>.

Scanning the victims[] array is time consuming with a large number of
target pages. Replace the loop to find the slot in the pagefile which
holds the requested gfn with an index.

Remove the victims array and replace it with a flat array. This array
holds the gfn for a given slot in the pagefile. Adjust all users of the
victims array.

Rename variable in main() from i to slot to clearify the meaning.

Update xenpaging_evict_page() to pass a pointer to xen_pfn_t to
xc_map_foreign_pages().

Update policy_choose_victim() to return either a gfn or INVALID_MFN.

Signed-off-by: Olaf Hering <olaf@aepfle.de>

diff -r 39df93acd408 -r 2d71d8bca0f1 tools/xenpaging/policy.h
--- a/tools/xenpaging/policy.h
+++ b/tools/xenpaging/policy.h
@@ -29,7 +29,7 @@
 
 
 int policy_init(struct xenpaging *paging);
-int policy_choose_victim(struct xenpaging *paging, struct victim *victim);
+unsigned long policy_choose_victim(struct xenpaging *paging);
 void policy_notify_paged_out(unsigned long gfn);
 void policy_notify_paged_in(unsigned long gfn);
 void policy_notify_paged_in_nomru(unsigned long gfn);
diff -r 39df93acd408 -r 2d71d8bca0f1 tools/xenpaging/policy_default.c
--- a/tools/xenpaging/policy_default.c
+++ b/tools/xenpaging/policy_default.c
@@ -77,7 +77,7 @@ int policy_init(struct xenpaging *paging
     return rc;
 }
 
-int policy_choose_victim(struct xenpaging *paging, struct victim *victim)
+unsigned long policy_choose_victim(struct xenpaging *paging)
 {
     xc_interface *xch = paging->xc_handle;
     unsigned long wrap = current_gfn;
@@ -102,16 +102,13 @@ int policy_choose_victim(struct xenpagin
                 /* One more round before returning ENOSPC */
                 continue;
             }
-            victim->gfn = INVALID_MFN;
-            return -ENOSPC;
+            return INVALID_MFN;
         }
     }
     while ( test_bit(current_gfn, bitmap) || test_bit(current_gfn, unconsumed) );
 
     set_bit(current_gfn, unconsumed);
-    victim->gfn = current_gfn;
-
-    return 0;
+    return current_gfn;
 }
 
 void policy_notify_paged_out(unsigned long gfn)
diff -r 39df93acd408 -r 2d71d8bca0f1 tools/xenpaging/xenpaging.c
--- a/tools/xenpaging/xenpaging.c
+++ b/tools/xenpaging/xenpaging.c
@@ -430,6 +430,12 @@ static struct xenpaging *xenpaging_init(
     }
     DPRINTF("max_pages = %d\n", paging->max_pages);
 
+    /* Allocate indicies for pagefile slots */
+    paging->slot_to_gfn = calloc(paging->max_pages, sizeof(*paging->slot_to_gfn));
+    paging->gfn_to_slot = calloc(paging->max_pages, sizeof(*paging->gfn_to_slot));
+    if ( !paging->slot_to_gfn || !paging->gfn_to_slot )
+        goto err;
+
     /* Initialise policy */
     rc = policy_init(paging);
     if ( rc != 0 )
@@ -468,6 +474,8 @@ static struct xenpaging *xenpaging_init(
 
         free(dom_path);
         free(watch_target_tot_pages);
+        free(paging->slot_to_gfn);
+        free(paging->gfn_to_slot);
         free(paging->bitmap);
         free(paging);
     }
@@ -561,31 +569,29 @@ static void put_response(struct mem_even
     RING_PUSH_RESPONSES(back_ring);
 }
 
-static int xenpaging_evict_page(struct xenpaging *paging, struct victim *victim, int fd, int i)
+static int xenpaging_evict_page(struct xenpaging *paging, unsigned long gfn, int fd, int slot)
 {
     xc_interface *xch = paging->xc_handle;
     void *page;
-    unsigned long gfn;
+    xen_pfn_t victim = gfn;
     int ret;
 
     DECLARE_DOMCTL;
 
     /* Map page */
-    gfn = victim->gfn;
     ret = -EFAULT;
-    page = xc_map_foreign_pages(xch, paging->mem_event.domain_id,
-                                PROT_READ | PROT_WRITE, &gfn, 1);
+    page = xc_map_foreign_pages(xch, paging->mem_event.domain_id, PROT_READ | PROT_WRITE, &victim, 1);
     if ( page == NULL )
     {
-        PERROR("Error mapping page %lx", victim->gfn);
+        PERROR("Error mapping page %lx", gfn);
         goto out;
     }
 
     /* Copy page */
-    ret = write_page(fd, page, i);
+    ret = write_page(fd, page, slot);
     if ( ret != 0 )
     {
-        PERROR("Error copying page %lx", victim->gfn);
+        PERROR("Error copying page %lx", gfn);
         munmap(page, PAGE_SIZE);
         goto out;
     }
@@ -593,17 +599,20 @@ static int xenpaging_evict_page(struct x
     munmap(page, PAGE_SIZE);
 
     /* Tell Xen to evict page */
-    ret = xc_mem_paging_evict(xch, paging->mem_event.domain_id,
-                              victim->gfn);
+    ret = xc_mem_paging_evict(xch, paging->mem_event.domain_id, gfn);
     if ( ret != 0 )
     {
-        PERROR("Error evicting page %lx", victim->gfn);
+        PERROR("Error evicting page %lx", gfn);
         goto out;
     }
 
-    DPRINTF("evict_page > gfn %lx pageslot %d\n", victim->gfn, i);
+    DPRINTF("evict_page > gfn %lx pageslot %d\n", gfn, slot);
     /* Notify policy of page being paged out */
-    policy_notify_paged_out(victim->gfn);
+    policy_notify_paged_out(gfn);
+
+    /* Update index */
+    paging->slot_to_gfn[slot] = gfn;
+    paging->gfn_to_slot[gfn] = slot;
 
     /* Record number of evicted pages */
     paging->num_paged_out++;
@@ -710,19 +719,19 @@ static void resume_pages(struct xenpagin
         page_in_trigger();
 }
 
-static int evict_victim(struct xenpaging *paging, struct victim *victim, int fd, int i)
+static int evict_victim(struct xenpaging *paging, int fd, int slot)
 {
     xc_interface *xch = paging->xc_handle;
+    unsigned long gfn;
     int j = 0;
     int ret;
 
     do
     {
-        ret = policy_choose_victim(paging, victim);
-        if ( ret != 0 )
+        gfn = policy_choose_victim(paging);
+        if ( gfn == INVALID_MFN )
         {
-            if ( ret != -ENOSPC )
-                ERROR("Error choosing victim");
+            ret = -ENOSPC;
             goto out;
         }
 
@@ -731,9 +740,9 @@ static int evict_victim(struct xenpaging
             ret = -EINTR;
             goto out;
         }
-        ret = xc_mem_paging_nominate(xch, paging->mem_event.domain_id, victim->gfn);
+        ret = xc_mem_paging_nominate(xch, paging->mem_event.domain_id, gfn);
         if ( ret == 0 )
-            ret = xenpaging_evict_page(paging, victim, fd, i);
+            ret = xenpaging_evict_page(paging, gfn, fd, slot);
         else
         {
             if ( j++ % 1000 == 0 )
@@ -743,7 +752,7 @@ static int evict_victim(struct xenpaging
     }
     while ( ret );
 
-    if ( test_and_set_bit(victim->gfn, paging->bitmap) )
+    if ( test_and_set_bit(gfn, paging->bitmap) )
         ERROR("Page has been evicted before");
 
     ret = 0;
@@ -753,7 +762,7 @@ static int evict_victim(struct xenpaging
 }
 
 /* Evict a batch of pages and write them to a free slot in the paging file */
-static int evict_pages(struct xenpaging *paging, int fd, struct victim *victims, int num_pages)
+static int evict_pages(struct xenpaging *paging, int fd, int num_pages)
 {
     xc_interface *xch = paging->xc_handle;
     int rc, slot, num = 0;
@@ -761,10 +770,10 @@ static int evict_pages(struct xenpaging 
     for ( slot = 0; slot < paging->max_pages && num < num_pages; slot++ )
     {
         /* Slot is allocated */
-        if ( victims[slot].gfn != INVALID_MFN )
+        if ( paging->slot_to_gfn[slot] )
             continue;
 
-        rc = evict_victim(paging, &victims[slot], fd, slot);
+        rc = evict_victim(paging, fd, slot);
         if ( rc == -ENOSPC )
             break;
         if ( rc == -EINTR )
@@ -780,11 +789,10 @@ int main(int argc, char *argv[])
 {
     struct sigaction act;
     struct xenpaging *paging;
-    struct victim *victims;
     mem_event_request_t req;
     mem_event_response_t rsp;
     int num, prev_num = 0;
-    int i;
+    int slot;
     int tot_pages;
     int rc = -1;
     int rc1;
@@ -813,15 +821,6 @@ int main(int argc, char *argv[])
         return 2;
     }
 
-    /* Allocate upper limit of pages to allow growing and shrinking */
-    victims = calloc(paging->max_pages, sizeof(struct victim));
-    if ( !victims )
-        goto out;
-
-    /* Mark all slots as unallocated */
-    for ( i = 0; i < paging->max_pages; i++ )
-        victims[i].gfn = INVALID_MFN;
-
     /* ensure that if we get a signal, we'll do cleanup, then exit */
     act.sa_handler = close_handler;
     act.sa_flags = 0;
@@ -853,32 +852,35 @@ int main(int argc, char *argv[])
         {
             get_request(&paging->mem_event, &req);
 
+            if ( req.gfn > paging->max_pages )
+            {
+                ERROR("Requested gfn %"PRIx64" higher than max_pages %lx\n", req.gfn, paging->max_pages);
+                goto out;
+            }
+
             /* Check if the page has already been paged in */
             if ( test_and_clear_bit(req.gfn, paging->bitmap) )
             {
                 /* Find where in the paging file to read from */
-                for ( i = 0; i < paging->max_pages; i++ )
+                slot = paging->gfn_to_slot[req.gfn];
+
+                /* Sanity check */
+                if ( paging->slot_to_gfn[slot] != req.gfn )
                 {
-                    if ( victims[i].gfn == req.gfn )
-                        break;
-                }
-    
-                if ( i >= paging->max_pages )
-                {
-                    DPRINTF("Couldn't find page %"PRIx64"\n", req.gfn);
+                    ERROR("Expected gfn %"PRIx64" in slot %d, but found gfn %lx\n", req.gfn, slot, paging->slot_to_gfn[slot]);
                     goto out;
                 }
-                
+
                 if ( req.flags & MEM_EVENT_FLAG_DROP_PAGE )
                 {
-                    DPRINTF("drop_page ^ gfn %"PRIx64" pageslot %d\n", req.gfn, i);
+                    DPRINTF("drop_page ^ gfn %"PRIx64" pageslot %d\n", req.gfn, slot);
                     /* Notify policy of page being dropped */
                     policy_notify_dropped(req.gfn);
                 }
                 else
                 {
                     /* Populate the page */
-                    rc = xenpaging_populate_page(paging, req.gfn, fd, i);
+                    rc = xenpaging_populate_page(paging, req.gfn, fd, slot);
                     if ( rc != 0 )
                     {
                         PERROR("Error populating page %"PRIx64"", req.gfn);
@@ -899,7 +901,7 @@ int main(int argc, char *argv[])
                 }
 
                 /* Clear this pagefile slot */
-                victims[i].gfn = INVALID_MFN;
+                paging->slot_to_gfn[slot] = 0;
             }
             else
             {
@@ -969,7 +971,7 @@ int main(int argc, char *argv[])
             /* Limit the number of evicts to be able to process page-in requests */
             if ( num > 42 )
                 num = 42;
-            evict_pages(paging, fd, victims, num);
+            evict_pages(paging, fd, num);
         }
         /* Resume some pages if target not reached */
         else if ( tot_pages < paging->target_tot_pages && paging->num_paged_out )
@@ -989,7 +991,6 @@ int main(int argc, char *argv[])
  out:
     close(fd);
     unlink_pagefile();
-    free(victims);
 
     /* Tear down domain paging */
     rc1 = xenpaging_teardown(paging);
diff -r 39df93acd408 -r 2d71d8bca0f1 tools/xenpaging/xenpaging.h
--- a/tools/xenpaging/xenpaging.h
+++ b/tools/xenpaging/xenpaging.h
@@ -46,6 +46,9 @@ struct xenpaging {
 
     unsigned long *bitmap;
 
+    unsigned long *slot_to_gfn;
+    int *gfn_to_slot;
+
     struct mem_event mem_event;
     /* number of pages for which data structures were allocated */
     int max_pages;
@@ -56,13 +59,6 @@ struct xenpaging {
     unsigned long pagein_queue[XENPAGING_PAGEIN_QUEUE_SIZE];
 };
 
-
-struct victim {
-    /* the gfn of the page to evict */
-    unsigned long gfn;
-};
-
-
 extern void create_page_in_thread(struct xenpaging *paging);
 extern void page_in_trigger(void);

  reply	other threads:[~2012-01-30 15:59 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-01-30 15:59 [PATCH 00 of 10] tools/xenpaging: cleanups and performance improvements Olaf Hering
2012-01-30 15:59 ` Olaf Hering [this message]
2012-01-30 15:59 ` [PATCH 02 of 10] xenpaging: no poll timeout while page-out is in progress Olaf Hering
2012-01-30 15:59 ` [PATCH 03 of 10] xenpaging: mmap guest pages read-only Olaf Hering
2012-01-30 15:59 ` [PATCH 04 of 10] xenpaging: reduce number of qemu cache flushes Olaf Hering
2012-01-30 15:59 ` [PATCH 05 of 10] xenpaging: move nominate+evict into single function Olaf Hering
2012-01-30 15:59 ` [PATCH 06 of 10] xenpaging: improve performance in policy_choose_victim Olaf Hering
2012-02-14 21:08   ` Olaf Hering
2012-02-20 17:25     ` [PATCH 06 of 10] xenpaging: improve performance in policy_choose_victim [and 1 more messages] Ian Jackson
2012-02-20 18:48       ` Olaf Hering
2012-01-30 15:59 ` [PATCH 07 of 10] xenpaging: unify error handling Olaf Hering
2012-01-30 15:59 ` [PATCH 08 of 10] xenpaging: move pagefile filedescriptor into struct xenpaging Olaf Hering
2012-01-30 15:59 ` [PATCH 09 of 10] xenpaging: move page_buffer " Olaf Hering
2012-01-30 15:59 ` [PATCH 10 of 10] xenpaging: implement stack of free slots in pagefile Olaf Hering
2012-02-09 17:57 ` [PATCH 00 of 10] tools/xenpaging: cleanups and performance improvements Ian Jackson

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=2d71d8bca0f15d353d28.1327939164@probook.site \
    --to=olaf@aepfle.de \
    --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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).