2010-04-19 Eric Seidel <eric@webkit.org>
authoreric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Apr 2010 06:55:46 +0000 (06:55 +0000)
committereric@webkit.org <eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Apr 2010 06:55:46 +0000 (06:55 +0000)
        Reviewed by Adam Barth.

        new-run-webkit-tests has much higher startup latency than run-webkit-tests
        https://bugs.webkit.org/show_bug.cgi?id=37643

        I got rid of the -expected.checksum reads during startup.
        This makes startup noticably better on my laptop.

        * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
         - Use image_hash() instead of .image_hash now that expected.checksum
           file reads are done lazily.
        * Scripts/webkitpy/layout_tests/port/http_server_base.py:
         - Add debug logging for this sleep call.
           In my testing I never saw this sleep() hit.
        * Scripts/webkitpy/layout_tests/port/websocket_server.py:
         - Sleep a shorter interval to make websocket server
           startup more responsive.  On my machine startup was
           taking around 1 second.
         - Remove the unconditional .5s delay on startup.
        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
         - Make image_hash file reads done lazily in a new image_hash() function.
         - Add a "Starting testing ..." meter update after DRT threads have
           been started, but before we get updates from the first one.
         - Rename variable "t" to a full english name to match WebKit style.

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

WebKitTools/ChangeLog
WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py
WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_files.py
WebKitTools/Scripts/webkitpy/layout_tests/port/http_server_base.py
WebKitTools/Scripts/webkitpy/layout_tests/port/websocket_server.py
WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py

index 21ae415..191539e 100644 (file)
@@ -1,3 +1,30 @@
+2010-04-19  Eric Seidel  <eric@webkit.org>
+
+        Reviewed by Adam Barth.
+
+        new-run-webkit-tests has much higher startup latency than run-webkit-tests
+        https://bugs.webkit.org/show_bug.cgi?id=37643
+
+        I got rid of the -expected.checksum reads during startup.
+        This makes startup noticably better on my laptop.
+
+        * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+         - Use image_hash() instead of .image_hash now that expected.checksum
+           file reads are done lazily.
+        * Scripts/webkitpy/layout_tests/port/http_server_base.py:
+         - Add debug logging for this sleep call.
+           In my testing I never saw this sleep() hit.
+        * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+         - Sleep a shorter interval to make websocket server
+           startup more responsive.  On my machine startup was
+           taking around 1 second.
+         - Remove the unconditional .5s delay on startup.
+        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+         - Make image_hash file reads done lazily in a new image_hash() function.
+         - Add a "Starting testing ..." meter update after DRT threads have
+           been started, but before we get updates from the first one.
+         - Rename variable "t" to a full english name to match WebKit style.
+
 2010-04-20  Daniel Bates  <dbates@rim.com>
 
         Reviewed by Eric Seidel.
index 9148f29..e61d11f 100644 (file)
@@ -156,7 +156,7 @@ class SingleTestThread(threading.Thread):
         start = time.time()
         crash, timeout, actual_checksum, output, error = \
             driver.run_test(test_info.uri.strip(), test_info.timeout,
-                            test_info.image_hash)
+                            test_info.image_hash())
         end = time.time()
         self._test_result = process_output(self._port,
             test_info, self._test_types, self._test_args,
@@ -420,7 +420,7 @@ class TestShellThread(threading.Thread):
         # checksums match, so it should be set to a blank value if we
         # are generating a new baseline.  (Otherwise, an image from a
         # previous run will be copied into the baseline.)
-        image_hash = test_info.image_hash
+        image_hash = test_info.image_hash()
         if image_hash and self._test_args.new_baseline:
             image_hash = ""
         start = time.time()
index e33248a..6754fa6 100644 (file)
@@ -36,6 +36,13 @@ under that directory."""
 
 import glob
 import os
+import time
+
+from webkitpy.common.system import logutils
+
+
+_log = logutils.get_logger(__file__)
+
 
 # When collecting test cases, we include any file with these extensions.
 _supported_file_extensions = set(['.html', '.shtml', '.xml', '.xhtml', '.xhtmlmp', '.pl',
@@ -51,6 +58,7 @@ def gather_test_files(port, paths):
       paths: a list of command line paths relative to the webkit/tests
           directory. glob patterns are ok.
     """
+    gather_start_time = time.time()
     paths_to_walk = set()
     # if paths is empty, provide a pre-defined list.
     if paths:
@@ -73,10 +81,16 @@ def gather_test_files(port, paths):
             continue
 
         for root, dirs, files in os.walk(path):
-            # don't walk skipped directories and sub directories
+            # Don't walk skipped directories or their sub-directories.
             if os.path.basename(root) in _skipped_directories:
                 del dirs[:]
                 continue
+            # This copy and for-in is slightly inefficient, but
+            # the extra walk avoidance consistently shaves .5 seconds
+            # off of total walk() time on my MacBook Pro.
+            for directory in dirs[:]:
+                if directory in _skipped_directories:
+                    dirs.remove(directory)
 
             for filename in files:
                 if _has_supported_extension(filename):
@@ -84,6 +98,9 @@ def gather_test_files(port, paths):
                     filename = os.path.normpath(filename)
                     test_files.add(filename)
 
+    gather_time = time.time() - gather_start_time
+    _log.debug("Test gathering took %f seconds" % gather_time)
+
     return test_files
 
 
index 387390f..c9805d6 100644 (file)
@@ -49,6 +49,7 @@ class HttpServerBase(object):
         while time.time() - start_time < 20:
             if action():
                 return True
+            _log.debug("Waiting for action: %s" % action)
             time.sleep(1)
 
         return False
index 03b4948..a9ba160 100644 (file)
@@ -64,6 +64,7 @@ def url_is_alive(url):
     Return:
       True if the url is alive.
     """
+    sleep_time = 0.5
     wait_time = 5
     while wait_time > 0:
         try:
@@ -72,9 +73,9 @@ def url_is_alive(url):
             return True
         except IOError:
             pass
-        wait_time -= 1
-        # Wait a second and try again.
-        time.sleep(1)
+        # Wait for sleep_time before trying again.
+        wait_time -= sleep_time
+        time.sleep(sleep_time)
 
     return False
 
@@ -209,9 +210,6 @@ class PyWebSocket(http_server.Lighttpd):
                                          stderr=subprocess.STDOUT,
                                          env=env)
 
-        # Wait a bit before checking the liveness of the server.
-        time.sleep(0.5)
-
         if self._use_tls:
             url = 'https'
         else:
index 1be87ae..4082cdb 100755 (executable)
@@ -44,6 +44,9 @@ directory.  Entire lines starting with '//' (comments) will be ignored.
 For details of the files' contents and purposes, see test_lists/README.
 """
 
+from __future__ import with_statement
+
+import codecs
 import errno
 import glob
 import logging
@@ -122,13 +125,27 @@ class TestInfo:
         self.filename = filename
         self.uri = port.filename_to_uri(filename)
         self.timeout = timeout
-        expected_hash_file = port.expected_filename(filename, '.checksum')
+        # FIXME: Confusing that the file is .checksum and we call it "hash"
+        self._expected_hash_path = port.expected_filename(filename, '.checksum')
+        self._have_read_expected_hash = False
+        self._image_hash = None
+
+    def _read_image_hash(self):
         try:
-            self.image_hash = open(expected_hash_file, "r").read()
+            with codecs.open(self._expected_hash_path, "r", "ascii") as hash_file:
+                return hash_file.read()
         except IOError, e:
             if errno.ENOENT != e.errno:
                 raise
-            self.image_hash = None
+
+    def image_hash(self):
+        # Read the image_hash lazily to reduce startup time.
+        # This class is accessed across threads, but only one thread should
+        # ever be dealing with any given TestInfo so no locking is needed.
+        if not self._have_read_expected_hash:
+            self._have_read_expected_hash = True
+            self._image_hash = self._read_image_hash()
+        return self._image_hash
 
 
 class ResultSummary(object):
@@ -542,8 +559,8 @@ class TestRunner:
         for i in xrange(int(self._options.child_processes)):
             # Create separate TestTypes instances for each thread.
             test_types = []
-            for t in self._test_types:
-                test_types.append(t(self._port,
+            for test_type in self._test_types:
+                test_types.append(test_type(self._port,
                                     self._options.results_directory))
 
             test_args, png_path, shell_args = \
@@ -584,6 +601,7 @@ class TestRunner:
                            (self._port.driver_name(), plural))
         threads = self._instantiate_dump_render_tree_threads(file_list,
                                                              result_summary)
+        self._meter.update("Starting testing ...")
 
         # Wait for the threads to finish and collect test failures.
         failures = {}