Changeset 121809 in webkit
- Timestamp:
- Jul 3, 2012 4:31:57 PM (12 years ago)
- Location:
- trunk/Tools
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Tools/ChangeLog
r121807 r121809 1 2012-07-03 Dirk Pranke <dpranke@chromium.org> 2 3 nrwt: make the worker class stand alone with a cleaner interface 4 https://bugs.webkit.org/show_bug.cgi?id=90409 5 6 Reviewed by Ojan Vafai. 7 8 Currently the Worker class derives from AbstractWorker, which is 9 kind of crufty and awkward; it would be better if we did not 10 rely on shared state. 11 12 This change changes that so that Worker derives from object, and 13 exposes the following interface: 14 __init__() - called in the manager process 15 safe_init() - called in the worker process to initialize 16 unpicklable state 17 handle() - a single routine to handle all messages 18 cleanup() - called so the worker can clean up 19 20 Also, all of the "administrative" messages that are handled by 21 the worker (notification of start/stop/etc.) move into 22 manager_worker_broker - this reduces worker.py to just handling 23 the mechanics of actually running each test. 24 25 For the moment, we do this by creating Yet Another wrapper/proxy 26 class in manager_worker_broker, but this will get simpler 27 shortly when the rest of m_w_b is cleaned up. 28 29 With this change worker is now in its new form but there will be 30 a follow-on change that cleans up some names and other minor 31 things. 32 33 This change is again mostly just moving things around and should 34 be covered by the (updated) existing tests. 35 36 * Scripts/webkitpy/layout_tests/controllers/manager_worker_broker.py: 37 (get): 38 (AbstractWorker.__init__): 39 (AbstractWorker.run): 40 (AbstractWorker): 41 (AbstractWorker.handle_stop): 42 (AbstractWorker.handle_test_list): 43 (AbstractWorker.yield_to_broker): 44 (AbstractWorker.post_message): 45 (_WorkerConnection.__init__): 46 (_Process.run): 47 * Scripts/webkitpy/layout_tests/controllers/manager_worker_broker_unittest.py: 48 (_TestWorker): 49 (_TestWorker.__init__): 50 (_TestWorker.name): 51 (_TestWorker.cleanup): 52 (_TestWorker.handle): 53 (_TestWorker.safe_init): 54 (_TestWorker.stop): 55 (_TestsMixin.handle_finished_test): 56 (_TestsMixin.setUp): 57 (_TestsMixin.test_cancel): 58 (_TestsMixin.test_done): 59 * Scripts/webkitpy/layout_tests/controllers/worker.py: 60 (Worker): 61 (Worker.__init__): 62 (Worker.safe_init): 63 (Worker.handle): 64 1 65 2012-07-03 Dirk Pranke <dpranke@chromium.org> 2 66 -
trunk/Tools/Scripts/webkitpy/layout_tests/controllers/manager_worker_broker.py
r121807 r121809 76 76 77 77 78 from webkitpy.common.host import Host 78 79 from webkitpy.common.system import stack_utils 79 80 from webkitpy.layout_tests.views import metered_stream … … 97 98 client - BrokerClient implementation to dispatch 98 99 replies to. 99 worker_factory: factory method for creatin objects that implement the AbstractWorker interface.100 worker_factory: factory method for creating objects that implement the Worker interface. 100 101 host: optional picklable host object that can be passed to workers for testing. 101 102 Returns: … … 264 265 class AbstractWorker(BrokerClient): 265 266 def __init__(self, worker_connection, worker_number): 266 """The constructor should be used to do any simple initialization267 necessary, but should not do anything that creates data structures268 that cannot be Pickled or sent across processes (like opening269 files or sockets). Complex initialization should be done at the270 start of the run() call.271 272 Args:273 worker_connection - handle to the _BrokerConnection object creating274 the worker and that can be used for messaging.275 worker_number - the number/index of the current worker."""276 267 BrokerClient.__init__(self) 268 self.worker = None 277 269 self._worker_connection = worker_connection 278 270 self._worker_number = worker_number … … 281 273 self._canceled = False 282 274 self._options = optparse.Values({'verbose': False}) 275 self.host = None 283 276 284 277 def name(self): … … 291 284 self._done = True 292 285 293 def run(self ):286 def run(self, host): 294 287 """Callback for the worker to start executing. Typically does any 295 288 remaining initialization and then calls broker_connection.run_message_loop().""" 296 289 exception_msg = "" 290 self.host = host 291 292 self.worker.safe_init() 293 _log.debug('%s starting' % self._name) 297 294 298 295 try: … … 309 306 finally: 310 307 _log.debug("%s done with message loop%s" % (self._name, exception_msg)) 308 self.worker.cleanup() 309 self._worker_connection.post_message('done') 310 311 def handle_stop(self, source): 312 self._done = True 313 314 def handle_test_list(self, source, list_name, test_list): 315 self.worker.handle('test_list', source, list_name, test_list) 311 316 312 317 def cancel(self): … … 315 320 method being called, so clients should not rely solely on this.""" 316 321 self._canceled = True 322 323 def yield_to_broker(self): 324 self._worker_connection.yield_to_broker() 325 326 def post_message(self, *args): 327 self._worker_connection.post_message(*args) 317 328 318 329 … … 363 374 class _WorkerConnection(_BrokerConnection): 364 375 def __init__(self, host, broker, worker_factory, worker_number): 365 self._client = worker_factory(self, worker_number) 376 # FIXME: keeping track of the differences between the WorkerConnection, the AbstractWorker, and the 377 # actual Worker (created by worker_factory) is very confusing, but this all gets better when 378 # _WorkerConnection and AbstractWorker get merged. 379 self._client = AbstractWorker(self, worker_number) 380 self._worker = worker_factory(self._client, worker_number) 381 self._client.worker = self._worker 366 382 self._host = host 367 383 self._log_messages = [] … … 452 468 453 469 def run(self): 470 if not self._worker_connection._host: 471 self._worker_connection._host = Host() 454 472 self._worker_connection.run() 455 473 -
trunk/Tools/Scripts/webkitpy/layout_tests/controllers/manager_worker_broker_unittest.py
r121807 r121809 55 55 56 56 57 class _TestWorker( manager_worker_broker.AbstractWorker):58 def __init__(self, worker_connection, worker_number=1):59 s uper(_TestWorker, self).__init__(worker_connection, worker_number)57 class _TestWorker(object): 58 def __init__(self, caller, worker_number): 59 self._caller = caller 60 60 self._thing_to_greet = 'everybody' 61 61 self._starting_queue = starting_queue 62 62 self._stopping_queue = stopping_queue 63 64 def handle_stop(self, src): 65 self.stop_handling_messages() 66 67 def handle_test(self, src, an_int, a_str): 63 self._options = optparse.Values({'verbose': False}) 64 65 def name(self): 66 return WORKER_NAME 67 68 def cleanup(self): 69 pass 70 71 def handle(self, message, src, an_int, a_str): 68 72 assert an_int == 1 69 73 assert a_str == "hello, world" 70 self._ worker_connection.post_message('test', 2, 'hi, ' + self._thing_to_greet)71 72 def run(self, host):74 self._caller.post_message('finished_test', 2) 75 76 def safe_init(self): 73 77 if self._starting_queue: 74 78 self._starting_queue.put('') … … 76 80 if self._stopping_queue: 77 81 self._stopping_queue.get() 78 try: 79 super(_TestWorker, self).run() 80 finally: 81 self._worker_connection.post_message('done') 82 83 def stop(self): 84 self._caller.post_message('done') 82 85 83 86 … … 106 109 self._done = True 107 110 108 def handle_ test(self, src, an_int, a_str):111 def handle_finished_test(self, src, an_int, log_messages): 109 112 self._an_int = an_int 110 self._a_str = a_str111 113 112 114 def handle_exception(self, src, exception_type, exception_value, stack): … … 115 117 def setUp(self): 116 118 self._an_int = None 117 self._a_str = None118 119 self._broker = None 119 120 self._done = False … … 137 138 self.make_broker() 138 139 worker = self._broker.start_worker(1) 139 self._broker.post_message('test ', 1, 'hello, world')140 self._broker.post_message('test_list', 1, 'hello, world') 140 141 worker.cancel() 141 142 worker.join(0.1) … … 146 147 self.make_broker() 147 148 worker = self._broker.start_worker(1) 148 self._broker.post_message('test ', 1, 'hello, world')149 self._broker.post_message('test_list', 1, 'hello, world') 149 150 self._broker.post_message('stop') 150 151 self._broker.run_message_loop() … … 153 154 self.assertTrue(self.is_done()) 154 155 self.assertEqual(self._an_int, 2) 155 self.assertEqual(self._a_str, 'hi, everybody')156 156 self._broker.cleanup() 157 157 -
trunk/Tools/Scripts/webkitpy/layout_tests/controllers/worker.py
r121807 r121809 33 33 import time 34 34 35 from webkitpy.common.host import Host36 from webkitpy.layout_tests.controllers import manager_worker_broker37 35 from webkitpy.layout_tests.controllers import single_test_runner 38 36 from webkitpy.layout_tests.models import test_expectations … … 43 41 44 42 45 class Worker( manager_worker_broker.AbstractWorker):43 class Worker(object): 46 44 def __init__(self, worker_connection, worker_number, results_directory, options): 47 super(Worker, self).__init__(worker_connection, worker_number) 45 self._worker_connection = worker_connection 46 self._worker_number = worker_number 47 self._name = 'worker/%d' % worker_number 48 48 self._results_directory = results_directory 49 49 self._options = options 50 51 # The remaining fields are initialized in safe_init() 52 self._host = None 50 53 self._port = None 51 54 self._batch_size = None … … 60 63 61 64 def safe_init(self): 62 """This method should only be called when it is is safe for the mixin63 to create state that can't be Pickled.64 65 This routine exists so that the mixin can be created and then marshaled66 across into a child process."""67 self._filesystem = self._port.host.filesystem 65 """This method is called when it is safe for the object to create state that 66 does not need to be pickled (usually this means it is called in a child process).""" 67 self._host = self._worker_connection.host 68 self._filesystem = self._host.filesystem 69 self._port = self._host.port_factory.get(self._options.platform, self._options) 70 68 71 self._batch_count = 0 69 72 self._batch_size = self._options.batch_size or 0 … … 71 74 self._tests_run_file = self._filesystem.open_text_file_for_writing(tests_run_filename) 72 75 73 def run(self, host): 74 if not host: 75 host = Host() 76 77 options = self._options 78 self._port = host.port_factory.get(options.platform, options) 79 80 self.safe_init() 81 try: 82 _log.debug("%s starting" % self._name) 83 super(Worker, self).run() 84 finally: 85 self.kill_driver() 86 _log.debug("%s exiting" % self._name) 87 self.cleanup() 88 self._worker_connection.post_message('done') 89 90 def handle_test_list(self, src, list_name, test_list): 76 def handle(self, name, source, list_name, test_list): 77 assert name == 'test_list' 91 78 start_time = time.time() 92 79 num_tests = 0 … … 99 86 elapsed_time = time.time() - start_time 100 87 self._worker_connection.post_message('finished_list', list_name, num_tests, elapsed_time) 101 102 def handle_stop(self, src):103 self.stop_handling_messages()104 88 105 89 def _update_test_input(self, test_input):
Note: See TracChangeset
for help on using the changeset viewer.