[Mesa-dev] glapi/gen: Create optimized glX opcode dispatch tree

Stefan Bruens stefan.bruens at rwth-aachen.de
Fri Mar 8 12:45:39 PST 2013


The current code omits some possibilities to optimize the tree, leading
to a large tree with way to many steps until the leaf is reached.

The new code optimizes the tree based on a simple observation: as long
as at most half of the nodes at the current level are leaves, tree size
is reduced or unchanged when the children are pulled up one level.

Tree depth is halved on average (for some leaves, reduced from 9 to 3),
tree size is reduced slightly.

The algorithm works as follows:
1. create leaves, each containing min_op_count opcodes
2. create a binary tree
3. pullup children, as long as there are children and tree size is reduced
3.1. do the same for each non-leaf child

The pullup algorithm has one tunable, "pullup_bias". If set to 0, the
algorithm is followed strictly, if set to values larger 0, some more
children are pulled up, reducing depth in favor of slightly increased size.

Signed-off-by: Stefan Brüns <stefan.bruens at rwth-aachen.de>
---
 src/mapi/glapi/gen/glX_server_table.py |   76 
++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/src/mapi/glapi/gen/glX_server_table.py 
b/src/mapi/glapi/gen/glX_server_table.py
index 47aa111..5c48fc1 100644
--- a/src/mapi/glapi/gen/glX_server_table.py
+++ b/src/mapi/glapi/gen/glX_server_table.py
@@ -65,6 +65,8 @@ class function_table:
         # Minimum number of opcodes in a leaf node.
         self.min_op_bits = 3
         self.min_op_count = (1 << self.min_op_bits)
+
+        self.pullup_bias = 1
         return
 
 
@@ -84,6 +86,80 @@ class function_table:
         return
 
 
+    def get_leaves(self):
+        leaves = []
+
+        for i in range(0, (1<<self.max_bits), self.min_op_count):
+
+            # M, [children], tree size, depth, type, first opcode
+            leaf = [ 0, [], 1, 0, 'E', i ]
+
+            for j in range(i, i + self.min_op_count):
+                if self.functions.has_key(j):
+                    leaf[4] = 'L'
+                    break;
+
+            leaves.append(leaf)
+
+        return leaves
+
+
+    def combine_tree(self, nodes):
+        newnodes = []
+
+        for i in range(0, len(nodes)-1, 2):
+            c1 = nodes[i]
+            c2 = nodes[i+1]
+            parent = [ 1, [c1, c2], c1[2]+c2[2]+1, 0, 'N', c1[5] ]
+            if c1[4] == c2[4]:
+                parent[4] = c1[4]
+
+            newnodes.append(parent)
+
+        if len(newnodes) >= 2:
+            return self.combine_tree(newnodes)
+
+        return parent
+
+
+    def pullup_nodes(self, node):
+
+        children = node[1]
+
+        # Count non-leaves. If at least half of the children
+        # are non-leaves pulling up saves space. Add a small
+        # bias to favor shallower trees
+        count = sum( 1 for child in children if child[4] == 'N' )
+        count += self.pullup_bias
+
+        # conditionally replace the children of a node with its
+        # grandchildren. Grandchildren exist if child size > 1
+        if count >= len(children)/2 and children[0][2] > 1:
+            newnodes = []
+            for child in children:
+                newnodes.append(child[1][0])
+                newnodes.append(child[1][1])
+
+            node[0] += 1
+            node[1] = newnodes
+            node[2] = newnodes[0][2] * len(newnodes) + 1
+            self.pullup_nodes(node)
+
+        else:
+            node[2] = 1
+            for child in children:
+                if child[4] == 'N':
+                    self.pullup_nodes(child)
+                else:
+                    child[1] = []
+                    child[2] = 1
+
+                node[3] = max( child[3] + 1, node[3] )
+                node[2] += child[2]
+
+        return
+
+
     def divide_group(self, min_opcode, total):
         """Divide the group starting min_opcode into subgroups.
         Returns a tuple containing the number of bits consumed by
-- 
1.7.10.4



More information about the mesa-dev mailing list