[Piglit] [PATCH 20/35] profile: Add support for loading xml based profiles
Dylan Baker
dylan at pnwbakers.com
Wed Apr 4 22:27:08 UTC 2018
Which includes de-serialization on demand. This will vastly reduce the
amount of resident memory that is necessary to hold the tests since test
instances are made on demand, and can be garbage collected as soon as
the run in complete.
---
framework/profile.py | 108 +++++++++++++++++++++++++++++-
unittests/framework/test_profile.py | 5 +-
2 files changed, 108 insertions(+), 5 deletions(-)
diff --git a/framework/profile.py b/framework/profile.py
index 925271e..7b1b41b 100644
--- a/framework/profile.py
+++ b/framework/profile.py
@@ -30,15 +30,18 @@ tests, and the Test instance.
from __future__ import (
absolute_import, division, print_function, unicode_literals
)
+import ast
import collections
import contextlib
import copy
import importlib
+import io
import itertools
import multiprocessing
import multiprocessing.dummy
import os
import re
+import xml.etree.cElementTree as et
import six
@@ -47,6 +50,12 @@ from framework.dmesg import get_dmesg
from framework.log import LogManager
from framework.monitoring import Monitoring
from framework.test.base import Test, DummyTest
+from framework.test.piglit_test import (
+ PiglitCLTest, PiglitGLTest, ASMParserTest, BuiltInConstantsTest,
+ CLProgramTester, ROOT_DIR,
+)
+from framework.test.shader_test import ShaderTest, MultiShaderTest
+from framework.test.glsl_parser_test import GLSLParserTest
__all__ = [
'RegexFilter',
@@ -256,6 +265,100 @@ class TestDict(collections.MutableMapping):
self.__allow_reassignment -= 1
+def make_test(element):
+ """Rebuild a test instance from xml."""
+ def process(elem, opt):
+ k = elem.attrib['name']
+ v = elem.attrib['value']
+ try:
+ opt[k] = ast.literal_eval(v)
+ except ValueError:
+ opt[k] = v
+
+ type_ = element.attrib['type']
+ options = {}
+ for e in element.findall('./option'):
+ process(e, options)
+
+ if type_ == 'gl':
+ return PiglitGLTest(**options)
+ if type_ == 'gl_builtin':
+ return BuiltInConstantsTest(**options)
+ if type_ == 'cl':
+ return PiglitCLTest(**options)
+ if type_ == 'cl_prog':
+ return CLProgramTester(**options)
+ if type_ == 'shader':
+ return ShaderTest(**options)
+ if type_ == 'glsl_parser':
+ return GLSLParserTest(**options)
+ if type_ == 'asm_parser':
+ return ASMParserTest(**options)
+ if type_ == 'multi_shader':
+ options['skips'] = []
+ for e in element.findall('./Skips/Skip/option'):
+ skips = {}
+ process(e, skips)
+ options['skips'].append(skips)
+ return MultiShaderTest(**options)
+ raise Exception('Unreachable')
+
+
+class XMLProfile(object):
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.forced_test_list = []
+ self.filters = []
+ self.options = {
+ 'dmesg': get_dmesg(False),
+ 'monitor': Monitoring(False),
+ 'ignore_missing': False,
+ }
+
+ def __len__(self):
+ if not (self.filters or self.forced_test_list):
+ with io.open(self.filename, 'rt') as f:
+ iter_ = et.iterparse(f, events=(b'start', ))
+ for _, elem in iter_:
+ if elem.tag == 'PiglitTestList':
+ return int(elem.attrib['count'])
+ return sum(1 for _ in self.itertests())
+
+ def setup(self):
+ pass
+
+ def teardown(self):
+ pass
+
+ def _itertests(self):
+ """Always iterates tests instead of using the forced test_list."""
+ with io.open(self.filename, 'rt') as f:
+ doc = et.iterparse(f, events=(b'end', ))
+ _, root = next(doc) # get the root so we can keep clearing it
+ for _, e in doc:
+ if e.tag != 'Test':
+ continue
+ k = e.attrib['name']
+ v = make_test(e)
+ if all(f(k, v) for f in self.filters):
+ yield k, v
+ root.clear()
+
+ def itertests(self):
+ if self.forced_test_list:
+ alltests = dict(self._itertests())
+ opts = collections.OrderedDict()
+ for n in self.forced_test_list:
+ if self.options['ignore_missing'] and n not in alltests:
+ opts[n] = DummyTest(n, status.NOTRUN)
+ else:
+ opts[n] = alltests[n]
+ return six.iteritems(opts)
+ else:
+ return iter(self._itertests())
+
+
class TestProfile(object):
"""Class that holds a list of tests for execution.
@@ -347,6 +450,11 @@ def load_test_profile(filename):
Arguments:
filename -- the name of a python module to get a 'profile' from
"""
+ name = os.path.splitext(os.path.basename(filename))[0]
+ xml = os.path.join(ROOT_DIR, 'tests', name + '.xml')
+ if os.path.exists(xml):
+ return XMLProfile(xml)
+
try:
mod = importlib.import_module('tests.{0}'.format(
os.path.splitext(os.path.basename(filename))[0]))
diff --git a/unittests/framework/test_profile.py b/unittests/framework/test_profile.py
index d86db1b..714f7e0 100644
--- a/unittests/framework/test_profile.py
+++ b/unittests/framework/test_profile.py
@@ -61,11 +61,6 @@ class TestLoadTestProfile(object):
with pytest.raises(exceptions.PiglitFatalError):
profile.load_test_profile('this_module_will_never_ever_exist')
- def test_return_type(self):
- """profile.load_test_profile: returns a TestProfile instance."""
- assert isinstance(profile.load_test_profile('sanity'),
- profile.TestProfile)
-
class TestTestProfile(object):
"""Tests for profile.TestProfile."""
--
git-series 0.9.1
More information about the Piglit
mailing list