| # Copyright 2023 The Chromium Authors | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| """Various helper functions related to working with websockets.""" | |
| import logging | |
| import time | |
| from gpu_tests import common_typing as ct | |
| from gpu_tests.util import websocket_server as wss | |
| def HandleWebsocketReceiveTimeoutError( | |
| tab: ct.Tab, start_time: float, additional_info: str | None = None | |
| ) -> None: | |
| """Helper function for when a message is not received on time. | |
| Args: | |
| tab: The Telemetry Tab that the test was run in. | |
| start_time: The time.time() value that the test was started at. | |
| additional_info: An optional string to output alongside common logging. | |
| """ | |
| logging.error( | |
| 'Timed out waiting for websocket message (%.3f seconds since test ' | |
| 'start), checking for hung renderer', | |
| time.time() - start_time, | |
| ) | |
| if additional_info: | |
| logging.error( | |
| 'Additional information provided by test: %s', additional_info | |
| ) | |
| # Telemetry has some code to automatically crash the renderer and GPU | |
| # processes if it thinks that the renderer is hung. So, execute some | |
| # trivial JavaScript now to hit that code if we got the timeout because of | |
| # a hung renderer. If we do detect a hung renderer, this will raise | |
| # another exception and prevent the following line about the renderer not | |
| # being hung from running. | |
| tab.action_runner.EvaluateJavaScript('let somevar = undefined;', timeout=5) | |
| logging.error('Timeout does *not* appear to be due to a hung renderer') | |
| def HandlePrematureSocketClose( | |
| original_error: wss.ClientClosedConnectionError, | |
| start_time: float, | |
| additional_info: str | None = None, | |
| ) -> None: | |
| """Helper function for when a websocket connection is closed early. | |
| Args: | |
| original_error: The original error that was raised to signal a socket | |
| closure. | |
| start_time: The time.time() value that the test was started at. | |
| additional_info: An optional string to output alongside common logging. | |
| """ | |
| elapsed = time.time() - start_time | |
| extra_info_str = '' | |
| if additional_info: | |
| extra_info_str = ( | |
| f' Additional information provided by the test: {additional_info}' | |
| ) | |
| raise RuntimeError( | |
| f'Detected closed websocket ({elapsed:.3f} seconds since test start) - ' | |
| f'likely caused by a renderer crash.{extra_info_str}' | |
| ) from original_error | |
| def GetScaledConnectionTimeout(num_jobs: int) -> float: | |
| """Gets a scaled Websocket setup timeout based on number of test jobs. | |
| Args: | |
| num_jobs: How many parallel test jobs are being run. | |
| Returns: | |
| The scaled timeout to pass to WaitForConnection that accounts for slowness | |
| caused by multiple test jobs. | |
| """ | |
| # Target a 2x multiplier when running 4 jobs. | |
| multiplier = 1 + (num_jobs - 1) / 3.0 | |
| return multiplier * wss.WEBSOCKET_SETUP_TIMEOUT_SECONDS |