[Piglit] [PATCH 2/2] summary.py: Replace buildDictionary function with a much simpler method

Dylan Baker baker.dylan.c at gmail.com
Tue Oct 15 14:28:49 CEST 2013


This patch produces the exact same output as the previous approach, just
in a much simpler way. It also moves some more of the status information
out of if branches and into the Status class in the status module.

Signed-off-by: Dylan Baker <baker.dylan.c at gmail.com>
---
 framework/status.py  |   6 ++-
 framework/summary.py | 143 ++++++++++++++-------------------------------------
 2 files changed, 45 insertions(+), 104 deletions(-)

diff --git a/framework/status.py b/framework/status.py
index a265317..2fe153e 100644
--- a/framework/status.py
+++ b/framework/status.py
@@ -104,10 +104,11 @@ class Status(object):
 
     # Using __slots__ allows us to implement the flyweight pattern, limiting
     # the memory consumed for creating tens of thousands of these objects.
-    __slots__ = ['name', 'value']
+    __slots__ = ['name', 'value', 'fraction']
 
     name = None
     value = None
+    fraction = (0, 1)
 
     def __init__(self):
         raise NotImplementedError
@@ -149,6 +150,7 @@ class Status(object):
 class NotRun(Status):
     name = 'Not Run'
     value = 0
+    fraction = (0, 0)
 
     def __init__(self):
         pass
@@ -157,6 +159,7 @@ class NotRun(Status):
 class Pass(Status):
     name = 'pass'
     value = 10
+    fraction = (1, 1)
 
     def __init__(self):
         pass
@@ -205,6 +208,7 @@ class Crash(Status):
 class Skip(Status):
     name = 'skip'
     value = 50
+    fraction = (0, 0)
 
     def __init__(self):
         pass
diff --git a/framework/summary.py b/framework/summary.py
index 31c1c26..4f983bf 100644
--- a/framework/summary.py
+++ b/framework/summary.py
@@ -25,12 +25,14 @@ import string
 from itertools import izip_longest
 from shutil import copy
 from json import loads
+import collections
 from mako.template import Template
 
-import core
 # a local variable status exists, prevent accidental overloading by renaming
 # the module
 import status as so
+import core
+
 
 __all__ = [
     'Summary',
@@ -265,98 +267,6 @@ class Summary:
         piglit-run.
         """
 
-        def buildDictionary(summary):
-            # Build a dictionary from test name to pass count/total count, i.e.
-            # counts['spec/glsl/foo'] == (456, 800)
-            counts = {}
-
-            if not summary.tests:
-                return {}
-
-            lastGroup = ''
-
-            # Build a dictionary of group stati, passing groupname = status.
-            # This is the "worst" status of the group in descending order:
-            # crash, skip, fail, warn, pass
-            status = {}
-
-            # currentStack is a stack containing numerical values that that
-            # relate to a status output, 5 for crash, 4 for skip, 3 for fail, 2
-            # for warn, 1 for pass
-            currentStatus = []
-
-            # Stack contains tuples like: (pass count, total count)
-            stack = []
-
-            def openGroup(name):
-                stack.append((0, 0))
-
-                # Since NotRun is the "lowest" status for HTML generation, if
-                # there is another status it will replace skip
-                currentStatus.append(so.NotRun())
-
-            def closeGroup(group_name):
-                # We're done with this group, record the number of pass/total
-                # in the dictionary.
-                (nr_pass, nr_total) = stack.pop()
-                counts[group_name] = (nr_pass, nr_total)
-
-                # Also add our pass/total count to the parent group's counts
-                # (which are still being computed)
-                (parent_pass, parent_total) = stack[-1]
-                stack[-1] = (parent_pass + nr_pass, parent_total + nr_total)
-
-                # Add the status back to the group hierarchy
-                if currentStatus[-2] < currentStatus[-1]:
-                    currentStatus[-2] = currentStatus[-1]
-                status[group_name] = currentStatus.pop()
-
-            openGroup('fake')
-            openGroup('all')
-
-            # fulltest is a full test name,
-            # i.e. tests/shaders/glsl-algebraic-add-zero
-            for fulltest in sorted(summary.tests):
-                # same as fulltest.rpartition('/')
-                group, test = path.split(fulltest)
-
-                if group != lastGroup:
-                    # We're in a different group now.  Close the old ones
-                    # and open the new ones.
-                    for x in path.relpath(group, lastGroup).split('/'):
-                        if x != '..':
-                            openGroup(x)
-                        else:
-                            closeGroup(lastGroup)
-                            lastGroup = path.normpath(path.join(lastGroup,
-                                                                ".."))
-
-                    lastGroup = group
-
-                # Add the current test
-                (pass_so_far, total_so_far) = stack[-1]
-                if summary.tests[fulltest]['result'] == so.Pass():
-                    pass_so_far += 1
-                if summary.tests[fulltest]['result'] != so.Skip():
-                    total_so_far += 1
-                stack[-1] = (pass_so_far, total_so_far)
-
-                # compare the status
-                if summary.tests[fulltest]['result'] > currentStatus[-1]:
-                    currentStatus[-1] = summary.tests[fulltest]['result']
-
-            # Work back up the stack closing groups as we go until we reach the
-            # top, where we need to manually close this as "all"
-            while len(stack) > 2:
-                closeGroup(lastGroup)
-                lastGroup = path.dirname(lastGroup)
-            closeGroup("all")
-
-            assert(len(stack) == 1)
-            assert(len(currentStatus) == 1)
-
-            return counts, status
-
         # Create a Result object for each piglit result and append it to the
         # results list
         self.results = [Result(i) for i in resultfiles]
@@ -366,16 +276,43 @@ class Summary:
         self.tests = {'all': set(), 'changes': set(), 'problems': set(),
                       'skipped': set(), 'regressions': set(), 'fixes': set()}
 
-        for each in self.results:
-            # Build a dict of the status output of all of the tests, with the
-            # name of the test run as the key for that result, this will be
-            # used to write pull the statuses later
-            fraction, status = buildDictionary(each)
-            self.fractions.update({each.name: fraction})
-            self.status.update({each.name: status})
-
-            # Create a list with all the test names in it
-            self.tests['all'] = set(self.tests['all']) | set(each.tests)
+        for results in self.results:
+            # Create a set of all of the tset names across all of the runs
+            self.tests['all'] = set(self.tests['all'] | set(results.tests))
+
+            # Create two dictionaries that have a default factory: they return
+            # a default value instead of a key error.
+            # This default key must be callable
+            self.fractions[results.name] = collections.defaultdict(lambda: (0, 0))
+            self.status[results.name] = collections.defaultdict(so.NotRun)
+
+            # short names
+            fraction = self.fractions[results.name]
+            status = self.status[results.name]
+
+            for test, value in results.tests.iteritems():
+                result = value['result']
+                #FIXME: Add subtest support
+
+                # Walk the test name as if it was a path, at each level update
+                # the tests passed over the total number of tests (fractions),
+                # and update the status of the current level if the status of
+                # the previous level was worse
+                while True:
+                    fraction[test] = tuple([sum(i) for i in zip(fraction[test],
+                                            result.fraction)])
+                    if result > status[test]:
+                        status[test] = result
+
+                    test = path.dirname(test)
+                    # when we hit the root update the 'all' group and break
+                    if test == '':
+                        fraction['all'] = \
+                            tuple([sum(i) for i in
+                                   zip(fraction['all'], result.fraction)])
+                        if status['all'] < result:
+                            status['all'] = result
+                        break
 
         # Create the lists of statuses like problems, regressions, fixes,
         # changes and skips
-- 
1.8.1.5



More information about the Piglit mailing list