133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# Copyright 2012 the V8 project authors. All rights reserved.
233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# Redistribution and use in source and binary forms, with or without
333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# modification, are permitted provided that the following conditions are
433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# met:
533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#
633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#     * Redistributions of source code must retain the above copyright
733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       notice, this list of conditions and the following disclaimer.
833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#     * Redistributions in binary form must reproduce the above
933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       copyright notice, this list of conditions and the following
1033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       disclaimer in the documentation and/or other materials provided
1133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       with the distribution.
1233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#     * Neither the name of Google Inc. nor the names of its
1333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       contributors may be used to endorse or promote products derived
1433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#       from this software without specific prior written permission.
1533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org#
1633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
2833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
2933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport os
3033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport socket
3133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport subprocess
3233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport threading
3333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgimport time
3433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
3533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom . import distro
3633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom ..local import execution
37285f85a5a149f36516a20200a76899651dd95fb6machenbach@chromium.orgfrom ..local import perfdata
3833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom ..objects import peer
3933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom ..objects import workpacket
4033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom ..server import compression
4133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom ..server import constants
4233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom ..server import local_handler
4333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgfrom ..server import signatures
4433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
4533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
4633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgdef GetPeers():
4733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  data = local_handler.LocalQuery([constants.REQUEST_PEERS])
4833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  if not data: return []
4933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  return [ peer.Peer.Unpack(p) for p in data ]
5033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
5133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
5233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.orgclass NetworkedRunner(execution.Runner):
5333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def __init__(self, suites, progress_indicator, context, peers, workspace):
5433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.suites = suites
5533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    num_tests = 0
5633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    datapath = os.path.join("out", "testrunner_data")
57285f85a5a149f36516a20200a76899651dd95fb6machenbach@chromium.org    # TODO(machenbach): These fields should exist now in the superclass.
58285f85a5a149f36516a20200a76899651dd95fb6machenbach@chromium.org    # But there is no super constructor call. Check if this is a problem.
5933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.perf_data_manager = perfdata.PerfDataManager(datapath)
6033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.perfdata = self.perf_data_manager.GetStore(context.arch, context.mode)
6133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    for s in suites:
6233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      for t in s.tests:
6333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        t.duration = self.perfdata.FetchPerfData(t) or 1.0
6433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      num_tests += len(s.tests)
6533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self._CommonInit(num_tests, progress_indicator, context)
6633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.tests = []  # Only used if we need to fall back to local execution.
6733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.tests_lock = threading.Lock()
6833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.peers = peers
6933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.pubkey_fingerprint = None  # Fetched later.
7033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.base_rev = subprocess.check_output(
7133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        "cd %s; git log -1 --format=%%H --grep=git-svn-id" % workspace,
7233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        shell=True).strip()
7333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.base_svn_rev = subprocess.check_output(
7433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        "cd %s; git log -1 %s"          # Get commit description.
7533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        " | grep -e '^\s*git-svn-id:'"  # Extract "git-svn-id" line.
7633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        " | awk '{print $2}'"           # Extract "repository@revision" part.
7733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        " | sed -e 's/.*@//'" %         # Strip away "repository@".
7833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        (workspace, self.base_rev), shell=True).strip()
7933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.patch = subprocess.check_output(
8033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        "cd %s; git diff %s" % (workspace, self.base_rev), shell=True)
8133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.binaries = {}
8233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.initialization_lock = threading.Lock()
8333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.initialization_lock.acquire()  # Released when init is done.
8433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self._OpenLocalConnection()
8533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_receiver_thread = threading.Thread(
8633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        target=self._ListenLocalConnection)
8733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_receiver_thread.daemon = True
8833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_receiver_thread.start()
8933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.initialization_lock.acquire()
9033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.initialization_lock.release()
9133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
9233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def _OpenLocalConnection(self):
9333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
9433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    code = self.local_socket.connect_ex(("localhost", constants.CLIENT_PORT))
9533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if code != 0:
9633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      raise RuntimeError("Failed to connect to local server")
9733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    compression.Send([constants.REQUEST_PUBKEY_FINGERPRINT], self.local_socket)
9833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
9933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def _ListenLocalConnection(self):
10033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    release_lock_countdown = 1  # Pubkey.
10133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_receiver = compression.Receiver(self.local_socket)
10233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    while not self.local_receiver.IsDone():
10333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      data = self.local_receiver.Current()
10433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      if data[0] == constants.REQUEST_PUBKEY_FINGERPRINT:
10533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        pubkey = data[1]
10633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        if not pubkey: raise RuntimeError("Received empty public key")
10733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        self.pubkey_fingerprint = pubkey
10833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        release_lock_countdown -= 1
10933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      if release_lock_countdown == 0:
11033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        self.initialization_lock.release()
11133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        release_lock_countdown -= 1  # Prevent repeated triggering.
11233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self.local_receiver.Advance()
11333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
11433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def Run(self, jobs):
11533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.indicator.Starting()
11633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    need_libv8 = False
11733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    for s in self.suites:
11833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      shell = s.shell()
11933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      if shell not in self.binaries:
12033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        path = os.path.join(self.context.shell_dir, shell)
12133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        # Check if this is a shared library build.
12233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        try:
12333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          ldd = subprocess.check_output("ldd %s | grep libv8\\.so" % (path),
12433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                                        shell=True)
12533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          ldd = ldd.strip().split(" ")
12633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          assert ldd[0] == "libv8.so"
12733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          assert ldd[1] == "=>"
12833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          need_libv8 = True
12933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          binary_needs_libv8 = True
13033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          libv8 = signatures.ReadFileAndSignature(ldd[2])
13133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        except:
13233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          binary_needs_libv8 = False
13333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        binary = signatures.ReadFileAndSignature(path)
13433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        if binary[0] is None:
13533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          print("Error: Failed to create signature.")
13633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          assert binary[1] != 0
13733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          return binary[1]
13833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        binary.append(binary_needs_libv8)
13933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        self.binaries[shell] = binary
14033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if need_libv8:
14133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self.binaries["libv8.so"] = libv8
14233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    distro.Assign(self.suites, self.peers)
14333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    # Spawn one thread for each peer.
14433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    threads = []
14533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    for p in self.peers:
14633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      thread = threading.Thread(target=self._TalkToPeer, args=[p])
14733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      threads.append(thread)
14833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      thread.start()
14933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    try:
15033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      for thread in threads:
15133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        # Use a timeout so that signals (Ctrl+C) will be processed.
15233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        thread.join(timeout=10000000)
15333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self._AnalyzePeerRuntimes()
15433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    except KeyboardInterrupt:
15533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self.terminate = True
15633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      raise
15733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    except Exception, _e:
15833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      # If there's an exception we schedule an interruption for any
15933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      # remaining threads...
16033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self.terminate = True
16133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      # ...and then reraise the exception to bail out.
16233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      raise
16333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    compression.Send(constants.END_OF_STREAM, self.local_socket)
16433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.local_socket.close()
16533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if self.tests:
16633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self._RunInternal(jobs)
16733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    self.indicator.Done()
16833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    return not self.failed
16933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
17033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def _TalkToPeer(self, peer):
17133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
17233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    sock.settimeout(self.context.timeout + 10)
17333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    code = sock.connect_ex((peer.address, constants.PEER_PORT))
17433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if code == 0:
17533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      try:
17633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        peer.runtime = None
17733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        start_time = time.time()
17833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        packet = workpacket.WorkPacket(peer=peer, context=self.context,
17933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                                       base_revision=self.base_svn_rev,
18033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                                       patch=self.patch,
18133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                                       pubkey=self.pubkey_fingerprint)
18233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        data, test_map = packet.Pack(self.binaries)
18333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        compression.Send(data, sock)
18433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        compression.Send(constants.END_OF_STREAM, sock)
18533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        rec = compression.Receiver(sock)
18633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        while not rec.IsDone() and not self.terminate:
18733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          data_list = rec.Current()
18833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          for data in data_list:
18933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org            test_id = data[0]
19033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org            if test_id < 0:
19133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              # The peer is reporting an error.
19233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              with self.lock:
19333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                print("\nPeer %s reports error: %s" % (peer.address, data[1]))
19433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              continue
19533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org            test = test_map.pop(test_id)
19633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org            test.MergeResult(data)
19733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org            try:
19833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              self.perfdata.UpdatePerfData(test)
19933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org            except Exception, e:
20033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              print("UpdatePerfData exception: %s" % e)
20133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              pass  # Just keep working.
20233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org            with self.lock:
20333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              perf_key = self.perfdata.GetKey(test)
20433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              compression.Send(
20533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                  [constants.INFORM_DURATION, perf_key, test.duration,
20633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                   self.context.arch, self.context.mode],
20733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                  self.local_socket)
20833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              self.indicator.AboutToRun(test)
209b752d4061aaeb7d6a6ec368607871789d54b0207dslomov@chromium.org              has_unexpected_output = test.suite.HasUnexpectedOutput(test)
210b752d4061aaeb7d6a6ec368607871789d54b0207dslomov@chromium.org              if has_unexpected_output:
21133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                self.failed.append(test)
21233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                if test.output.HasCrashed():
21333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                  self.crashed += 1
21433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              else:
21533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                self.succeeded += 1
21633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org              self.remaining -= 1
217b752d4061aaeb7d6a6ec368607871789d54b0207dslomov@chromium.org              self.indicator.HasRun(test, has_unexpected_output)
21833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org          rec.Advance()
21933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        peer.runtime = time.time() - start_time
22033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      except KeyboardInterrupt:
22133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        sock.close()
22233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        raise
22333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      except Exception, e:
22433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        print("Got exception: %s" % e)
22533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        pass  # Fall back to local execution.
22633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    else:
22733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      compression.Send([constants.UNRESPONSIVE_PEER, peer.address],
22833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                       self.local_socket)
22933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    sock.close()
23033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    if len(test_map) > 0:
23133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      # Some tests have not received any results. Run them locally.
23233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      print("\nNo results for %d tests, running them locally." % len(test_map))
23333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      self._EnqueueLocally(test_map)
23433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
23533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def _EnqueueLocally(self, test_map):
23633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    with self.tests_lock:
23733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      for test in test_map:
23833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        self.tests.append(test_map[test])
23933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org
24033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org  def _AnalyzePeerRuntimes(self):
24133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    total_runtime = 0.0
24233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    total_work = 0.0
24333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    for p in self.peers:
24433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      if p.runtime is None:
24533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org        return
24633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      total_runtime += p.runtime
24733e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      total_work += p.assigned_work
24833e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org    for p in self.peers:
24933e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      p.assigned_work /= total_work
25033e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      p.runtime /= total_runtime
25133e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      perf_correction = p.assigned_work / p.runtime
25233e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      old_perf = p.relative_performance
25333e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      p.relative_performance = (old_perf + perf_correction) / 2.0
25433e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org      compression.Send([constants.UPDATE_PERF, p.address,
25533e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                        p.relative_performance],
25633e09c8efd078308de3c77a88301566f65c07befverwaest@chromium.org                       self.local_socket)
257