xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: "Jan Beulich" <JBeulich@novell.com>
To: xen-devel@lists.xensource.com
Subject: [PATCH] x86: fix Dom0 booting time regression
Date: Tue, 04 May 2010 10:05:21 +0100	[thread overview]
Message-ID: <4BDFFF71020000780000118A@vpn.id2.novell.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 4003 bytes --]

Unfortunately the changes in c/s 21035 caused boot time to go up
significantly on certain large systems. To rectify this without going
back to the old behavior, introduce a new memory allocation flag so
that Dom0 allocations can exhaust non-DMA memory before starting to
consume DMA memory. For the latter, the behavior introduced in
aforementioned c/s gets retained, while for the former we can now even
try larger chunks first.

This builds on the fact that alloc_chunk() gets called with non-
increasing 'max_pages' arguments, end hence it can store locally the
allocation order last used (as larger order allocations can't succeed
during subsequent invocations if they failed once).

Signed-off-by: Jan Beulich <jbeulich@novell.com>

--- 2010-04-30.orig/xen/arch/x86/domain_build.c	2010-05-04 10:30:34.000000000 +0200
+++ 2010-04-30/xen/arch/x86/domain_build.c	2010-05-04 10:31:32.000000000 +0200
@@ -126,26 +126,36 @@ string_param("dom0_ioports_disable", opt
 static struct page_info * __init alloc_chunk(
     struct domain *d, unsigned long max_pages)
 {
+    static unsigned int __initdata last_order = MAX_ORDER;
+    static unsigned int __initdata memflags = MEMF_no_dma;
     struct page_info *page;
-    unsigned int order, free_order;
+    unsigned int order = get_order_from_pages(max_pages), free_order;
 
-    /*
-     * Allocate up to 2MB at a time: It prevents allocating very large chunks
-     * from DMA pools before the >4GB pool is fully depleted.
-     */
-    if ( max_pages > (2UL << (20 - PAGE_SHIFT)) )
-        max_pages = 2UL << (20 - PAGE_SHIFT);
-    order = get_order_from_pages(max_pages);
-    if ( (max_pages & (max_pages-1)) != 0 )
-        order--;
-    while ( (page = alloc_domheap_pages(d, order, 0)) == NULL )
+    if ( order > last_order )
+        order = last_order;
+    else if ( max_pages & (max_pages - 1) )
+        --order;
+    while ( (page = alloc_domheap_pages(d, order, memflags)) == NULL )
         if ( order-- == 0 )
             break;
+    if ( page )
+        last_order = order;
+    else if ( memflags )
+    {
+        /*
+         * Allocate up to 2MB at a time: It prevents allocating very large
+         * chunks from DMA pools before the >4GB pool is fully depleted.
+         */
+        last_order = 21 - PAGE_SHIFT;
+        memflags = 0;
+        return alloc_chunk(d, max_pages);
+    }
+
     /*
      * Make a reasonable attempt at finding a smaller chunk at a higher
      * address, to avoid allocating from low memory as much as possible.
      */
-    for ( free_order = order; page && order--; )
+    for ( free_order = order; !memflags && page && order--; )
     {
         struct page_info *pg2;
 
--- 2010-04-30.orig/xen/common/page_alloc.c	2010-05-04 10:30:34.000000000 +0200
+++ 2010-04-30/xen/common/page_alloc.c	2010-04-26 14:40:53.000000000 +0200
@@ -1157,8 +1157,9 @@ struct page_info *alloc_domheap_pages(
         pg = alloc_heap_pages(dma_zone + 1, zone_hi, node, order, memflags);
 
     if ( (pg == NULL) &&
-         ((pg = alloc_heap_pages(MEMZONE_XEN + 1, zone_hi,
-                                 node, order, memflags)) == NULL) )
+         ((memflags & MEMF_no_dma) ||
+          ((pg = alloc_heap_pages(MEMZONE_XEN + 1, zone_hi,
+                                  node, order, memflags)) == NULL)) )
          return NULL;
 
     if ( (d != NULL) && assign_pages(d, pg, order, memflags) )
--- 2010-04-30.orig/xen/include/xen/mm.h	2010-05-04 10:30:34.000000000 +0200
+++ 2010-04-30/xen/include/xen/mm.h	2010-04-26 17:46:32.000000000 +0200
@@ -79,6 +79,8 @@ int assign_pages(
 #define  MEMF_populate_on_demand (1U<<_MEMF_populate_on_demand)
 #define _MEMF_tmem        2
 #define  MEMF_tmem        (1U<<_MEMF_tmem)
+#define _MEMF_no_dma      3
+#define  MEMF_no_dma      (1U<<_MEMF_no_dma)
 #define _MEMF_node        8
 #define  MEMF_node(n)     ((((n)+1)&0xff)<<_MEMF_node)
 #define _MEMF_bits        24




[-- Attachment #2: x86-dom0-alloc-performance.patch --]
[-- Type: text/plain, Size: 3997 bytes --]

Unfortunately the changes in c/s 21035 caused boot time to go up
significantly on certain large systems. To rectify this without going
back to the old behavior, introduce a new memory allocation flag so
that Dom0 allocations can exhaust non-DMA memory before starting to
consume DMA memory. For the latter, the behavior introduced in
aforementioned c/s gets retained, while for the former we can now even
try larger chunks first.

This builds on the fact that alloc_chunk() gets called with non-
increasing 'max_pages' arguments, end hence it can store locally the
allocation order last used (as larger order allocations can't succeed
during subsequent invocations if they failed once).

Signed-off-by: Jan Beulich <jbeulich@novell.com>

--- 2010-04-30.orig/xen/arch/x86/domain_build.c	2010-05-04 10:30:34.000000000 +0200
+++ 2010-04-30/xen/arch/x86/domain_build.c	2010-05-04 10:31:32.000000000 +0200
@@ -126,26 +126,36 @@ string_param("dom0_ioports_disable", opt
 static struct page_info * __init alloc_chunk(
     struct domain *d, unsigned long max_pages)
 {
+    static unsigned int __initdata last_order = MAX_ORDER;
+    static unsigned int __initdata memflags = MEMF_no_dma;
     struct page_info *page;
-    unsigned int order, free_order;
+    unsigned int order = get_order_from_pages(max_pages), free_order;
 
-    /*
-     * Allocate up to 2MB at a time: It prevents allocating very large chunks
-     * from DMA pools before the >4GB pool is fully depleted.
-     */
-    if ( max_pages > (2UL << (20 - PAGE_SHIFT)) )
-        max_pages = 2UL << (20 - PAGE_SHIFT);
-    order = get_order_from_pages(max_pages);
-    if ( (max_pages & (max_pages-1)) != 0 )
-        order--;
-    while ( (page = alloc_domheap_pages(d, order, 0)) == NULL )
+    if ( order > last_order )
+        order = last_order;
+    else if ( max_pages & (max_pages - 1) )
+        --order;
+    while ( (page = alloc_domheap_pages(d, order, memflags)) == NULL )
         if ( order-- == 0 )
             break;
+    if ( page )
+        last_order = order;
+    else if ( memflags )
+    {
+        /*
+         * Allocate up to 2MB at a time: It prevents allocating very large
+         * chunks from DMA pools before the >4GB pool is fully depleted.
+         */
+        last_order = 21 - PAGE_SHIFT;
+        memflags = 0;
+        return alloc_chunk(d, max_pages);
+    }
+
     /*
      * Make a reasonable attempt at finding a smaller chunk at a higher
      * address, to avoid allocating from low memory as much as possible.
      */
-    for ( free_order = order; page && order--; )
+    for ( free_order = order; !memflags && page && order--; )
     {
         struct page_info *pg2;
 
--- 2010-04-30.orig/xen/common/page_alloc.c	2010-05-04 10:30:34.000000000 +0200
+++ 2010-04-30/xen/common/page_alloc.c	2010-04-26 14:40:53.000000000 +0200
@@ -1157,8 +1157,9 @@ struct page_info *alloc_domheap_pages(
         pg = alloc_heap_pages(dma_zone + 1, zone_hi, node, order, memflags);
 
     if ( (pg == NULL) &&
-         ((pg = alloc_heap_pages(MEMZONE_XEN + 1, zone_hi,
-                                 node, order, memflags)) == NULL) )
+         ((memflags & MEMF_no_dma) ||
+          ((pg = alloc_heap_pages(MEMZONE_XEN + 1, zone_hi,
+                                  node, order, memflags)) == NULL)) )
          return NULL;
 
     if ( (d != NULL) && assign_pages(d, pg, order, memflags) )
--- 2010-04-30.orig/xen/include/xen/mm.h	2010-05-04 10:30:34.000000000 +0200
+++ 2010-04-30/xen/include/xen/mm.h	2010-04-26 17:46:32.000000000 +0200
@@ -79,6 +79,8 @@ int assign_pages(
 #define  MEMF_populate_on_demand (1U<<_MEMF_populate_on_demand)
 #define _MEMF_tmem        2
 #define  MEMF_tmem        (1U<<_MEMF_tmem)
+#define _MEMF_no_dma      3
+#define  MEMF_no_dma      (1U<<_MEMF_no_dma)
 #define _MEMF_node        8
 #define  MEMF_node(n)     ((((n)+1)&0xff)<<_MEMF_node)
 #define _MEMF_bits        24

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

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

                 reply	other threads:[~2010-05-04  9:05 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=4BDFFF71020000780000118A@vpn.id2.novell.com \
    --to=jbeulich@novell.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 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).