[Piglit] [PATCH 2/3] framework: Add support for a test timeout

Daniel Vetter daniel.vetter at ffwll.ch
Tue Nov 12 02:36:32 PST 2013


i-g-t tests can take a long time, and for a bunch of reasons (bad
tuning on disparate set of platforms, stuck in the kernel which often
can be recovered by interrupting with a signal, ...) that sometimes
extends to a good approximation of forever.

Hence this adds a per-test timeout value and a bit of infrastructure
to adjust the results. Test results adjusting is done after calling
interpretResult so that we don't have to replicate this all over the
place. This might need to be adjusted for the piglit-native subtest
stuff, but otoh igt is a bit special with it's crazy long-running
tests. So I think we can fix this once it's actually needed.

The default timeout is None, so this is purely opt-in.

Note on the implementation: SIG_ALARM doesn't exists on Windows and
stackoverflow overwhelmingly recommended to go with this thread-based
approach here. But only tested on my Linux box here.
---
 framework/exectest.py | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/framework/exectest.py b/framework/exectest.py
index 986d803..32b0062 100644
--- a/framework/exectest.py
+++ b/framework/exectest.py
@@ -23,6 +23,7 @@
 import errno
 import os
 import subprocess
+import threading
 import shlex
 import types
 import re
@@ -72,6 +73,7 @@ class ExecTest(Test):
         self.command = command
         self.split_command = os.path.split(self.command[0])[1]
         self.env = {}
+        self.timeout = None
 
         if isinstance(self.command, basestring):
             self.command = shlex.split(str(self.command))
@@ -113,7 +115,7 @@ class ExecTest(Test):
                 else:
                     if env.dmesg:
                         old_dmesg = read_dmesg()
-                    (out, err, returncode) = \
+                    (out, err, returncode, timeout) = \
                         self.get_command_result(command, fullenv)
                     if env.dmesg:
                         dmesg_diff = get_dmesg_diff(old_dmesg, read_dmesg())
@@ -172,6 +174,9 @@ class ExecTest(Test):
             elif returncode != 0:
                 results['note'] = 'Returncode was {0}'.format(returncode)
 
+            if timeout:
+                results['result'] = 'timeout'
+
             if env.valgrind:
                 # If the underlying test failed, simply report
                 # 'skip' for this valgrind test.
@@ -196,6 +201,7 @@ class ExecTest(Test):
             results['returncode'] = returncode
             results['command'] = ' '.join(self.command)
             results['dmesg'] = dmesg_diff
+            results['timeout'] = timeout
 
             self.handleErr(results, err)
 
@@ -222,7 +228,23 @@ class ExecTest(Test):
                                     stderr=subprocess.PIPE,
                                     env=fullenv,
                                     universal_newlines=True)
-            out, err = proc.communicate()
+            out = ''
+            err = ''
+
+            def thread_fn():
+                out, err = proc.communicate()
+
+            thread = threading.Thread(target=thread_fn)
+            thread.start()
+
+            thread.join(self.timeout)
+
+            if thread.is_alive():
+                proc.terminate()
+                thread.join()
+                timeout = True
+            else:
+                timeout = False
             returncode = proc.returncode
         except OSError as e:
             # Different sets of tests get built under
@@ -237,7 +259,7 @@ class ExecTest(Test):
                 returncode = None
             else:
                 raise e
-        return out, err, returncode
+        return out, err, returncode, timeout
 
 
 class PlainExecTest(ExecTest):
-- 
1.8.1.4



More information about the Piglit mailing list