summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Baker <dylan@pnwbakers.com>2018-03-27 09:48:53 -0700
committerDylan Baker <dylan@pnwbakers.com>2018-05-01 14:30:13 -0700
commit1fd6f243cd853892834a25613e738f877845f57d (patch)
tree54fec694448ce07de47baed6c507eb40b28d1d91
parent7e9d859eb58ba40671c38186a7b79cd37f83e9b0 (diff)
profile: Add support for loading xml based profiles
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. Tested-by: Rafael Antognolli <rafael.antognolli@intel.com>
-rw-r--r--framework/profile.py108
-rw-r--r--unittests/framework/test_profile.py5
2 files changed, 108 insertions, 5 deletions
diff --git a/framework/profile.py b/framework/profile.py
index 925271e82..7b1b41be1 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 d86db1bc5..714f7e05a 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."""