Doh!
On Friday 20 September 2013 16:29:25 Marek Olšák wrote: > I think your implementation of dmesg logging isn't correct. Note that > dmesg is a ring buffer; once it's full, new lines added at the end of > dmesg will cause the lines at the beginning to disappear. That's why I > had to find and save the timestamp string, and find its position again > in a new dmesg log. > > Marek > > On Wed, Sep 18, 2013 at 11:17 PM, Dylan Baker <[email protected]> wrote: > > On Wednesday 18 September 2013 14:16:11 you wrote: > >> From: Marek Olšák <[email protected]> > >> > >> The Radeon driver writes GPU page faults to dmesg and we need to know > >> which > >> test caused them. > >> > >> If there is any change in dmesg during a test run, the test result is > >> changed as follows: > >> * pass -> dmesg-warn > >> * warn -> dmesg-warn > >> * fail -> dmesg-fail > >> Dmesg is captured before and after the test and the difference between > >> the > >> two is stored in the test summary. > >> > >> The piglit-run.py parameter which enables this behavior is --dmesg. It's > >> also recommended to use -c0. > >> > >> v2: - Use a simplified class to read dmesg > >> > >> Signed-off-by: Dylan Baker <[email protected]> > >> --- > >> > >> framework/core.py | 5 +++-- > >> framework/dmesg.py | 48 > >> > >> ++++++++++++++++++++++++++++++++++++++++++++++ > > > > framework/exectest.py | > > > >> 20 ++++++++++++++----- > >> > >> framework/shader_test.py | 4 ++-- > >> framework/summary.py | 26 ++++++++++++++++++------- > >> piglit-run.py | 6 +++++- > >> templates/index.css | 6 +++++- > >> templates/test_result.mako | 7 ++++++- > >> 8 files changed, 103 insertions(+), 19 deletions(-) > >> create mode 100644 framework/dmesg.py > >> > >> diff --git a/framework/core.py b/framework/core.py > >> index 25e84c1..0d7bbde 100644 > >> --- a/framework/core.py > >> +++ b/framework/core.py > >> > >> @@ -362,13 +362,14 @@ class TestrunResult: > >> class Environment: > >> def __init__(self, concurrent=True, execute=True, include_filter=[], > >> > >> - exclude_filter=[], valgrind=False): > >> > >> + exclude_filter=[], valgrind=False, dmesg=False): > >> self.concurrent = concurrent > >> self.execute = execute > >> self.filter = [] > >> self.exclude_filter = [] > >> self.exclude_tests = set() > >> self.valgrind = valgrind > >> > >> + self.dmesg = dmesg > >> > >> """ > >> The filter lists that are read in should be a list of string > >> > >> objects, @@ -446,7 +447,7 @@ class Test: > >> try: > >> status("running") > >> time_start = time.time() > >> > >> - result = self.run(env.valgrind) > >> + result = self.run(env.valgrind, env.dmesg) > >> > >> time_end = time.time() > >> > >> if 'time' not in result: > >> result['time'] = time_end - time_start > >> > >> diff --git a/framework/dmesg.py b/framework/dmesg.py > >> new file mode 100644 > >> index 0000000..659f3eb > >> --- /dev/null > >> +++ b/framework/dmesg.py > >> @@ -0,0 +1,48 @@ > >> +# Copyright (c) 2013 Intel Corporation > >> +# > >> +# Permission is hereby granted, free of charge, to any person obtaining > >> a > >> +# copy of this software and associated documentation files (the > >> "Software"), +# to deal in the Software without restriction, including > >> without limitation +# the rights to use, copy, modify, merge, publish, > >> distribute, sublicense, +# and/or sell copies of the Software, and to > >> permit persons to whom the +# Software is furnished to do so, subject to > >> the following conditions: +# > >> +# The above copyright notice and this permission notice (including the > >> next +# paragraph) shall be included in all copies or substantial > >> portions of the +# Software. > >> +# > >> +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > >> EXPRESS > >> OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > >> MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. > >> IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY > >> CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, > >> TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE > >> SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. > >> + > >> + > >> +import subprocess > >> + > >> + > >> +class Dmesg(object): > >> + def __init__(self): > >> + self.index = 0 > >> + self.__update_dmesg() > >> + > >> + def __call__(self): > >> + """ > >> + Calling dmesg updates the object by running the dmesg command > >> again. It + then returns either a populated list with the changes, > >> or an empty list + """ > >> + self.__update_dmesg() > >> + return self.contents > >> + > >> + def __update_dmesg(self): > >> + """ > >> + Call dmesg and store the output. > >> + Track the element index number, and only return entries new than > >> that + index. > >> + """ > >> + proc = subprocess.Popen(['dmesg'], stdout=subprocess.PIPE) > >> + dmesg = proc.communicate()[0].rstrip('\n').split('\n') > >> + self.contents = dmesg[self.index:] > >> + self.index = len(dmesg) > >> diff --git a/framework/exectest.py b/framework/exectest.py > >> index 6ee550c..c604f86 100644 > >> --- a/framework/exectest.py > >> +++ b/framework/exectest.py > >> @@ -27,6 +27,7 @@ import shlex > >> > >> import types > >> > >> from core import Test, testBinDir, TestResult > >> > >> +from dmesg import Dmesg > >> > >> # Platform global variables > >> > >> @@ -36,7 +37,7 @@ else: > >> PIGLIT_PLATFORM = '' > >> > >> -# ExecTest: A shared base class for tests that simply run an executable. > >> +# ExecTest: A shared base class for tests that simply runs an > >> executable. > >> > >> class ExecTest(Test): > >> def __init__(self, command): > >> Test.__init__(self) > >> > >> @@ -49,11 +50,11 @@ class ExecTest(Test): > >> self.skip_test = self.check_for_skip_scenario(command) > >> > >> - def interpretResult(self, out, returncode, results): > >> > >> + def interpretResult(self, out, returncode, results, dmesg): > >> raise NotImplementedError > >> return out > >> > >> - def run(self, valgrind): > >> > >> + def run(self, valgrind, dmesg): > >> """ > >> Run a test. The return value will be a dictionary with keys > >> including 'result', 'info', 'returncode' and 'command'. > >> > >> @@ -81,6 +82,7 @@ class ExecTest(Test): > >> err = "" > >> returncode = None > >> > >> else: > >> + dmesg = Dmesg() > >> > >> (out, err, returncode) = \ > >> > >> self.get_command_result(command, fullenv) > >> > >> @@ -117,7 +119,7 @@ class ExecTest(Test): > >> results['result'] = 'skip' > >> > >> else: > >> results['result'] = 'fail' > >> > >> - out = self.interpretResult(out, returncode, results) > >> + out = self.interpretResult(out, returncode, results, > >> dmesg)>> > >> crash_codes = [ > >> > >> # Unix: terminated by a signal > >> > >> @@ -161,6 +163,7 @@ class ExecTest(Test): > >> err, out) > >> > >> results['returncode'] = returncode > >> results['command'] = ' '.join(self.command) > >> > >> + results['dmesg'] = dmesg.contents > >> > >> self.handleErr(results, err) > >> > >> @@ -217,11 +220,18 @@ class PlainExecTest(ExecTest): > >> # Prepend testBinDir to the path. > >> self.command[0] = testBinDir + self.command[0] > >> > >> - def interpretResult(self, out, returncode, results): > >> > >> + def interpretResult(self, out, returncode, results, dmesg): > >> outlines = out.split('\n') > >> outpiglit = map(lambda s: s[7:], > >> > >> filter(lambda s: s.startswith('PIGLIT:'), > >> > >> outlines)) > >> > >> + # Using the __call__ method here returns either an empty list, > >> or a + # list with the relevant dmesg entries > >> + if dmesg(): > >> + outpiglit = map(lambda s: s.replace("'pass'", > >> "'dmesg-warn'"), > >> outpiglit) + outpiglit = map(lambda s: s.replace("'warn'", > >> "'dmesg-warn'"), outpiglit) + outpiglit = map(lambda s: > >> s.replace("'fail'", "'dmesg-fail'"), outpiglit) + > >> > >> if len(outpiglit) > 0: > >> try: > >> for piglit in outpiglit: > >> diff --git a/framework/shader_test.py b/framework/shader_test.py > >> index b80af24..c91c22e 100755 > >> --- a/framework/shader_test.py > >> +++ b/framework/shader_test.py > >> > >> @@ -243,7 +243,7 @@ class ShaderTest(PlainExecTest): > >> self.__command = [runner] + self.__shader_runner_args > >> return self.__command > >> > >> - def run(self, valgrind=False): > >> > >> + def run(self, valgrind=False, dmesg=False): > >> """ Parse the test file's [require] block to determine which > >> executable is needed to run the test. Then run the executable on > >> > >> the test file.""" > >> > >> @@ -259,7 +259,7 @@ class ShaderTest(PlainExecTest): > >> # parsing the test file discovered an error. > >> return self.__result > >> > >> - return PlainExecTest.run(self, valgrind) > >> + return PlainExecTest.run(self, valgrind, dmesg) > >> > >> def _usage_error(): > >> diff --git a/framework/summary.py b/framework/summary.py > >> index 1cdbab7..5ce327c 100644 > >> --- a/framework/summary.py > >> +++ b/framework/summary.py > >> > >> @@ -325,10 +325,14 @@ class Summary: > >> return 2 > >> > >> elif status == 'warn': > >> return 3 > >> > >> - elif status == 'fail': > >> > >> + elif status == 'dmesg-warn': > >> return 4 > >> > >> - elif status == 'crash': > >> > >> + elif status == 'fail': > >> return 5 > >> > >> + elif status == 'dmesg-fail': > >> + return 6 > >> + elif status == 'crash': > >> + return 7 > >> > >> openGroup('fake') > >> openGroup('all') > >> > >> @@ -421,12 +425,16 @@ class Summary: > >> return 1 > >> > >> elif status == 'warn': > >> return 2 > >> > >> - elif status == 'fail': > >> > >> + elif status == 'dmesg-warn': > >> return 3 > >> > >> - elif status == 'skip': > >> > >> + elif status == 'fail': > >> return 4 > >> > >> - elif status == 'crash': > >> > >> + elif status == 'dmesg-fail': > >> return 5 > >> > >> + elif status == 'skip': > >> + return 6 > >> + elif status == 'crash': > >> + return 7 > >> > >> elif status == 'special': > >> return 0 > >> > >> @@ -450,7 +458,7 @@ class Summary: > >> # If the result contains a value other than 1 (pass) > >> or > >> > >> 4 # (skip) it is a problem. Skips are not problems becasuse # they have > >> Their own page. > >> - if [i for e in [2, 3, 5] for i in status if e is i]: > >> + if [i for e in [2, 3, 4, 5, 7] for i in status if e > >> is > >> i]: self.tests['problems'].append(test) > >> > >> if 'skipped' in lists: > >> @@ -480,7 +488,8 @@ class Summary: > >> Private: Find the total number of pass, fail, crash, skip, and > >> warn > >> > >> in the *last* set of results stored in self.results. > >> > >> """ > >> > >> - self.totals = {'pass': 0, 'fail': 0, 'crash': 0, 'skip': 0, > >> 'warn': 0} + self.totals = {'pass': 0, 'fail': 0, 'crash': 0, > >> 'skip': 0, 'warn': 0, + 'dmesg-warn': 0, > >> 'dmesg-fail': 0}>> > >> for test in self.results[-1].tests.values(): > >> self.totals[test['result']] += 1 > >> > >> @@ -547,6 +556,7 @@ class Summary: > >> info=value.get('info', 'None'), > >> traceback=value.get('traceback', 'None'), > >> command=value.get('command', 'None'), > >> > >> + dmesg=value.get('dmesg', 'None'), > >> > >> css=path.relpath(resultCss, tPath), > >> index=path.relpath(index, tPath))) > >> > >> file.close() > >> > >> @@ -625,6 +635,8 @@ class Summary: > >> print " crash: %d" % self.totals['crash'] > >> print " skip: %d" % self.totals['skip'] > >> print " warn: %d" % self.totals['warn'] > >> > >> + print " dmesg-warn: %d" % self.totals['dmesg-warn'] > >> + print " dmesg-fail: %d" % self.totals['dmesg-fail'] > >> > >> if self.tests['changes']: > >> print " changes: %d" % len(self.tests['changes']) > >> print " fixes: %d" % len(self.tests['fixes']) > >> > >> diff --git a/piglit-run.py b/piglit-run.py > >> index 33318d4..7e99791 100755 > >> --- a/piglit-run.py > >> +++ b/piglit-run.py > >> > >> @@ -72,6 +72,9 @@ def main(): > >> parser.add_argument("--valgrind", > >> > >> action="store_true", > >> help="Run tests in valgrind's memcheck") > >> > >> + parser.add_argument("--dmesg", > >> + action="store_true", > >> + help="Capture a difference in dmesg before and > >> after each test") parser.add_argument("testProfile", > >> > >> metavar="<Path to test profile>", > >> help="Path to testfile to run") > >> > >> @@ -108,7 +111,8 @@ def main(): > >> exclude_filter=args.exclude_tests, > >> include_filter=args.include_tests, > >> execute=args.execute, > >> > >> - valgrind=args.valgrind) > >> + valgrind=args.valgrind, > >> + dmesg=args.dmesg) > >> > >> # Change working directory to the root of the piglit directory > >> piglit_dir = path.dirname(path.realpath(sys.argv[0])) > >> > >> diff --git a/templates/index.css b/templates/index.css > >> index 875333f..577370c 100644 > >> --- a/templates/index.css > >> +++ b/templates/index.css > >> @@ -36,7 +36,7 @@ td:first-child > div { > >> > >> background-color: #c8c838 > >> > >> } > >> > >> -td.skip, td.warn, td.fail, td.pass, td.trap, td.abort, td.crash { > >> +td.skip, td.warn, td.fail, td.pass, td.trap, td.abort, td.crash, > >> td.dmesg-warn, td.dmesg-fail { text-align: right; > >> > >> } > >> > >> @@ -59,9 +59,13 @@ tr:nth-child(even) td.skip { background-color: > >> #a0a0a0; > >> } > >> > >> tr:nth-child(odd) td.warn { background-color: #ff9020; } > >> tr:nth-child(even) td.warn { background-color: #ef8010; } > >> > >> +tr:nth-child(odd) td.dmesg-warn { background-color: #ff9020; } > >> +tr:nth-child(even) td.dmesg-warn { background-color: #ef8010; } > >> > >> tr:nth-child(odd) td.fail { background-color: #ff2020; } > >> tr:nth-child(even) td.fail { background-color: #e00505; } > >> > >> +tr:nth-child(odd) td.dmesg-fail { background-color: #ff2020; } > >> +tr:nth-child(even) td.dmesg-fail { background-color: #e00505; } > >> > >> tr:nth-child(odd) td.trap { background-color: #111111; } > >> tr:nth-child(even) td.trap { background-color: #000000; } > >> > >> diff --git a/templates/test_result.mako b/templates/test_result.mako > >> index 410dbb4..b23fb8e 100644 > >> --- a/templates/test_result.mako > >> +++ b/templates/test_result.mako > >> @@ -46,7 +46,12 @@ > >> > >> <pre>${traceback}</pre> > >> > >> </td> > >> > >> </tr> > >> > >> - > >> + <tr> > >> + <td>dmesg</td> > >> + <td> > >> + <pre>${dmesg}</pre> > >> + </td> > >> + </tr> > >> > >> </table> > >> <p><a href="${index}">Back to summary</a></p> > >> > >> </body> > > > > So I got bored last night and implemented a class as I'd suggested. I like > > it, but you're free to ignore it.
signature.asc
Description: This is a digitally signed message part.
_______________________________________________ Piglit mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/piglit
