[Lldb-commits] [lldb] r248059 - test events: announce worker count in new initialize event

Todd Fiala via lldb-commits lldb-commits at lists.llvm.org
Fri Sep 18 15:45:32 PDT 2015


Author: tfiala
Date: Fri Sep 18 17:45:31 2015
New Revision: 248059

URL: http://llvm.org/viewvc/llvm-project?rev=248059&view=rev
Log:
test events: announce worker count in new initialize event

See the following for details:
http://reviews.llvm.org/D12987

Modified:
    lldb/trunk/test/dosep.py
    lldb/trunk/test/dotest.py
    lldb/trunk/test/dotest_args.py
    lldb/trunk/test/test_results.py

Modified: lldb/trunk/test/dosep.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/dosep.py?rev=248059&r1=248058&r2=248059&view=diff
==============================================================================
--- lldb/trunk/test/dosep.py (original)
+++ lldb/trunk/test/dosep.py Fri Sep 18 17:45:31 2015
@@ -180,9 +180,14 @@ def call_with_timeout(command, timeout,
         command = [timeout_command, '-s', 'QUIT', timeout] + command
 
     if GET_WORKER_INDEX is not None:
-        worker_index = GET_WORKER_INDEX()
-        command.extend([
-            "--event-add-entries", "worker_index={}".format(worker_index)])
+        try:
+            worker_index = GET_WORKER_INDEX()
+            command.extend([
+                "--event-add-entries", "worker_index={}".format(worker_index)])
+        except:
+            # Ctrl-C does bad things to multiprocessing.Manager.dict() lookup.
+            pass
+
     # Specifying a value for close_fds is unsupported on Windows when using
     # subprocess.PIPE
     if os.name != "nt":
@@ -896,7 +901,7 @@ def walk_and_invoke(test_directory, test
     # listener channel and tell the inferior to send results to the
     # port on which we'll be listening.
     if RESULTS_FORMATTER is not None:
-        forwarding_func = RESULTS_FORMATTER.process_event
+        forwarding_func = RESULTS_FORMATTER.handle_event
         RESULTS_LISTENER_CHANNEL = (
             dotest_channels.UnpicklingForwardingListenerChannel(
                 RUNNER_PROCESS_ASYNC_MAP, "localhost", 0, forwarding_func))
@@ -1184,15 +1189,6 @@ def main(print_details_on_success, num_t
     for core in cores:
         os.unlink(core)
 
-    if not num_threads:
-        num_threads_str = os.environ.get("LLDB_TEST_THREADS")
-        if num_threads_str:
-            num_threads = int(num_threads_str)
-        else:
-            num_threads = multiprocessing.cpu_count()
-    if num_threads < 1:
-        num_threads = 1
-
     system_info = " ".join(platform.uname())
 
     # Figure out which testrunner strategy we'll use.

Modified: lldb/trunk/test/dotest.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/dotest.py?rev=248059&r1=248058&r2=248059&view=diff
==============================================================================
--- lldb/trunk/test/dotest.py (original)
+++ lldb/trunk/test/dotest.py Fri Sep 18 17:45:31 2015
@@ -1006,13 +1006,26 @@ def setupTestResults():
 
         # Start the results formatter session - we'll only have one
         # during a given dotest process invocation.
-        results_formatter_object.begin_session()
+        initialize_event = EventBuilder.bare_event("initialize")
+        if isMultiprocessTestRunner():
+            if test_runner_name is not None and test_runner_name == "serial":
+                # Only one worker queue here.
+                worker_count = 1
+            else:
+                # Workers will be the number of threads specified.
+                worker_count = num_threads
+        else:
+            worker_count = 1
+        initialize_event["worker_count"] = worker_count
+
+        results_formatter_object.handle_event(initialize_event)
 
         def shutdown_formatter():
             # Tell the formatter to write out anything it may have
             # been saving until the very end (e.g. xUnit results
             # can't complete its output until this point).
-            results_formatter_object.end_session()
+            terminate_event = EventBuilder.bare_event("terminate")
+            results_formatter_object.handle_event(terminate_event)
 
             # And now close out the output file-like object.
             if cleanup_func is not None:
@@ -1873,7 +1886,7 @@ if __name__ == "__main__":
                         self.stream.write(self.fmt % self.counter)
                     super(LLDBTestResult, self).startTest(test)
                     if self.results_formatter:
-                        self.results_formatter.process_event(
+                        self.results_formatter.handle_event(
                             EventBuilder.event_for_start(test))
 
                 def addSuccess(self, test):
@@ -1882,7 +1895,7 @@ if __name__ == "__main__":
                     if parsable:
                         self.stream.write("PASS: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
                     if self.results_formatter:
-                        self.results_formatter.process_event(
+                        self.results_formatter.handle_event(
                             EventBuilder.event_for_success(test))
 
                 def addError(self, test, err):
@@ -1896,7 +1909,7 @@ if __name__ == "__main__":
                     if parsable:
                         self.stream.write("FAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
                     if self.results_formatter:
-                        self.results_formatter.process_event(
+                        self.results_formatter.handle_event(
                             EventBuilder.event_for_error(test, err))
 
                 def addCleanupError(self, test, err):
@@ -1910,7 +1923,7 @@ if __name__ == "__main__":
                     if parsable:
                         self.stream.write("CLEANUP ERROR: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
                     if self.results_formatter:
-                        self.results_formatter.process_event(
+                        self.results_formatter.handle_event(
                             EventBuilder.event_for_cleanup_error(
                                 test, err))
 
@@ -1933,7 +1946,7 @@ if __name__ == "__main__":
                             else:
                                 failuresPerCategory[category] = 1
                     if self.results_formatter:
-                        self.results_formatter.process_event(
+                        self.results_formatter.handle_event(
                             EventBuilder.event_for_failure(test, err))
 
 
@@ -1948,7 +1961,7 @@ if __name__ == "__main__":
                     if parsable:
                         self.stream.write("XFAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
                     if self.results_formatter:
-                        self.results_formatter.process_event(
+                        self.results_formatter.handle_event(
                             EventBuilder.event_for_expected_failure(
                             test, err, bugnumber))
 
@@ -1963,7 +1976,7 @@ if __name__ == "__main__":
                     if parsable:
                         self.stream.write("UNSUPPORTED: LLDB (%s) :: %s (%s) \n" % (self._config_string(test), str(test), reason))
                     if self.results_formatter:
-                        self.results_formatter.process_event(
+                        self.results_formatter.handle_event(
                             EventBuilder.event_for_skip(test, reason))
 
                 def addUnexpectedSuccess(self, test, bugnumber):
@@ -1977,7 +1990,7 @@ if __name__ == "__main__":
                     if parsable:
                         self.stream.write("XPASS: LLDB (%s) :: %s\n" % (self._config_string(test), str(test)))
                     if self.results_formatter:
-                        self.results_formatter.process_event(
+                        self.results_formatter.handle_event(
                             EventBuilder.event_for_unexpected_success(
                                 test, bugnumber))
 

Modified: lldb/trunk/test/dotest_args.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/dotest_args.py?rev=248059&r1=248058&r2=248059&view=diff
==============================================================================
--- lldb/trunk/test/dotest_args.py (original)
+++ lldb/trunk/test/dotest_args.py Fri Sep 18 17:45:31 2015
@@ -1,4 +1,5 @@
 import sys
+import multiprocessing
 import os
 import textwrap
 
@@ -26,6 +27,16 @@ def parse_args(parser, argv):
     else:
         return parser.parse_args(args=argv)
 
+
+def default_thread_count():
+    # Check if specified in the environment
+    num_threads_str = os.environ.get("LLDB_TEST_THREADS")
+    if num_threads_str:
+        return int(num_threads_str)
+    else:
+        return multiprocessing.cpu_count()
+
+
 def create_parser():
     parser = argparse.ArgumentParser(description='description', prefix_chars='+-', add_help=False)
     group = None
@@ -126,6 +137,7 @@ def create_parser():
         '--threads',
         type=int,
         dest='num_threads',
+        default=default_thread_count(),
         help=('The number of threads/processes to use when running tests '
               'separately, defaults to the number of CPU cores available'))
     group.add_argument(

Modified: lldb/trunk/test/test_results.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/test_results.py?rev=248059&r1=248058&r2=248059&view=diff
==============================================================================
--- lldb/trunk/test/test_results.py (original)
+++ lldb/trunk/test/test_results.py Fri Sep 18 17:45:31 2015
@@ -40,6 +40,29 @@ class EventBuilder(object):
         return (test_class_name, test_name)
 
     @staticmethod
+    def bare_event(event_type):
+        """Creates an event with default additions, event type and timestamp.
+
+        @param event_type the value set for the "event" key, used
+        to distinguish events.
+
+        @returns an event dictionary with all default additions, the "event"
+        key set to the passed in event_type, and the event_time value set to
+        time.time().
+        """
+        if EventBuilder.BASE_DICTIONARY is not None:
+            # Start with a copy of the "always include" entries.
+            event = dict(EventBuilder.BASE_DICTIONARY)
+        else:
+            event = {}
+
+        event.update({
+            "event": event_type,
+            "event_time": time.time()
+            })
+        return event
+
+    @staticmethod
     def _event_dictionary_common(test, event_type):
         """Returns an event dictionary setup with values for the given event type.
 
@@ -51,18 +74,12 @@ class EventBuilder(object):
         """
         test_class_name, test_name = EventBuilder._get_test_name_info(test)
 
-        if EventBuilder.BASE_DICTIONARY is not None:
-            # Start with a copy of the "always include" entries.
-            result = dict(EventBuilder.BASE_DICTIONARY)
-        else:
-            result = {}
-        result.update({
-            "event": event_type,
+        event = EventBuilder.bare_event(event_type)
+        event.update({
             "test_class": test_class_name,
             "test_name": test_name,
-            "event_time": time.time()
         })
-        return result
+        return event
 
     @staticmethod
     def _error_tuple_class(error_tuple):
@@ -278,14 +295,6 @@ class EventBuilder(object):
         """
         EventBuilder.BASE_DICTIONARY = dict(entries_dict)
 
-    @staticmethod
-    def base_event():
-        """@return the base event dictionary that all events should contain."""
-        if EventBuilder.BASE_DICTIONARY is not None:
-            return dict(EventBuilder.BASE_DICTIONARY)
-        else:
-            return None
-
 
 class ResultsFormatter(object):
 
@@ -312,6 +321,8 @@ class ResultsFormatter(object):
     # Single call to session start, before parsing any events.
     formatter.begin_session()
 
+    formatter.handle_event({"event":"initialize",...})
+
     # Zero or more calls specified for events recorded during the test session.
     # The parallel test runner manages getting results from all the inferior
     # dotest processes, so from a new format perspective, don't worry about
@@ -319,12 +330,12 @@ class ResultsFormatter(object):
     # sandwiched between a single begin_session()/end_session() pair in the
     # parallel test runner process/thread.
     for event in zero_or_more_test_events():
-        formatter.process_event(event)
+        formatter.handle_event(event)
 
-    # Single call to session end.  Formatters that need all the data before
-    # they can print a correct result (e.g. xUnit/JUnit), this is where
-    # the final report can be generated.
-    formatter.end_session()
+    # Single call to terminate/wrap-up. Formatters that need all the
+    # data before they can print a correct result (e.g. xUnit/JUnit),
+    # this is where the final report can be generated.
+    formatter.handle_event({"event":"terminate",...})
 
     It is not the formatter's responsibility to close the file_like_object.
     (i.e. do not close it).
@@ -380,32 +391,8 @@ class ResultsFormatter(object):
         # entirely consistent from the outside.
         self.lock = threading.Lock()
 
-    def begin_session(self):
-        """Begins a test session.
-
-        All process_event() calls must be sandwiched between
-        begin_session() and end_session() calls.
-
-        Derived classes may override this but should call this first.
-        """
-        pass
-
-    def end_session(self):
-        """Ends a test session.
-
-        All process_event() calls must be sandwiched between
-        begin_session() and end_session() calls.
-
-        All results formatting should be sent to the output
-        file object by the end of this call.
-
-        Derived classes may override this but should call this after
-        the dervied class's behavior is complete.
-        """
-        pass
-
-    def process_event(self, test_event):
-        """Processes the test event for collection into the formatter output.
+    def handle_event(self, test_event):
+        """Handles the test event for collection into the formatter output.
 
         Derived classes may override this but should call down to this
         implementation first.
@@ -573,17 +560,16 @@ class XunitFormatter(ResultsFormatter):
             "unexpected_success": self._handle_unexpected_success
             }
 
-    def begin_session(self):
-        super(XunitFormatter, self).begin_session()
-
-    def process_event(self, test_event):
-        super(XunitFormatter, self).process_event(test_event)
+    def handle_event(self, test_event):
+        super(XunitFormatter, self).handle_event(test_event)
 
         event_type = test_event["event"]
         if event_type is None:
             return
 
-        if event_type == "test_start":
+        if event_type == "terminate":
+            self._finish_output()
+        elif event_type == "test_start":
             self.track_start_time(
                 test_event["test_class"],
                 test_event["test_name"],
@@ -805,7 +791,7 @@ class XunitFormatter(ResultsFormatter):
 
         return result
 
-    def _end_session_internal(self):
+    def _finish_output_no_lock(self):
         """Flushes out the report of test executions to form valid xml output.
 
         xUnit output is in XML.  The reporting system cannot complete the
@@ -850,11 +836,9 @@ class XunitFormatter(ResultsFormatter):
         # Close off the test suite.
         self.out_file.write('</testsuite></testsuites>\n')
 
-        super(XunitFormatter, self).end_session()
-
-    def end_session(self):
+    def _finish_output(self):
         with self.lock:
-            self._end_session_internal()
+            self._finish_output_no_lock()
 
 
 class RawPickledFormatter(ResultsFormatter):
@@ -875,42 +859,31 @@ class RawPickledFormatter(ResultsFormatt
         super(RawPickledFormatter, self).__init__(out_file, options)
         self.pid = os.getpid()
 
-    def begin_session(self):
-        super(RawPickledFormatter, self).begin_session()
-        event = EventBuilder.base_event()
-        if event is None:
-            event = {}
-        event.update({
-            "event": "session_begin",
-            "event_time": time.time(),
-            "pid": self.pid
-        })
-        self.process_event(event)
+    def handle_event(self, test_event):
+        super(RawPickledFormatter, self).handle_event(test_event)
 
-    def process_event(self, test_event):
-        super(RawPickledFormatter, self).process_event(test_event)
+        # Convert initialize/terminate events into job_begin/job_end events.
+        event_type = test_event["event"]
+        if event_type is None:
+            return
+
+        if event_type == "initialize":
+            test_event["event"] = "job_begin"
+        elif event_type == "terminate":
+            test_event["event"] = "job_end"
+
+        # Tack on the pid.
+        test_event["pid"] = self.pid
 
         # Send it as {serialized_length_of_serialized_bytes}#{serialized_bytes}
         pickled_message = cPickle.dumps(test_event)
         self.out_file.send(
             "{}#{}".format(len(pickled_message), pickled_message))
 
-    def end_session(self):
-        event = EventBuilder.base_event()
-        if event is None:
-            event = {}
-        event.update({
-            "event": "session_end",
-            "event_time": time.time(),
-            "pid": self.pid
-        })
-        self.process_event(event)
-        super(RawPickledFormatter, self).end_session()
-
 
 class DumpFormatter(ResultsFormatter):
     """Formats events to the file as their raw python dictionary format."""
 
-    def process_event(self, test_event):
-        super(DumpFormatter, self).process_event(test_event)
+    def handle_event(self, test_event):
+        super(DumpFormatter, self).handle_event(test_event)
         self.out_file.write("\n" + pprint.pformat(test_event) + "\n")




More information about the lldb-commits mailing list