Benefit from recent changes to Mesa master which allows correct reporting
in multi-threaded runs, and generally more robust reporting when comparing
different runs, e.g. that differ in the set of tests that were run.
Parsing also becomes much faster because we (a) do not recompile regexes in
the inner iterations, (b) have fewer lines to parse in total, and (c) are
more selective about when we try to match which regular expression.
While we're at it, parse out S_NOP instructions from the disassembly and
report wait states.
---
README | 4 +-
si-report.py | 208 ++-
2 files changed, 136 insertions(+), 76 deletions(-)
diff --git a/README b/README
index 06294c9..9561c19 100644
--- a/README
+++ b/README
@@ -37,12 +37,10 @@ to run.
=== Running shaders ===
-./run shaders -1 2> new-run
+./run shaders > new-run 2> /dev/null
Note that a debug mesa build required (ie. --enable-debug)
--1 option for disabling multi-threading is required to avoid garbled shader
dumps.
-
=== Analysis ===
./si-report.py old-run new-run
diff --git a/si-report.py b/si-report.py
index ec88112..e4aea40 100755
--- a/si-report.py
+++ b/si-report.py
@@ -23,6 +23,8 @@
# DEALINGS IN THE SOFTWARE.
#
+from collections import defaultdict
+import itertools
import re
import sys
@@ -65,6 +67,10 @@ def get_scratch_str(value, suffixes = True):
suffix = 'bytes per wave'
return get_value_str(value, 'Scratch', suffix)
+def get_waitstates_str(value, suffixes = True):
+suffix = ''
+return get_value_str(value, 'Wait states', suffix)
+
def calculate_percent_change(b, a):
if b == 0:
return 0
@@ -89,15 +95,17 @@ class si_stats:
self.code_size = 0
self.lds = 0
self.scratch = 0
+self.waitstates = 0
def to_string(self, suffixes = True):
-return "{}{}{}{}{}".format(
+return "{}{}{}{}{}{}".format(
get_sgpr_str(self.sgprs, suffixes),
get_vgpr_str(self.vgprs, suffixes),
get_code_size_str(self.code_size, suffixes),
get_lds_str(self.lds, suffixes),
-get_scratch_str(self.scratch, suffixes))
+get_scratch_str(self.scratch, suffixes),
+get_waitstates_str(self.waitstates, suffixes))
def __str__(self):
@@ -109,6 +117,7 @@ class si_stats:
self.code_size += other.code_size
self.lds += other.lds
self.scratch += other.scratch
+self.waitstates += other.waitstates
def update(self, comp, cmp_fn):
for name in self.__dict__.keys():
@@ -153,56 +162,76 @@ class si_stats:
return False
return True
-def get_results(filename):
-file = open(filename, "r")
-lines = file.read().split('\n')
-
-results = []
-current_stats = si_stats()
-
-for line in lines:
-re_start = re.compile("^\*\*\* SHADER STATS \*\*\*$")
-re_sgprs = re.compile("^SGPRS: ([0-9]+)$")
-re_vgprs = re.compile("^VGPRS: ([0-9]+)$")
-re_code_size = re.compile("^Code Size: ([0-9]+) bytes$")
-re_lds = re.compile("^LDS: ([0-9]+) blocks$")
-re_scratch = re.compile("^Scratch: ([0-9]+) bytes per wave$")
-re_end = re.compile("^\*+$")
-
-# First line of stats
-match = re.search(re_start, line)
-if match:
-continue
-match = re.search(re_sgprs, line)
-if match:
-current_stats.sgprs = int(match.groups()[0])
-continue
+class si_parser(object):
+re_stats = re.compile(
+r"^Shader Stats: SGPRS: ([0-9]+) VGPRS: ([0-9]+) Code Size: ([0-9]+) "+
+r"LDS: ([0-9]+) Scratch: ([0-9]+)$")
+re_nop = re.compile("^\ts_nop ([0-9]+)")
-match = re.search(re_vgprs, line)
-if match:
-current_stats.vgprs = int(match.groups()[0])
-continue
-
-match = re.search(re_code_size, line)
-if match:
-current_stats.code_size = int(match.groups()[0])
-continue
-
-match = re.search(re_lds, line)
-if match:
-current_stats.lds = int(match.groups()[0])
-continue
+def __init__(self):
+self._stats = None
+self._in_disasm = False
+
+def finish(self):
+return self._stats
+
+def parse(self, msg):
+if not self._in_disasm:
+if msg == "Shader Disassembly Begin":
+old_stats = self._stats
+self._stats = si_stats()
+self._in_disasm = True
+return old_stats
+
+match = si_parser.re_stats.match(msg)
+if match is not None:
+self._stats.sgprs = int(match.group(1))
+self._stats.vgprs = int(match.group(2))
+self._stats.code_size = int(match.group(3))
+self._stats.lds = int(match.group(4))
+