[Mesa-dev] [PATCH 6/8] radeonsi/sid_tables: store strings by offset instead of by pointer

Nicolai Hähnle nhaehnle at gmail.com
Mon May 9 16:32:25 UTC 2016


From: Nicolai Hähnle <nicolai.haehnle at amd.com>

This saves some space and avoids the need for relocations.
---
 src/gallium/drivers/radeonsi/si_debug.c    |  22 +++--
 src/gallium/drivers/radeonsi/sid_tables.py | 147 +++++++++++++++++++++++++----
 2 files changed, 141 insertions(+), 28 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_debug.c b/src/gallium/drivers/radeonsi/si_debug.c
index 3ddabab..b8a1461 100644
--- a/src/gallium/drivers/radeonsi/si_debug.c
+++ b/src/gallium/drivers/radeonsi/si_debug.c
@@ -187,13 +187,14 @@ static void si_dump_reg(FILE *file, unsigned offset, uint32_t value,
 
 	for (r = 0; r < ARRAY_SIZE(reg_table); r++) {
 		const struct si_reg *reg = &reg_table[r];
+		const char *reg_name = sid_strings + reg->name_offset;
 
 		if (reg->offset == offset) {
 			bool first_field = true;
 
 			print_spaces(file, INDENT_PKT);
 			fprintf(file, COLOR_YELLOW "%s" COLOR_RESET " <- ",
-				reg->name);
+				reg_name);
 
 			if (!reg->num_fields) {
 				print_value(file, value, 32);
@@ -202,6 +203,7 @@ static void si_dump_reg(FILE *file, unsigned offset, uint32_t value,
 
 			for (f = 0; f < reg->num_fields; f++) {
 				const struct si_field *field = &reg->fields[f];
+				const int *values_offsets = sid_strings_offsets + field->values_offset;
 				uint32_t val = (value & field->mask) >>
 					       (ffs(field->mask) - 1);
 
@@ -211,13 +213,13 @@ static void si_dump_reg(FILE *file, unsigned offset, uint32_t value,
 				/* Indent the field. */
 				if (!first_field)
 					print_spaces(file,
-						     INDENT_PKT + strlen(reg->name) + 4);
+						     INDENT_PKT + strlen(reg_name) + 4);
 
 				/* Print the field. */
-				fprintf(file, "%s = ", field->name);
+				fprintf(file, "%s = ", sid_strings + field->name_offset);
 
-				if (val < field->num_values && field->values[val])
-					fprintf(file, "%s\n", field->values[val]);
+				if (val < field->num_values && values_offsets[val] >= 0)
+					fprintf(file, "%s\n", sid_strings + values_offsets[val]);
 				else
 					print_value(file, val,
 						    util_bitcount(field->mask));
@@ -254,17 +256,19 @@ static uint32_t *si_parse_packet3(FILE *f, uint32_t *ib, int *num_dw,
 		if (packet3_table[i].op == op)
 			break;
 
-	if (i < ARRAY_SIZE(packet3_table))
+	if (i < ARRAY_SIZE(packet3_table)) {
+		const char *name = sid_strings + packet3_table[i].name_offset;
+
 		if (op == PKT3_SET_CONTEXT_REG ||
 		    op == PKT3_SET_CONFIG_REG ||
 		    op == PKT3_SET_UCONFIG_REG ||
 		    op == PKT3_SET_SH_REG)
 			fprintf(f, COLOR_CYAN "%s%s" COLOR_CYAN ":\n",
-				packet3_table[i].name, predicate);
+				name, predicate);
 		else
 			fprintf(f, COLOR_GREEN "%s%s" COLOR_RESET ":\n",
-				packet3_table[i].name, predicate);
-	else
+				name, predicate);
+	} else
 		fprintf(f, COLOR_RED "PKT3_UNKNOWN 0x%x%s" COLOR_RESET ":\n",
 			op, predicate);
 
diff --git a/src/gallium/drivers/radeonsi/sid_tables.py b/src/gallium/drivers/radeonsi/sid_tables.py
index 1fe5d3c..59954c5 100755
--- a/src/gallium/drivers/radeonsi/sid_tables.py
+++ b/src/gallium/drivers/radeonsi/sid_tables.py
@@ -30,6 +30,103 @@ import sys
 import re
 
 
+class StringTable:
+    """
+    A class for collecting multiple strings in a single larger string that is
+    used by indexing (to avoid relocations in the resulting binary)
+    """
+    def __init__(self):
+        self.table = []
+        self.length = 0
+
+    def add(self, string):
+        # We might get lucky with string being a suffix of a previously added string
+        for te in self.table:
+            if te[0].endswith(string):
+                idx = te[1] + len(te[0]) - len(string)
+                te[2].add(idx)
+                return idx
+
+        idx = self.length
+        self.table.append((string, idx, set((idx,))))
+        self.length += len(string) + 1
+
+        return idx
+
+    def emit(self, filp, name, static=True):
+        """
+        Write
+        [static] const char name[] = "...";
+        to filp.
+        """
+        fragments = [
+            '"%s\\0" /* %s */' % (
+                te[0].encode('string_escape'),
+                ', '.join(str(idx) for idx in te[2])
+            )
+            for te in self.table
+        ]
+        filp.write('%sconst char %s[] =\n%s;\n' % (
+            'static ' if static else '',
+            name,
+            '\n'.join('\t' + fragment for fragment in fragments)
+        ))
+
+class IntTable:
+    """
+    A class for collecting multiple arrays of integers in a single big array
+    that is used by indexing (to avoid relocations in the resulting binary)
+    """
+    def __init__(self, typename):
+        self.typename = typename
+        self.table = []
+        self.idxs = set()
+
+    def add(self, array):
+        # We might get lucky and find the array somewhere in the existing data
+        try:
+            idx = 0
+            while True:
+                idx = self.table.index(array[0], idx, len(self.table) - len(array) + 1)
+
+                for i in range(1, len(array)):
+                    if array[i] != self.table[idx + i]:
+                        break
+                else:
+                    self.idxs.add(idx)
+                    return idx
+
+                idx += 1
+        except ValueError:
+            pass
+
+        idx = len(self.table)
+        self.table += array
+        self.idxs.add(idx)
+        return idx
+
+    def emit(self, filp, name, static=True):
+        """
+        Write
+        [static] const typename name[] = { ... };
+        to filp.
+        """
+        idxs = sorted(self.idxs) + [-1]
+
+        fragments = [
+            ('\t/* %s */ %s' % (
+                idxs[i],
+                ' '.join((str(elt) + ',') for elt in self.table[idxs[i]:idxs[i+1]])
+            ))
+            for i in range(len(idxs) - 1)
+        ]
+
+        filp.write('%sconst %s %s[] = {\n%s\n};\n' % (
+            'static ' if static else '',
+            self.typename, name,
+            '\n'.join(fragments)
+        ))
+
 class Field:
     def __init__(self, reg, s_name):
         self.s_name = s_name
@@ -71,7 +168,8 @@ def parse(filename):
             reg.fields.append(field)
 
         elif line.startswith('V_'):
-            field.values.append(line.split()[0])
+            split = line.split()
+            field.values.append((split[0], int(split[1], 0)))
 
         elif line.startswith('PKT3_') and line.find('0x') != -1 and line.find('(') == -1:
             packets.append(line.split()[0])
@@ -103,6 +201,9 @@ def write_tables(tables):
     regs = tables[0]
     packets = tables[1]
 
+    strings = StringTable()
+    strings_offsets = IntTable("int")
+
     print '/* This file is autogenerated by sid_tables.py from sid.h. Do not edit directly. */'
     print
     print CopyRight.strip()
@@ -111,60 +212,66 @@ def write_tables(tables):
 #define SID_TABLES_H
 
 struct si_field {
-        const char *name;
+        unsigned name_offset;
         unsigned mask;
         unsigned num_values;
-        const char **values;
+        unsigned values_offset; /* offset into sid_strings_offsets */
 };
 
 struct si_reg {
-        const char *name;
+        unsigned name_offset;
         unsigned offset;
         unsigned num_fields;
         const struct si_field *fields;
 };
 
 struct si_packet3 {
-        const char *name;
+        unsigned name_offset;
         unsigned op;
 };
 '''
 
     print 'static const struct si_packet3 packet3_table[] = {'
     for pkt in packets:
-        print '\t{"%s", %s},' % (pkt[5:], pkt)
+        print '\t{%s, %s},' % (strings.add(pkt[5:]), pkt)
     print '};'
     print
 
     for reg in regs:
         if len(reg.fields) and reg.own_fields:
-            for field in reg.fields:
-                if len(field.values):
-                    print 'static const char *%s[] = {' % (field.varname_values)
-                    for value in field.values:
-                        print '\t[%s] = "%s",' % (value, strip_prefix(value))
-                    print '};'
-                    print
-
             print 'static const struct si_field %s[] = {' % (reg.varname_fields)
             for field in reg.fields:
                 if len(field.values):
-                    print '\t{"%s", %s(~0u), ARRAY_SIZE(%s), %s},' % (field.name,
-                        field.s_name, field.varname_values, field.varname_values)
+                    values_offsets = []
+                    for value in field.values:
+                        while value[1] >= len(values_offsets):
+                            values_offsets.append(-1)
+                        values_offsets[value[1]] = strings.add(strip_prefix(value[0]))
+                    print '\t{%s, %s(~0u), %s, %s},' % (
+                        strings.add(field.name), field.s_name,
+                        len(values_offsets), strings_offsets.add(values_offsets))
                 else:
-                    print '\t{"%s", %s(~0u)},' % (field.name, field.s_name)
+                    print '\t{%s, %s(~0u)},' % (strings.add(field.name), field.s_name)
             print '};'
             print
 
     print 'static const struct si_reg reg_table[] = {'
     for reg in regs:
         if len(reg.fields):
-            print '\t{"%s", %s, ARRAY_SIZE(%s), %s},' % (reg.name, reg.r_name,
+            print '\t{%s, %s, ARRAY_SIZE(%s), %s},' % (strings.add(reg.name), reg.r_name,
                 reg.varname_fields, reg.varname_fields)
         else:
-            print '\t{"%s", %s},' % (reg.name, reg.r_name)
+            print '\t{%s, %s},' % (strings.add(reg.name), reg.r_name)
     print '};'
     print
+
+    strings.emit(sys.stdout, "sid_strings")
+
+    print
+
+    strings_offsets.emit(sys.stdout, "sid_strings_offsets")
+
+    print
     print '#endif'
 
 
@@ -177,3 +284,5 @@ def main():
 
 if __name__ == '__main__':
     main()
+
+# kate: space-indent on; indent-width 4; replace-tabs on;
-- 
2.7.4



More information about the mesa-dev mailing list