diff mbox

[RFC,5/5] exec: memory radix tree page level compression

Message ID 1384187560-20557-6-git-send-email-mst@redhat.com
State New
Headers show

Commit Message

Michael S. Tsirkin Nov. 11, 2013, 4:41 p.m. UTC
At the moment, memory radix tree is already variable width, but it can
only skip the low bits of address.

This is efficient if we have huge memory regions but inefficient if we
are only using a tiny portion of the address space.

After we have built up the map, it's a simple matter to detect
configurations where a single L2 entry is valid.

We can them speed up the lookup by skipping one or more levels.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 exec.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

Comments

Eric Blake Nov. 11, 2013, 5:58 p.m. UTC | #1
On 11/11/2013 09:41 AM, Michael S. Tsirkin wrote:
> At the moment, memory radix tree is already variable width, but it can
> only skip the low bits of address.
> 
> This is efficient if we have huge memory regions but inefficient if we
> are only using a tiny portion of the address space.
> 
> After we have built up the map, it's a simple matter to detect
> configurations where a single L2 entry is valid.
> 
> We can them speed up the lookup by skipping one or more levels.

s/them/then/
diff mbox

Patch

diff --git a/exec.c b/exec.c
index 39f76ee..3ec6c2c 100644
--- a/exec.c
+++ b/exec.c
@@ -216,6 +216,75 @@  static void phys_page_set(AddressSpaceDispatch *d,
     phys_page_set_level(&d->phys_map, &index, &nb, leaf, P_L2_LEVELS - 1);
 }
 
+/* Compact a non leaf page entry. Simply detect that the entry has a single child,
+ * and update our entry so we can skip it and go directly to the destination.
+ */
+static void phys_page_compact(PhysPageEntry *lp, Node *nodes, unsigned long *compacted)
+{
+    unsigned valid_ptr = P_L2_SIZE;
+    int valid = 0;
+    PhysPageEntry *p;
+    int i;
+
+    if (lp->ptr == PHYS_MAP_NODE_NIL || test_and_set_bit(lp->ptr, compacted)) {
+        return;
+    }
+
+    set_bit(lp->ptr, compacted);
+
+    p = nodes[lp->ptr];
+    for (i = 0; i < P_L2_SIZE; i++) {
+        if (p[i].ptr == PHYS_MAP_NODE_NIL) {
+            continue;
+        }
+
+        valid_ptr = i;
+        valid++;
+        if (p[i].skip) {
+            phys_page_compact(&p[i], nodes, compacted);
+        }
+    }
+
+    /* We can only compress if there's only one child. */
+    if (valid != 1) {
+        return;
+    }
+
+    assert(valid_ptr < P_L2_SIZE);
+
+    /* Don't compress if it won't fit in the # of bits we have. */
+    if (lp->skip + p[valid_ptr].skip >= (1 << 3)) {
+        return;
+    }
+
+    lp->ptr = p[valid_ptr].ptr;
+    if (!p[valid_ptr].skip) {
+        /* If our only child is a leaf, make this a leaf. */
+        /* By design, we should have made this node a leaf to begin with so we
+         * should never reach here.
+         * But since it's so simple to handle this, let's do it just in case we
+         * change this rule.
+         */
+        lp->skip = 0;
+    } else {
+        lp->skip += p[valid_ptr].skip;
+    }
+}
+
+static void phys_page_compact_all(AddressSpaceDispatch *d, int nodes_nb)
+{
+    DECLARE_BITMAP(compacted, nodes_nb);
+    int i;
+
+    return;
+
+    for (i = 0; i < next_map.nodes_nb; ++i) {
+        if (d->phys_map.skip) {
+            phys_page_compact(&d->phys_map, d->nodes, compacted);
+        }
+    }
+}
+
 static MemoryRegionSection *phys_page_find(PhysPageEntry lp, hwaddr index,
                                            Node *nodes, MemoryRegionSection *sections)
 {
@@ -1659,6 +1728,8 @@  static void mem_commit(MemoryListener *listener)
     next->nodes = next_map.nodes;
     next->sections = next_map.sections;
 
+    phys_page_compact_all(next, next_map.nodes_nb);
+
     as->dispatch = next;
     g_free(cur);
 }