2010-11-19 Dirk Pranke <dpranke@chromium.org>
authordpranke@chromium.org <dpranke@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 20 Nov 2010 01:49:50 +0000 (01:49 +0000)
committerdpranke@chromium.org <dpranke@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 20 Nov 2010 01:49:50 +0000 (01:49 +0000)
        Reviewed by Tony Chang.

        nrwt multiprocessing - add 'worker number' concept, move stuff to worker thread

        Add the 'worker number' and 'worker name' concepts to the
        TestShellThread objects, and move test_types and test_args from
        the TestRunner to the TestShellThread.

        https://bugs.webkit.org/show_bug.cgi?id=49768

        * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@72458 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKitTools/ChangeLog
WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py
WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py

index 3e10a2c919cdd0a1844be0e3564edacb49b57676..7e647934871afd5b0e224b837747895c899e3a20 100644 (file)
@@ -1,3 +1,18 @@
+2010-11-19  Dirk Pranke  <dpranke@chromium.org>
+
+        Reviewed by Tony Chang.
+
+        nrwt multiprocessing - add 'worker number' concept, move stuff to worker thread
+
+        Add the 'worker number' and 'worker name' concepts to the 
+        TestShellThread objects, and move test_types and test_args from
+        the TestRunner to the TestShellThread.
+
+        https://bugs.webkit.org/show_bug.cgi?id=49768
+
+        * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
 2010-11-19  Dirk Pranke  <dpranke@chromium.org>
 
         Reviewed by Ojan Vafai.
index 48dfb16cd9fd10afad7d83d9de6e8045997f1877..af15a82efbe059a841e293fcc5b8f4a80b81e2c4 100644 (file)
@@ -49,6 +49,11 @@ import thread
 import threading
 import time
 
+
+from webkitpy.layout_tests.test_types import image_diff
+from webkitpy.layout_tests.test_types import test_type_base
+from webkitpy.layout_tests.test_types import text_diff
+
 import test_failures
 import test_output
 import test_results
@@ -64,7 +69,7 @@ def _expected_test_output(port, filename):
                                   port.expected_checksum(filename))
 
 def _process_output(port, options, test_input, test_types, test_args,
-                    test_output):
+                    test_output, worker_name):
     """Receives the output from a DumpRenderTree process, subjects it to a
     number of tests, and returns a list of failure types the test produced.
 
@@ -76,6 +81,7 @@ def _process_output(port, options, test_input, test_types, test_args,
       test_types: list of test types to subject the output to
       test_args: arguments to be passed to each test
       test_output: a TestOutput object containing the output of the test
+      worker_name: worker name for logging
 
     Returns: a TestResult object
     """
@@ -86,20 +92,18 @@ def _process_output(port, options, test_input, test_types, test_args,
     if test_output.timeout:
         failures.append(test_failures.FailureTimeout())
 
+    test_name = port.relative_test_filename(test_input.filename)
     if test_output.crash:
-        _log.debug("Stacktrace for %s:\n%s" % (test_input.filename,
-                                               test_output.error))
-        # Strip off "file://" since RelativeTestFilename expects
-        # filesystem paths.
-        filename = os.path.join(options.results_directory,
-                                port.relative_test_filename(
-                                test_input.filename))
+        _log.debug("%s Stacktrace for %s:\n%s" % (worker_name, test_name,
+                                                  test_output.error))
+        filename = os.path.join(options.results_directory, test_name)
         filename = os.path.splitext(filename)[0] + "-stack.txt"
         port.maybe_make_directory(os.path.split(filename)[0])
         with codecs.open(filename, "wb", "utf-8") as file:
             file.write(test_output.error)
     elif test_output.error:
-        _log.debug("Previous test output stderr lines:\n%s" % test_output.error)
+        _log.debug("%s %s output stderr lines:\n%s" % (worker_name, test_name,
+                                                       test_output.error))
 
     expected_test_output = _expected_test_output(port, test_input.filename)
 
@@ -143,7 +147,7 @@ def _should_fetch_expected_checksum(options):
     return options.pixel_tests and not (options.new_baseline or options.reset_results)
 
 
-def _run_single_test(port, options, test_input, test_types, test_args, driver):
+def _run_single_test(port, options, test_input, test_types, test_args, driver, worker_name):
     # FIXME: Pull this into TestShellThread._run().
 
     # The image hash is used to avoid doing an image dump if the
@@ -157,17 +161,21 @@ def _run_single_test(port, options, test_input, test_types, test_args, driver):
     uri = port.filename_to_uri(test_input.filename)
     test_output = driver.run_test(uri, test_input.timeout, image_hash_to_driver)
     return _process_output(port, options, test_input, test_types, test_args,
-                           test_output)
+                           test_output, worker_name)
 
 
 class SingleTestThread(threading.Thread):
     """Thread wrapper for running a single test file."""
 
-    def __init__(self, port, options, test_input, test_types, test_args):
+    def __init__(self, port, options, worker_number, worker_name,
+                 test_input, test_types, test_args):
         """
         Args:
           port: object implementing port-specific hooks
           options: command line argument object from optparse
+          worker_number: worker number for tests
+              (FIXME: this should be passed to port.create_driver()).
+          worker_name: for logging
           test_input: Object containing the test filename and timeout
           test_types: A list of TestType objects to run the test output
               against.
@@ -181,6 +189,8 @@ class SingleTestThread(threading.Thread):
         self._test_types = test_types
         self._test_args = test_args
         self._driver = None
+        self._worker_number = worker_number
+        self._name = worker_name
 
     def run(self):
         self._covered_run()
@@ -193,7 +203,8 @@ class SingleTestThread(threading.Thread):
         self._driver.start()
         self._test_result = _run_single_test(self._port, self._options,
                                              self._test_input, self._test_types,
-                                             self._test_args, self._driver)
+                                             self._test_args, self._driver,
+                                             self._name)
         self._driver.stop()
 
     def get_test_result(self):
@@ -236,29 +247,27 @@ class WatchableThread(threading.Thread):
 
 
 class TestShellThread(WatchableThread):
-    def __init__(self, port, options, filename_list_queue, result_queue,
-                 test_types, test_args):
+    def __init__(self, port, options, worker_number,
+                 filename_list_queue, result_queue):
         """Initialize all the local state for this DumpRenderTree thread.
 
         Args:
           port: interface to port-specific hooks
           options: command line options argument from optparse
+          worker_number: identifier for a particular worker thread.
           filename_list_queue: A thread safe Queue class that contains lists
               of tuples of (filename, uri) pairs.
           result_queue: A thread safe Queue class that will contain
               serialized TestResult objects.
-          test_types: A list of TestType objects to run the test output
-              against.
-          test_args: A TestArguments object to pass to each TestType.
         """
         WatchableThread.__init__(self)
         self._port = port
         self._options = options
+        self._worker_number = worker_number
+        self._name = 'worker-%d' % worker_number
         self._filename_list_queue = filename_list_queue
         self._result_queue = result_queue
         self._filename_list = []
-        self._test_types = test_types
-        self._test_args = test_args
         self._driver = None
         self._test_group_timing_stats = {}
         self._test_results = []
@@ -269,6 +278,12 @@ class TestShellThread(WatchableThread):
         self._http_lock_wait_begin = 0
         self._http_lock_wait_end = 0
 
+        self._test_types = []
+        for cls in self._get_test_type_classes():
+            self._test_types.append(cls(self._port,
+                                        self._options.results_directory))
+        self._test_args = self._get_test_args(worker_number)
+
         # Current group of tests we're running.
         self._current_group = None
         # Number of tests in self._current_group.
@@ -276,6 +291,26 @@ class TestShellThread(WatchableThread):
         # Time at which we started running tests from self._current_group.
         self._current_group_start_time = None
 
+    def _get_test_args(self, worker_number):
+        """Returns the tuple of arguments for tests and for DumpRenderTree."""
+        test_args = test_type_base.TestArguments()
+        test_args.png_path = None
+        if self._options.pixel_tests:
+            png_path = os.path.join(self._options.results_directory,
+                                    "png_result%s.png" %
+                                    self._worker_number)
+            test_args.png_path = png_path
+        test_args.new_baseline = self._options.new_baseline
+        test_args.reset_results = self._options.reset_results
+
+        return test_args
+
+    def _get_test_type_classes(self):
+        classes = [text_diff.TestTextDiff]
+        if self._options.pixel_tests:
+            classes.append(image_diff.ImageDiff)
+        return classes
+
     def get_test_group_timing_stats(self):
         """Returns a dictionary mapping test group to a tuple of
         (number of tests in that group, time to run the tests)"""
@@ -446,6 +481,8 @@ class TestShellThread(WatchableThread):
         """
         worker = SingleTestThread(self._port,
                                   self._options,
+                                  self._worker_number,
+                                  self._name,
                                   test_input,
                                   self._test_types,
                                   self._test_args)
@@ -495,7 +532,7 @@ class TestShellThread(WatchableThread):
         self._next_timeout = time.time() + thread_timeout
         test_result = _run_single_test(self._port, self._options, test_input,
                                        self._test_types, self._test_args,
-                                       self._driver)
+                                       self._driver, self._name)
         self._test_results.append(test_result)
         return test_result
 
index b3804f470bc63fb3d5b7b60eaf7693a3d9989a71..9128ae8542bb4cbd4c9d9a5e9799eff2b42b48d9 100755 (executable)
@@ -72,9 +72,6 @@ from layout_package import test_expectations
 from layout_package import test_failures
 from layout_package import test_results
 from layout_package import test_results_uploader
-from test_types import image_diff
-from test_types import text_diff
-from test_types import test_type_base
 
 from webkitpy.common.system import user
 from webkitpy.thirdparty import simplejson
@@ -254,11 +251,6 @@ class TestRunner:
         # self._websocket_secure_server = websocket_server.PyWebSocket(
         #        options.results_directory, use_tls=True, port=9323)
 
-        # a list of TestType objects
-        self._test_types = [text_diff.TestTextDiff]
-        if options.pixel_tests:
-            self._test_types.append(image_diff.ImageDiff)
-
         # a set of test files, and the same tests as a list
         self._test_files = set()
         self._test_files_list = None
@@ -559,19 +551,6 @@ class TestRunner:
             filename_queue.put(item)
         return filename_queue
 
-    def _get_test_args(self, index):
-        """Returns the tuple of arguments for tests and for DumpRenderTree."""
-        test_args = test_type_base.TestArguments()
-        test_args.png_path = None
-        if self._options.pixel_tests:
-            png_path = os.path.join(self._options.results_directory,
-                                    "png_result%s.png" % index)
-            test_args.png_path = png_path
-        test_args.new_baseline = self._options.new_baseline
-        test_args.reset_results = self._options.reset_results
-
-        return test_args
-
     def _contains_tests(self, subdir):
         for test_file in self._test_files:
             if test_file.find(subdir) >= 0:
@@ -589,17 +568,10 @@ class TestRunner:
 
         # Instantiate TestShellThreads and start them.
         threads = []
-        for i in xrange(int(self._options.child_processes)):
-            # Create separate TestTypes instances for each thread.
-            test_types = []
-            for test_type in self._test_types:
-                test_types.append(test_type(self._port,
-                                    self._options.results_directory))
-
-            test_args = self._get_test_args(i)
+        for worker_number in xrange(int(self._options.child_processes)):
             thread = dump_render_tree_thread.TestShellThread(self._port,
-                self._options, filename_queue, self._result_queue,
-                test_types, test_args)
+                self._options, worker_number,
+                filename_queue, self._result_queue)
             if self._is_single_threaded():
                 thread.run_in_main_thread(self, result_summary)
             else: