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

[Xen-devel] [PATCH 2/2] [Qemu] Reduce memory required to allocate ioports.



To store ioport information some very huge (3.5 MB on 64bit) static arrays
where used. Doing some scalability tests we discover that these arrays
consume a lot of memory.
Rewrite the implementation to use a tree.
New Qemu upstream use a structure which is much more complicated.

Signed-off-by: Frediano Ziglio <frediano.ziglio@xxxxxxxxxx>
---
 vl.c | 105 ++++++++++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 69 insertions(+), 36 deletions(-)

diff --git a/vl.c b/vl.c
index d21c3aa..39e79e4 100644
--- a/vl.c
+++ b/vl.c
@@ -191,9 +191,18 @@ int main(int argc, char **argv)
 
 const char *bios_dir = CONFIG_QEMU_SHAREDIR;
 const char *bios_name = NULL;
-static void *ioport_opaque[MAX_IOPORTS];
-static IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
-static IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
+
+typedef struct ioport_data {
+       IOPortReadFunc *read_table[3];
+       IOPortWriteFunc *write_table[3];
+       void *opaque;
+       void *res; // to align structure
+} ioport_data_t;
+#define IOPORT_PAGESIZE 4096u
+#define IOPORT_PAGE_ENTRIES (IOPORT_PAGESIZE/sizeof(ioport_data_t))
+#define IOPORT_NUM_PAGES (((MAX_IOPORTS-1)/IOPORT_PAGE_ENTRIES)+1)
+static ioport_data_t* ioport_table[IOPORT_NUM_PAGES];
+
 /* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
    to store the VM snapshots */
 DriveInfo drives_table[MAX_DRIVES+1];
@@ -290,30 +299,55 @@ PicState2 *isa_pic;
 static IOPortReadFunc default_ioport_readb, default_ioport_readw, 
default_ioport_readl;
 static IOPortWriteFunc default_ioport_writeb, default_ioport_writew, 
default_ioport_writel;
 
+static const ioport_data_t default_ioport = {
+    { default_ioport_readb, default_ioport_readw, default_ioport_readl },
+    { default_ioport_writeb, default_ioport_writew, default_ioport_writel }
+};
+
+static ioport_data_t* ioport_create_page(void)
+{
+    unsigned n;
+    ioport_data_t* data = qemu_malloc(IOPORT_PAGESIZE);
+
+    for (n = 0; n < IOPORT_PAGE_ENTRIES; ++n)
+        data[n] = default_ioport;
+
+    return data;
+}
+
+static inline const ioport_data_t *get_ioport(int address)
+{
+    ioport_data_t *page;
+
+    page = ioport_table[address / IOPORT_PAGE_ENTRIES];
+    if (page)
+        return &page[address % IOPORT_PAGE_ENTRIES];
+    return &default_ioport;
+}
+
+static ioport_data_t *get_ioport_alloc(int address)
+{
+    ioport_data_t *page;
+
+    page = ioport_table[address / IOPORT_PAGE_ENTRIES];
+    if (!page)
+        ioport_table[address / IOPORT_PAGE_ENTRIES] = page = 
ioport_create_page();
+    return &page[address % IOPORT_PAGE_ENTRIES];
+}
+
+
 static uint32_t ioport_read(int index, uint32_t address)
 {
-    static IOPortReadFunc *default_func[3] = {
-        default_ioport_readb,
-        default_ioport_readw,
-        default_ioport_readl
-    };
-    IOPortReadFunc *func = ioport_read_table[index][address];
-    if (!func)
-        func = default_func[index];
-    return func(ioport_opaque[address], address);
+    const ioport_data_t *port = get_ioport(address);
+
+    return port->read_table[index](port->opaque, address);
 }
 
 static void ioport_write(int index, uint32_t address, uint32_t data)
 {
-    static IOPortWriteFunc *default_func[3] = {
-        default_ioport_writeb,
-        default_ioport_writew,
-        default_ioport_writel
-    };
-    IOPortWriteFunc *func = ioport_write_table[index][address];
-    if (!func)
-        func = default_func[index];
-    func(ioport_opaque[address], address, data);
+    const ioport_data_t *port = get_ioport(address);
+
+    port->write_table[index](port->opaque, address, data);
 }
 
 static uint32_t default_ioport_readb(void *opaque, uint32_t address)
@@ -380,10 +414,12 @@ int register_ioport_read(int start, int length, int size,
         return -1;
     }
     for(i = start; i < start + length; i += size) {
-        ioport_read_table[bsize][i] = func;
-        if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
+        ioport_data_t *data = get_ioport_alloc(i);
+
+        data->read_table[bsize] = func;
+        if (data->opaque != NULL && data->opaque != opaque)
             hw_error("register_ioport_read: invalid opaque");
-        ioport_opaque[i] = opaque;
+        data->opaque = opaque;
     }
     return 0;
 }
@@ -405,10 +441,12 @@ int register_ioport_write(int start, int length, int size,
         return -1;
     }
     for(i = start; i < start + length; i += size) {
-        ioport_write_table[bsize][i] = func;
-        if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
-            hw_error("register_ioport_write: invalid opaque");
-        ioport_opaque[i] = opaque;
+        ioport_data_t *data = get_ioport_alloc(i);
+
+        data->write_table[bsize] = func;
+        if (data->opaque != NULL && data->opaque != opaque)
+            hw_error("register_ioport_read: invalid opaque");
+        data->opaque = opaque;
     }
     return 0;
 }
@@ -418,15 +456,10 @@ void isa_unassign_ioport(int start, int length)
     int i;
 
     for(i = start; i < start + length; i++) {
-        ioport_read_table[0][i] = default_ioport_readb;
-        ioport_read_table[1][i] = default_ioport_readw;
-        ioport_read_table[2][i] = default_ioport_readl;
-
-        ioport_write_table[0][i] = default_ioport_writeb;
-        ioport_write_table[1][i] = default_ioport_writew;
-        ioport_write_table[2][i] = default_ioport_writel;
+        /* TODO do not alloc if not required */
+        ioport_data_t *data = get_ioport_alloc(i);
 
-        ioport_opaque[i] = NULL;
+        *data = default_ioport;
     }
 }
 
-- 
1.9.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

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