Revert "Switch WebGL tests to heartbeat"
This reverts commit d88b939650
.
Reason for revert: Causing Fuchsia builders to time out
Original change's description:
> Switch WebGL tests to heartbeat
>
> Switches the WebGL conformance tests to use a heartbeat mechanism
> like the WebGPU conformance tests instead of a fixed 5 minute
> timeout. The 5 minute timeout still exists, but should basically
> never be hit.
>
> The end result of this is that we should fail much faster in
> cases of hung/crashed renderers. Before, we would take 5 minutes
> to detect these, but now we can detect them within 15 seconds.
> This will help normalize shard times and open up opportunities to
> make further improvements such as lowering the shard timeout we
> use.
>
> No noticeable impact to test runtime when tests run normally.
>
> Synopsis of changes under the hood:
> * Moved the WebGL harness JavaScript code into dedicated
> JavaScript files instead of defining them directly in the Python
> test harness file.
> * Generalized the WebGPU websocket code for use in both test
> suites
> * Added Slow expectation support, which is necessary to address
> slow heartbeats on a few configurations
> * Adjusted the number of parallel jobs on some configurations to
> ensure heartbeats are sent on time instead of being delayed due
> to the hardware being hit too hard
>
> Bug: 1354797
> Change-Id: Ie862bd081d9e97947efd10400ab5c7337215124a
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3840756
> Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
> Commit-Queue: Brian Sheedy <bsheedy@chromium.org>
> Reviewed-by: Kenneth Russell <kbr@chromium.org>
> Reviewed-by: Ben Pastene <bpastene@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#1054455}
Bug: 1354797
Change-Id: Ia541bca2b4cd8955e6d8e3ea7adeb61f156626d6
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3926272
Auto-Submit: Chong Gu <chonggu@google.com>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Reviewed-by: Ben Pastene <bpastene@chromium.org>
Commit-Queue: Chong Gu <chonggu@google.com>
Cr-Commit-Position: refs/heads/main@{#1055024}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
6aa2d5ea75
commit
85ae84b891
.vpython3
content/test/gpu/gpu_tests
testing/buildbot
@ -166,7 +166,7 @@ wheel: <
|
||||
version: "version:8.3.1"
|
||||
# There is currently no Linux arm/arm64 version in CIPD.
|
||||
not_match_tag <
|
||||
platform: "linux_arm64"
|
||||
platform: "linux_aarch64"
|
||||
>
|
||||
>
|
||||
wheel: <
|
||||
@ -174,7 +174,7 @@ wheel: <
|
||||
version: "version:4.5.3.56.chromium.4"
|
||||
# There is currently no Linux arm/arm64 version in CIPD.
|
||||
not_match_tag <
|
||||
platform: "linux_arm64"
|
||||
platform: "linux_aarch64"
|
||||
>
|
||||
>
|
||||
|
||||
@ -476,7 +476,7 @@ wheel: <
|
||||
|
||||
wheel: <
|
||||
name: "infra/python/wheels/websockets-py3"
|
||||
version: "version:10.3"
|
||||
version: "version:10.1"
|
||||
>
|
||||
|
||||
# Used by:
|
||||
@ -525,7 +525,7 @@ wheel: <
|
||||
name: "infra/python/wheels/pandas/${vpython_platform}"
|
||||
version: "version:1.3.2.chromium.1"
|
||||
not_match_tag: <
|
||||
platform: "linux_arm64"
|
||||
platform: "linux_aarch64"
|
||||
>
|
||||
>
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
// Copyright 2022 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
window.onload = function() { window._loaded = true; }
|
@ -1,137 +0,0 @@
|
||||
// Copyright 2022 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
const HEARTBEAT_THROTTLE_MS = 5000;
|
||||
|
||||
class WebSocketWrapper {
|
||||
constructor() {
|
||||
this.queued_messages = [];
|
||||
this.throttle_timer = null;
|
||||
this.last_heartbeat = null;
|
||||
this.socket = null;
|
||||
|
||||
this._sendDelayedHeartbeat = this._sendDelayedHeartbeat.bind(this);
|
||||
}
|
||||
|
||||
setWebSocket(s) {
|
||||
this.socket = s;
|
||||
for (let qm of this.queued_messages) {
|
||||
s.send(qm);
|
||||
}
|
||||
}
|
||||
|
||||
_sendMessage(message) {
|
||||
if (this.socket === null) {
|
||||
this.queued_messages.push(message);
|
||||
} else {
|
||||
this.socket.send(message);
|
||||
}
|
||||
}
|
||||
|
||||
_sendHeartbeat() {
|
||||
this._sendMessage('{"type": "TEST_HEARTBEAT"}');
|
||||
}
|
||||
|
||||
_sendDelayedHeartbeat() {
|
||||
this.throttle_timer = null;
|
||||
this.last_heartbeat = +new Date();
|
||||
this._sendHeartbeat();
|
||||
}
|
||||
|
||||
sendHeartbeatThrottled() {
|
||||
const now = +new Date();
|
||||
// Heartbeat already scheduled.
|
||||
if (this.throttle_timer !== null) {
|
||||
// If we've already passed the point in time where the heartbeat should
|
||||
// have been sent, cancel it and send it immediately. This helps in cases
|
||||
// where we've scheduled one, but the test is doing so much work that
|
||||
// the callback doesn't fire in a reasonable amount of time.
|
||||
if (this.last_heartbeat !== null &&
|
||||
now - this.last_heartbeat >= HEARTBEAT_THROTTLE_MS) {
|
||||
this._clearPendingHeartbeat();
|
||||
this.last_heartbeat = now;
|
||||
this._sendHeartbeat();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Send a heartbeat immediately.
|
||||
if (this.last_heartbeat === null ||
|
||||
now - this.last_heartbeat >= HEARTBEAT_THROTTLE_MS){
|
||||
this.last_heartbeat = now;
|
||||
this._sendHeartbeat();
|
||||
return;
|
||||
}
|
||||
// Schedule a heartbeat for the future.
|
||||
this.throttle_timer = setTimeout(
|
||||
this._sendDelayedHeartbeat, HEARTBEAT_THROTTLE_MS);
|
||||
}
|
||||
|
||||
_clearPendingHeartbeat() {
|
||||
if (this.throttle_timer !== null) {
|
||||
clearTimeout(this.throttle_timer);
|
||||
this.throttle_timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
sendTestFinished() {
|
||||
this._clearPendingHeartbeat();
|
||||
this._sendMessage('{"type": "TEST_FINISHED"}');
|
||||
}
|
||||
}
|
||||
|
||||
if (window.parent.wrapper !== undefined) {
|
||||
const wrapper = window.parent.wrapper;
|
||||
} else {
|
||||
const wrapper = new WebSocketWrapper();
|
||||
window.wrapper = wrapper;
|
||||
}
|
||||
|
||||
function connectWebsocket(port) {
|
||||
let socket = new WebSocket('ws://127.0.0.1:' + port);
|
||||
socket.addEventListener('open', () => {
|
||||
wrapper.setWebSocket(socket);
|
||||
});
|
||||
}
|
||||
|
||||
var testHarness = {};
|
||||
testHarness._allTestSucceeded = true;
|
||||
testHarness._messages = '';
|
||||
testHarness._failures = 0;
|
||||
testHarness._finished = false;
|
||||
testHarness._originalLog = window.console.log;
|
||||
|
||||
testHarness.log = function(msg) {
|
||||
wrapper.sendHeartbeatThrottled();
|
||||
testHarness._messages += msg + "\n";
|
||||
testHarness._originalLog.apply(window.console, [msg]);
|
||||
}
|
||||
|
||||
testHarness.reportResults = function(url, success, msg) {
|
||||
wrapper.sendHeartbeatThrottled();
|
||||
testHarness._allTestSucceeded = testHarness._allTestSucceeded && !!success;
|
||||
if(!success) {
|
||||
testHarness._failures++;
|
||||
if(msg) {
|
||||
testHarness.log(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
testHarness.notifyFinished = function(url) {
|
||||
wrapper.sendTestFinished();
|
||||
testHarness._finished = true;
|
||||
};
|
||||
testHarness.navigateToPage = function(src) {
|
||||
var testFrame = document.getElementById("test-frame");
|
||||
testFrame.src = src;
|
||||
};
|
||||
|
||||
window.webglTestHarness = testHarness;
|
||||
window.parent.webglTestHarness = testHarness;
|
||||
window.console.log = testHarness.log;
|
||||
window.onerror = function(message, url, line) {
|
||||
testHarness.reportResults(null, false, message);
|
||||
testHarness.notifyFinished(null);
|
||||
};
|
||||
window.quietMode = function() { return true; }
|
@ -212,9 +212,6 @@ crbug.com/891953 [ mac ] WebglExtension_OVR_multiview2 [ Failure ]
|
||||
crbug.com/891953 [ android ] WebglExtension_OVR_multiview2 [ Failure ]
|
||||
crbug.com/891953 [ linux display-server-wayland ] WebglExtension_OVR_multiview2 [ Failure ]
|
||||
|
||||
# Can take a rather long time to load, during which heartbeats aren't sent.
|
||||
conformance2/sync/sync-webgl-specific.html [ Slow ]
|
||||
|
||||
# ========================
|
||||
# Conformance expectations
|
||||
# ========================
|
||||
@ -415,8 +412,6 @@ crbug.com/angleproject/6430 [ mac passthrough angle-metal apple-angle-metal-rend
|
||||
crbug.com/1298619 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] deqp/functional/gles3/occlusionquery_strict.html [ Failure ]
|
||||
crbug.com/angleproject/7397 [ mac passthrough angle-metal apple-angle-metal-renderer:-apple-m1 ] conformance2/renderbuffers/invalidate-framebuffer.html [ Failure ]
|
||||
|
||||
crbug.com/1363349 [ mac passthrough angle-metal ] conformance/glsl/bugs/complex-glsl-does-not-crash.html [ Slow ]
|
||||
|
||||
######################################################################
|
||||
# Mac failures (mainly OpenGL; some need to be reevaluated on Metal) #
|
||||
######################################################################
|
||||
|
@ -526,8 +526,6 @@ crbug.com/1336736 [ win angle-d3d11 ] conformance/textures/misc/texture-video-tr
|
||||
|
||||
crbug.com/982294 [ win debug passthrough nvidia ] conformance/uniforms/uniform-samplers-test.html [ RetryOnFailure ]
|
||||
|
||||
crbug.com/1364333 [ win debug angle-vulkan passthrough ] conformance/glsl/bugs/temp-expressions-should-not-crash.html [ Slow ]
|
||||
crbug.com/1364333 [ win debug angle-vulkan passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ]
|
||||
[ win angle-swiftshader passthrough ] conformance/uniforms/no-over-optimization-on-uniform-array-* [ Slow ]
|
||||
[ win angle-swiftshader passthrough ] conformance/renderbuffers/framebuffer-object-attachment.html [ Slow ]
|
||||
|
||||
@ -573,7 +571,6 @@ crbug.com/angleproject/4846 [ mac angle-metal passthrough ] conformance/uniforms
|
||||
crbug.com/angleproject/5505 [ mac angle-metal passthrough ] conformance/ogles/GL/acos/acos_001_to_006.html [ Failure ]
|
||||
crbug.com/angleproject/5505 [ mac angle-metal passthrough ] conformance/ogles/GL/asin/asin_001_to_006.html [ Failure ]
|
||||
crbug.com/angleproject/6489 [ mac angle-metal passthrough ] conformance/ogles/GL/build/build_009_to_016.html [ Failure ]
|
||||
crbug.com/1363349 [ mac passthrough angle-metal ] conformance/glsl/bugs/complex-glsl-does-not-crash.html [ Slow ]
|
||||
|
||||
# Mac / Passthrough command decoder / Metal / Intel
|
||||
crbug.com/angleproject/4846 [ mac angle-metal passthrough intel ] conformance/rendering/rendering-stencil-large-viewport.html [ Failure ]
|
||||
|
@ -1,141 +0,0 @@
|
||||
# Copyright 2022 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
"""Code to allow tests to communicate via a websocket server."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import sys
|
||||
import threading
|
||||
from typing import Optional
|
||||
|
||||
import websockets # pylint: disable=import-error
|
||||
import websockets.server as ws_server # pylint: disable=import-error
|
||||
|
||||
WEBSOCKET_PORT_TIMEOUT_SECONDS = 10
|
||||
WEBSOCKET_SETUP_TIMEOUT_SECONDS = 5
|
||||
|
||||
# The client (Chrome) should never be closing the connection. If it does, it's
|
||||
# indicative of something going wrong like a renderer crash.
|
||||
ClientClosedConnectionError = websockets.exceptions.ConnectionClosedOK
|
||||
|
||||
# Alias for readability and so that users don't have to import asyncio.
|
||||
WebsocketReceiveMessageTimeoutError = asyncio.TimeoutError
|
||||
|
||||
|
||||
class WebsocketServer():
|
||||
def __init__(self):
|
||||
"""Server that abstracts the asyncio calls used under the hood.
|
||||
|
||||
Only supports one active connection at a time.
|
||||
"""
|
||||
self.server_port = None
|
||||
self.server_stopper = None
|
||||
self.connection_stopper = None
|
||||
self.websocket = None
|
||||
self.port_set_event = threading.Event()
|
||||
self.connection_received_event = threading.Event()
|
||||
self.event_loop = None
|
||||
self._server_thread = None
|
||||
|
||||
def StartServer(self) -> None:
|
||||
"""Starts the websocket server on a separate thread."""
|
||||
assert self._server_thread is None, 'Server already running'
|
||||
self._server_thread = _ServerThread(self)
|
||||
self._server_thread.daemon = True
|
||||
self._server_thread.start()
|
||||
got_port = self.port_set_event.wait(WEBSOCKET_PORT_TIMEOUT_SECONDS)
|
||||
if not got_port:
|
||||
raise RuntimeError('Websocket server did not provide a port')
|
||||
# Through some existing Telemetry magic, we don't need to set up port
|
||||
# forwarding for remote platforms (ChromeOS/Android). We can provide the
|
||||
# actual server port on these platforms and the page can connect just fine.
|
||||
|
||||
def ClearCurrentConnection(self) -> None:
|
||||
if self.connection_stopper:
|
||||
self.connection_stopper.cancel()
|
||||
try:
|
||||
self.connection_stopper.exception()
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
self.connection_stopper = None
|
||||
self.websocket = None
|
||||
self.connection_received_event.clear()
|
||||
|
||||
def WaitForConnection(self, timeout: Optional[int] = None) -> None:
|
||||
if self.websocket:
|
||||
return
|
||||
timeout = timeout or WEBSOCKET_SETUP_TIMEOUT_SECONDS
|
||||
self.connection_received_event.wait(timeout)
|
||||
if not self.websocket:
|
||||
raise RuntimeError('Websocket connection was not established')
|
||||
|
||||
def StopServer(self) -> None:
|
||||
self.ClearCurrentConnection()
|
||||
if self.server_stopper:
|
||||
self.server_stopper.cancel()
|
||||
try:
|
||||
self.server_stopper.exception()
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
self.server_stopper = None
|
||||
self.server_port = None
|
||||
|
||||
self._server_thread.join(5)
|
||||
if self._server_thread.is_alive():
|
||||
logging.error(
|
||||
'Websocket server did not shut down properly - this might be '
|
||||
'indicative of an issue in the test harness')
|
||||
|
||||
def Send(self, message: str) -> None:
|
||||
asyncio.run_coroutine_threadsafe(self.websocket.send(message),
|
||||
self.event_loop)
|
||||
|
||||
def Receive(self, timeout: int) -> str:
|
||||
future = asyncio.run_coroutine_threadsafe(
|
||||
asyncio.wait_for(self.websocket.recv(), timeout), self.event_loop)
|
||||
try:
|
||||
return future.result()
|
||||
except asyncio.exceptions.TimeoutError as e:
|
||||
raise WebsocketReceiveMessageTimeoutError(
|
||||
'Timed out after %d seconds waiting for websocket message' %
|
||||
timeout) from e
|
||||
|
||||
|
||||
class _ServerThread(threading.Thread):
|
||||
def __init__(self, server_instance: WebsocketServer, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._server_instance = server_instance
|
||||
|
||||
def run(self) -> None:
|
||||
try:
|
||||
asyncio.run(StartWebsocketServer(self._server_instance))
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
sys.stdout.write('Server thread had an exception: %s\n' % e)
|
||||
|
||||
|
||||
async def StartWebsocketServer(server_instance: WebsocketServer) -> None:
|
||||
async def HandleWebsocketConnection(
|
||||
websocket: ws_server.WebSocketServerProtocol) -> None:
|
||||
# We only allow one active connection - if there are multiple, something is
|
||||
# wrong.
|
||||
assert server_instance.connection_stopper is None
|
||||
assert server_instance.websocket is None
|
||||
server_instance.connection_stopper = asyncio.Future()
|
||||
# Keep our own reference in case the server clears its reference before the
|
||||
# await finishes.
|
||||
connection_stopper = server_instance.connection_stopper
|
||||
server_instance.websocket = websocket
|
||||
server_instance.connection_received_event.set()
|
||||
await connection_stopper
|
||||
|
||||
async with websockets.serve(HandleWebsocketConnection, '127.0.0.1',
|
||||
0) as server:
|
||||
server_instance.event_loop = asyncio.get_running_loop()
|
||||
server_instance.server_port = server.sockets[0].getsockname()[1]
|
||||
server_instance.port_set_event.set()
|
||||
server_instance.server_stopper = asyncio.Future()
|
||||
server_stopper = server_instance.server_stopper
|
||||
await server_stopper
|
@ -3,11 +3,9 @@
|
||||
# found in the LICENSE file.
|
||||
|
||||
import logging
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from typing import Any, List, Optional, Set, Tuple
|
||||
import unittest
|
||||
|
||||
@ -16,29 +14,54 @@ from gpu_tests import common_typing as ct
|
||||
from gpu_tests import gpu_helper
|
||||
from gpu_tests import gpu_integration_test
|
||||
from gpu_tests import webgl_test_util
|
||||
from gpu_tests.util import websocket_server
|
||||
|
||||
import gpu_path_util
|
||||
|
||||
from telemetry.internal.platform import gpu_info as telemetry_gpu_info
|
||||
|
||||
JAVASCRIPT_DIR = os.path.join(gpu_path_util.GPU_DIR, 'gpu_tests', 'javascript')
|
||||
conformance_harness_script = r"""
|
||||
var testHarness = {};
|
||||
testHarness._allTestSucceeded = true;
|
||||
testHarness._messages = '';
|
||||
testHarness._failures = 0;
|
||||
testHarness._finished = false;
|
||||
testHarness._originalLog = window.console.log;
|
||||
|
||||
WEBSOCKET_JAVASCRIPT_TIMEOUT_S = 30
|
||||
HEARTBEAT_TIMEOUT_S = 15
|
||||
ASAN_MULTIPLIER = 2
|
||||
SLOW_MULTIPLIER = 4
|
||||
testHarness.log = function(msg) {
|
||||
testHarness._messages += msg + "\n";
|
||||
testHarness._originalLog.apply(window.console, [msg]);
|
||||
}
|
||||
|
||||
# Non-standard timeouts that can't be handled by a Slow expectation, likely due
|
||||
# to being particularly long or not specific to a configuration. Try to use
|
||||
# expectations first.
|
||||
NON_STANDARD_HEARTBEAT_TIMEOUTS = {}
|
||||
testHarness.reportResults = function(url, success, msg) {
|
||||
testHarness._allTestSucceeded = testHarness._allTestSucceeded && !!success;
|
||||
if(!success) {
|
||||
testHarness._failures++;
|
||||
if(msg) {
|
||||
testHarness.log(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
testHarness.notifyFinished = function(url) {
|
||||
testHarness._finished = true;
|
||||
};
|
||||
testHarness.navigateToPage = function(src) {
|
||||
var testFrame = document.getElementById("test-frame");
|
||||
testFrame.src = src;
|
||||
};
|
||||
|
||||
# Non-standard timeouts for executing the JavaScript to establish the websocket
|
||||
# connection. A test being in here implies that it starts doing a huge amount
|
||||
# of work in JavaScript immediately, preventing execution of JavaScript via
|
||||
# devtools as well.
|
||||
NON_STANDARD_WEBSOCKET_JAVASCRIPT_TIMEOUTS = {}
|
||||
window.webglTestHarness = testHarness;
|
||||
window.parent.webglTestHarness = testHarness;
|
||||
window.console.log = testHarness.log;
|
||||
window.onerror = function(message, url, line) {
|
||||
testHarness.reportResults(null, false, message);
|
||||
testHarness.notifyFinished(null);
|
||||
};
|
||||
window.quietMode = function() { return true; }
|
||||
"""
|
||||
|
||||
extension_harness_additional_script = r"""
|
||||
window.onload = function() { window._loaded = true; }
|
||||
"""
|
||||
|
||||
# cmp no longer exists in Python 3
|
||||
def cmp(a: Any, b: Any) -> int:
|
||||
@ -72,12 +95,6 @@ class WebGLConformanceIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
_verified_flags = False
|
||||
_original_environ = None
|
||||
|
||||
# Scripts read from file during process start up.
|
||||
_conformance_harness_script = None
|
||||
_extension_harness_additional_script = None
|
||||
|
||||
websocket_server = None
|
||||
|
||||
@classmethod
|
||||
def Name(cls) -> str:
|
||||
return 'webgl_conformance'
|
||||
@ -98,13 +115,6 @@ class WebGLConformanceIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
return {
|
||||
# crbug.com/1347970.
|
||||
'conformance/textures/misc/texture-video-transparent.html',
|
||||
# Specifically when using Metal, this test can be rather slow. When run
|
||||
# in parallel, even a minute is not long enough for it to reliably run,
|
||||
# as it does not properly send heartbeats (possibly due to a large
|
||||
# amount of work being done). Instead of increasing the heartbeat
|
||||
# timeout further, run it serially. Can potentially be removed depending
|
||||
# on the response to crbug.com/1363349.
|
||||
'conformance/glsl/bugs/complex-glsl-does-not-crash.html',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
@ -126,17 +136,6 @@ class WebGLConformanceIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
@classmethod
|
||||
def _SetClassVariablesFromOptions(cls, options: ct.ParsedCmdArgs) -> None:
|
||||
cls._webgl_version = int(options.webgl_conformance_version.split('.')[0])
|
||||
if not cls._conformance_harness_script:
|
||||
with open(
|
||||
os.path.join(JAVASCRIPT_DIR,
|
||||
'webgl_conformance_harness_script.js')) as f:
|
||||
cls._conformance_harness_script = f.read()
|
||||
if not cls._extension_harness_additional_script:
|
||||
with open(
|
||||
os.path.join(
|
||||
JAVASCRIPT_DIR,
|
||||
'webgl_conformance_extension_harness_additional_script.js')) as f:
|
||||
cls._extension_harness_additional_script = f.read()
|
||||
|
||||
@classmethod
|
||||
def GenerateGpuTests(cls, options: ct.ParsedCmdArgs) -> ct.TestGenerator:
|
||||
@ -343,86 +342,10 @@ class WebGLConformanceIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
self._verified_flags = True
|
||||
url = self.UrlOfStaticFilePath(test_path)
|
||||
self.tab.Navigate(url, script_to_evaluate_on_commit=harness_script)
|
||||
self.tab.action_runner.EvaluateJavaScript(
|
||||
'connectWebsocket("%d")' %
|
||||
WebGLConformanceIntegrationTest.websocket_server.server_port,
|
||||
timeout=self._GetWebsocketJavaScriptTimeout())
|
||||
WebGLConformanceIntegrationTest.websocket_server.WaitForConnection()
|
||||
|
||||
def _HandleMessageLoop(self, test_timeout: float) -> None:
|
||||
start_time = time.time()
|
||||
try:
|
||||
while True:
|
||||
response = WebGLConformanceIntegrationTest.websocket_server.Receive(
|
||||
self._GetHeartbeatTimeout())
|
||||
response = json.loads(response)
|
||||
response_type = response['type']
|
||||
|
||||
if time.time() - start_time > test_timeout:
|
||||
raise RuntimeError(
|
||||
'Hit %.3f second global timeout, but page continued to send '
|
||||
'messages over the websocket, i.e. was not due to a renderer '
|
||||
'crash.' % test_timeout)
|
||||
|
||||
if response_type == 'TEST_HEARTBEAT':
|
||||
continue
|
||||
if response_type == 'TEST_FINISHED':
|
||||
break
|
||||
raise RuntimeError('Received unknown message type %s' % response_type)
|
||||
except websocket_server.WebsocketReceiveMessageTimeoutError:
|
||||
logging.error(
|
||||
'Timed out waiting for websocket message, checking for hung renderer')
|
||||
# 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.
|
||||
self.tab.action_runner.EvaluateJavaScript('let somevar = undefined;',
|
||||
timeout=5)
|
||||
logging.error('Timeout does *not* appear to be due to a hung renderer')
|
||||
raise
|
||||
except websocket_server.ClientClosedConnectionError as e:
|
||||
raise RuntimeError(
|
||||
'Detected closed websocket - likely caused by a renderer '
|
||||
'crash') from e
|
||||
finally:
|
||||
WebGLConformanceIntegrationTest.websocket_server.ClearCurrentConnection()
|
||||
|
||||
def _GetWebsocketJavaScriptTimeout(self) -> int:
|
||||
# Most tests should be able to run JavaScript immediately after page load.
|
||||
# However, some tests will do so much work that we're unable to actually
|
||||
# run the JavaScript for quite a while.
|
||||
return int(
|
||||
NON_STANDARD_WEBSOCKET_JAVASCRIPT_TIMEOUTS.get(
|
||||
self.shortName(), WEBSOCKET_JAVASCRIPT_TIMEOUT_S) *
|
||||
self._GetTimeoutMultiplier())
|
||||
|
||||
def _GetHeartbeatTimeout(self) -> int:
|
||||
return int(
|
||||
NON_STANDARD_HEARTBEAT_TIMEOUTS.get(self.shortName(),
|
||||
HEARTBEAT_TIMEOUT_S) *
|
||||
self._GetTimeoutMultiplier())
|
||||
|
||||
def _GetTimeoutMultiplier(self) -> float:
|
||||
# Parallel jobs increase load and can slow down test execution, so scale
|
||||
# based on the number of jobs. Target 2x increase with 4 jobs.
|
||||
multiplier = 1 + (self.child.jobs - 1) / 3.0
|
||||
if self.is_asan:
|
||||
multiplier *= ASAN_MULTIPLIER
|
||||
if self._IsSlowTest():
|
||||
multiplier *= SLOW_MULTIPLIER
|
||||
return multiplier
|
||||
|
||||
def _IsSlowTest(self) -> bool:
|
||||
# We access the expectations directly instead of using
|
||||
# self.GetExpectationsForTest since we need the raw results, but that method
|
||||
# only returns the parsed results and whether the test should be retried.
|
||||
expectation = self.child.expectations.expectations_for(self.shortName())
|
||||
return 'Slow' in expectation.raw_results
|
||||
|
||||
def _CheckTestCompletion(self) -> None:
|
||||
self._HandleMessageLoop(self._GetTestTimeout())
|
||||
self.tab.action_runner.WaitForJavaScriptCondition(
|
||||
'webglTestHarness._finished', timeout=self._GetTestTimeout())
|
||||
if self._crash_count != self.browser.GetSystemInfo().gpu \
|
||||
.aux_attributes['process_crash_count']:
|
||||
self.fail('GPU process crashed during test.\n' +
|
||||
@ -431,12 +354,12 @@ class WebGLConformanceIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
self.fail(self._WebGLTestMessages(self.tab))
|
||||
|
||||
def _RunConformanceTest(self, test_path: str, _: WebGLTestArgs) -> None:
|
||||
self._NavigateTo(test_path, self._conformance_harness_script)
|
||||
self._NavigateTo(test_path, conformance_harness_script)
|
||||
self._CheckTestCompletion()
|
||||
|
||||
def _RunExtensionCoverageTest(self, test_path: str,
|
||||
test_args: WebGLTestArgs) -> None:
|
||||
self._NavigateTo(test_path, self._GetExtensionHarnessScript())
|
||||
self._NavigateTo(test_path, _GetExtensionHarnessScript())
|
||||
self.tab.action_runner.WaitForJavaScriptCondition(
|
||||
'window._loaded', timeout=self._GetTestTimeout())
|
||||
context_type = 'webgl2' if test_args.webgl_version == 2 else 'webgl'
|
||||
@ -451,7 +374,7 @@ class WebGLConformanceIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
self._CheckTestCompletion()
|
||||
|
||||
def _RunExtensionTest(self, test_path: str, test_args: WebGLTestArgs) -> None:
|
||||
self._NavigateTo(test_path, self._GetExtensionHarnessScript())
|
||||
self._NavigateTo(test_path, _GetExtensionHarnessScript())
|
||||
self.tab.action_runner.WaitForJavaScriptCondition(
|
||||
'window._loaded', timeout=self._GetTestTimeout())
|
||||
context_type = 'webgl2' if test_args.webgl_version == 2 else 'webgl'
|
||||
@ -468,12 +391,6 @@ class WebGLConformanceIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
timeout *= 2
|
||||
return timeout
|
||||
|
||||
def _GetExtensionHarnessScript(self) -> str:
|
||||
assert self._conformance_harness_script is not None
|
||||
assert self._extension_harness_additional_script is not None
|
||||
return (self._conformance_harness_script +
|
||||
self._extension_harness_additional_script)
|
||||
|
||||
@classmethod
|
||||
def GenerateBrowserArgs(cls, additional_args: List[str]) -> List[str]:
|
||||
"""Adds default arguments to |additional_args|.
|
||||
@ -539,11 +456,6 @@ class WebGLConformanceIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
@classmethod
|
||||
def SetUpProcess(cls) -> None:
|
||||
super(WebGLConformanceIntegrationTest, cls).SetUpProcess()
|
||||
# Logging every time a connection is opened/closed is spammy, so decrease
|
||||
# the default log level.
|
||||
logging.getLogger('websockets.server').setLevel(logging.WARNING)
|
||||
cls.websocket_server = websocket_server.WebsocketServer()
|
||||
cls.websocket_server.StartServer()
|
||||
cls.CustomizeBrowserArgs([])
|
||||
cls.StartBrowser()
|
||||
# By setting multiple server directories, the root of the server
|
||||
@ -556,12 +468,6 @@ class WebGLConformanceIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
webgl_test_util.extensions_relpath)
|
||||
])
|
||||
|
||||
@classmethod
|
||||
def TearDownProcess(cls) -> None:
|
||||
cls.websocket_server.StopServer()
|
||||
cls.websocket_server = None
|
||||
super(WebGLConformanceIntegrationTest, cls).TearDownProcess()
|
||||
|
||||
# Helper functions.
|
||||
|
||||
@staticmethod
|
||||
@ -708,6 +614,10 @@ def _GetGPUInfoErrorString(gpu_info: telemetry_gpu_info.GPUInfo) -> str:
|
||||
return error_str
|
||||
|
||||
|
||||
def _GetExtensionHarnessScript() -> str:
|
||||
return conformance_harness_script + extension_harness_additional_script
|
||||
|
||||
|
||||
def load_tests(loader: unittest.TestLoader, tests: Any,
|
||||
pattern: Any) -> unittest.TestSuite:
|
||||
del loader, tests, pattern # Unused.
|
||||
|
@ -2,17 +2,22 @@
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import asyncio
|
||||
import fnmatch
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from typing import Any, Dict, List, Set
|
||||
import unittest
|
||||
|
||||
import websockets # pylint:disable=import-error
|
||||
import websockets.server as ws_server # pylint: disable=import-error
|
||||
|
||||
from gpu_tests import common_typing as ct
|
||||
from gpu_tests import gpu_integration_test
|
||||
from gpu_tests.util import websocket_server
|
||||
|
||||
import gpu_path_util
|
||||
|
||||
@ -59,6 +64,37 @@ class WebGpuTestResult():
|
||||
self.log_pieces = []
|
||||
|
||||
|
||||
async def StartWebsocketServer() -> None:
|
||||
async def HandleWebsocketConnection(
|
||||
websocket: ws_server.WebSocketServerProtocol) -> None:
|
||||
# We only allow one active connection - if there are multiple, something is
|
||||
# wrong.
|
||||
assert WebGpuCtsIntegrationTest.connection_stopper is None
|
||||
assert WebGpuCtsIntegrationTest.websocket is None
|
||||
WebGpuCtsIntegrationTest.connection_stopper = asyncio.Future()
|
||||
WebGpuCtsIntegrationTest.websocket = websocket
|
||||
WebGpuCtsIntegrationTest.connection_received_event.set()
|
||||
await WebGpuCtsIntegrationTest.connection_stopper
|
||||
|
||||
async with websockets.serve(HandleWebsocketConnection, '127.0.0.1',
|
||||
0) as server:
|
||||
WebGpuCtsIntegrationTest.event_loop = asyncio.get_running_loop()
|
||||
WebGpuCtsIntegrationTest.server_port = server.sockets[0].getsockname()[1]
|
||||
WebGpuCtsIntegrationTest.port_set_event.set()
|
||||
WebGpuCtsIntegrationTest.server_stopper = asyncio.Future()
|
||||
await WebGpuCtsIntegrationTest.server_stopper
|
||||
|
||||
|
||||
class ServerThread(threading.Thread):
|
||||
def run(self) -> None:
|
||||
try:
|
||||
asyncio.run(StartWebsocketServer())
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
except Exception as e: # pylint:disable=broad-except
|
||||
sys.stdout.write('Server thread had exception: %s\n' % e)
|
||||
|
||||
|
||||
class WebGpuCtsIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
# Whether the test page has already been loaded. Caching this state here is
|
||||
# faster than checking the URL every time, and given how fast these tests are,
|
||||
@ -77,7 +113,14 @@ class WebGpuCtsIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
|
||||
total_tests_run = 0
|
||||
|
||||
websocket_server = None
|
||||
server_stopper = None
|
||||
connection_stopper = None
|
||||
server_port = None
|
||||
websocket = None
|
||||
port_set_event = None
|
||||
connection_received_event = None
|
||||
event_loop = None
|
||||
_server_thread = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
@ -127,12 +170,25 @@ class WebGpuCtsIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
cls._page_loaded = False
|
||||
super(WebGpuCtsIntegrationTest, cls).StartBrowser()
|
||||
|
||||
@classmethod
|
||||
def SetUpWebsocketServer(cls) -> None:
|
||||
cls.port_set_event = threading.Event()
|
||||
cls.connection_received_event = threading.Event()
|
||||
cls._server_thread = ServerThread()
|
||||
# Mark as a daemon so that the harness does not hang when shutting down if
|
||||
# the thread fails to shut down properly.
|
||||
cls._server_thread.daemon = True
|
||||
cls._server_thread.start()
|
||||
got_port = WebGpuCtsIntegrationTest.port_set_event.wait(
|
||||
WEBSOCKET_PORT_TIMEOUT_SECONDS)
|
||||
if not got_port:
|
||||
raise RuntimeError('Server did not provide a port.')
|
||||
|
||||
@classmethod
|
||||
def SetUpProcess(cls) -> None:
|
||||
super(WebGpuCtsIntegrationTest, cls).SetUpProcess()
|
||||
|
||||
cls.websocket_server = websocket_server.WebsocketServer()
|
||||
cls.websocket_server.StartServer()
|
||||
cls.SetUpWebsocketServer()
|
||||
browser_args = [
|
||||
'--enable-unsafe-webgpu',
|
||||
'--disable-dawn-features=disallow_unsafe_apis',
|
||||
@ -159,10 +215,34 @@ class WebGpuCtsIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
os.path.join(cls._build_dir, 'gen', 'third_party', 'dawn'),
|
||||
])
|
||||
|
||||
@classmethod
|
||||
def TearDownWebsocketServer(cls) -> None:
|
||||
if cls.connection_stopper:
|
||||
cls.connection_stopper.cancel()
|
||||
try:
|
||||
cls.connection_stopper.exception()
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
if cls.server_stopper:
|
||||
cls.server_stopper.cancel()
|
||||
try:
|
||||
cls.server_stopper.exception()
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
cls.server_stopper = None
|
||||
cls.connection_stopper = None
|
||||
cls.server_port = None
|
||||
cls.websocket = None
|
||||
|
||||
cls._server_thread.join(5)
|
||||
if cls._server_thread.is_alive():
|
||||
logging.error(
|
||||
'WebSocket server did not shut down properly - this might be '
|
||||
'indicative of an issue in the test harness')
|
||||
|
||||
@classmethod
|
||||
def TearDownProcess(cls) -> None:
|
||||
cls.websocket_server.StopServer()
|
||||
cls.websocket_server = None
|
||||
cls.TearDownWebsocketServer()
|
||||
super(WebGpuCtsIntegrationTest, cls).TearDownProcess()
|
||||
|
||||
@classmethod
|
||||
@ -221,12 +301,13 @@ class WebGpuCtsIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
|
||||
try:
|
||||
first_load = self._NavigateIfNecessary(test_path)
|
||||
WebGpuCtsIntegrationTest.websocket_server.Send(
|
||||
json.dumps({
|
||||
'q': self._query,
|
||||
'w': self._run_in_worker
|
||||
}))
|
||||
result = self.HandleMessageLoop(first_load)
|
||||
asyncio.run_coroutine_threadsafe(
|
||||
WebGpuCtsIntegrationTest.websocket.send(
|
||||
json.dumps({
|
||||
'q': self._query,
|
||||
'w': self._run_in_worker
|
||||
})), WebGpuCtsIntegrationTest.event_loop)
|
||||
result = self.HandleMessageLoop(first_load=first_load)
|
||||
|
||||
log_str = ''.join(result.log_pieces)
|
||||
status = result.status
|
||||
@ -235,7 +316,7 @@ class WebGpuCtsIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
log_str)
|
||||
elif status == 'fail':
|
||||
self.fail(log_str)
|
||||
except websocket_server.ClientClosedConnectionError as e:
|
||||
except websockets.exceptions.ConnectionClosedOK as e:
|
||||
raise RuntimeError(
|
||||
'Detected closed websocket - likely caused by renderer crash') from e
|
||||
except WebGpuMessageTimeoutError as e:
|
||||
@ -320,7 +401,10 @@ class WebGpuCtsIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
while True:
|
||||
timeout = step_timeout * browser_timeout_multiplier
|
||||
try:
|
||||
response = WebGpuCtsIntegrationTest.websocket_server.Receive(timeout)
|
||||
future = asyncio.run_coroutine_threadsafe(
|
||||
asyncio.wait_for(WebGpuCtsIntegrationTest.websocket.recv(),
|
||||
timeout), WebGpuCtsIntegrationTest.event_loop)
|
||||
response = future.result()
|
||||
response = json.loads(response)
|
||||
response_type = response['type']
|
||||
|
||||
@ -363,7 +447,7 @@ class WebGpuCtsIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
else:
|
||||
raise WebGpuMessageProtocolError('Received unknown message type %s' %
|
||||
response_type)
|
||||
except websocket_server.WebsocketReceiveMessageTimeoutError as e:
|
||||
except asyncio.TimeoutError as e:
|
||||
self.HandleDurationTagOnFailure(message_state, global_timeout)
|
||||
raise WebGpuMessageTimeoutError(
|
||||
'Timed out waiting %.3f seconds for a message. Message state: %s' %
|
||||
@ -388,18 +472,32 @@ class WebGpuCtsIntegrationTest(gpu_integration_test.GpuIntegrationTest):
|
||||
and JAVASCRIPT_DURATION not in self.additionalTags):
|
||||
self.additionalTags[JAVASCRIPT_DURATION] = '%.9fs' % test_timeout
|
||||
|
||||
@classmethod
|
||||
def CleanUpExistingWebsocket(cls) -> None:
|
||||
if cls.connection_stopper:
|
||||
cls.connection_stopper.cancel()
|
||||
try:
|
||||
cls.connection_stopper.exception()
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
cls.connection_stopper = None
|
||||
cls.websocket = None
|
||||
cls.connection_received_event.clear()
|
||||
|
||||
def _NavigateIfNecessary(self, path: str) -> bool:
|
||||
if WebGpuCtsIntegrationTest._page_loaded:
|
||||
return False
|
||||
WebGpuCtsIntegrationTest.websocket_server.ClearCurrentConnection()
|
||||
WebGpuCtsIntegrationTest.CleanUpExistingWebsocket()
|
||||
url = self.UrlOfStaticFilePath(path)
|
||||
self.tab.Navigate(url)
|
||||
self.tab.action_runner.WaitForJavaScriptCondition(
|
||||
'window.setupWebsocket != undefined')
|
||||
self.tab.action_runner.ExecuteJavaScript(
|
||||
'window.setupWebsocket("%s")' %
|
||||
WebGpuCtsIntegrationTest.websocket_server.server_port)
|
||||
WebGpuCtsIntegrationTest.websocket_server.WaitForConnection()
|
||||
'window.setupWebsocket("%s")' % WebGpuCtsIntegrationTest.server_port)
|
||||
WebGpuCtsIntegrationTest.connection_received_event.wait(
|
||||
WEBSOCKET_SETUP_TIMEOUT_SECONDS)
|
||||
if not WebGpuCtsIntegrationTest.websocket:
|
||||
raise RuntimeError('Websocket connection was not established.')
|
||||
WebGpuCtsIntegrationTest._page_loaded = True
|
||||
return True
|
||||
|
||||
|
@ -128,24 +128,6 @@ def GPUExpectedDeviceId(test_config, _, tester_config):
|
||||
return retval
|
||||
|
||||
|
||||
def _GetGpusFromTestConfig(test_config):
|
||||
"""Generates all GPU dimension strings from a test config.
|
||||
|
||||
Args:
|
||||
test_config: A dict containing a configuration for a specific test on a
|
||||
specific builder.
|
||||
"""
|
||||
dimensions = test_config.get('swarming', {}).get('dimension_sets', [])
|
||||
assert dimensions
|
||||
for d in dimensions:
|
||||
# Split up multiple GPU/driver combinations if the swarming OR operator is
|
||||
# being used.
|
||||
if 'gpu' in d:
|
||||
gpus = d['gpu'].split('|')
|
||||
for gpu in gpus:
|
||||
yield gpu
|
||||
|
||||
|
||||
def GPUParallelJobs(test_config, _, tester_config):
|
||||
"""Substitutes the correct number of jobs for GPU tests.
|
||||
|
||||
@ -165,26 +147,19 @@ def GPUParallelJobs(test_config, _, tester_config):
|
||||
|
||||
# Return --jobs=1 for Windows Intel bots running the WebGPU CTS
|
||||
# These bots can't handle parallel tests. See crbug.com/1353938.
|
||||
# The load can also negatively impact WebGL tests, so reduce the number of
|
||||
# jobs there.
|
||||
# TODO(crbug.com/1349828): Try removing the Windows special casing once we
|
||||
# swap which machines we're using.
|
||||
is_webgpu_cts = test_name.startswith('webgpu_cts') or test_config.get(
|
||||
'telemetry_test_name') == 'webgpu_cts'
|
||||
is_webgl_cts = 'webgl_conformance' in test_name or test_config.get(
|
||||
'telemetry_test_name') == 'webgl_conformance'
|
||||
if os_type == 'win' and (is_webgl_cts or is_webgpu_cts):
|
||||
for gpu in _GetGpusFromTestConfig(test_config):
|
||||
if gpu.startswith('8086'):
|
||||
if is_webgpu_cts:
|
||||
return ['--jobs=1']
|
||||
return ['--jobs=2']
|
||||
# Similarly, the NVIDIA Macbooks are quite old and slow, so reduce the number
|
||||
# of jobs there as well.
|
||||
if os_type == 'mac' and is_webgl_cts:
|
||||
for gpu in _GetGpusFromTestConfig(test_config):
|
||||
if gpu.startswith('10de'):
|
||||
return ['--jobs=3']
|
||||
if os_type == 'win' and is_webgpu_cts:
|
||||
dimensions = test_config.get('swarming', {}).get('dimension_sets', [])
|
||||
assert dimensions
|
||||
for d in dimensions:
|
||||
# Split up multiple GPU/driver combinations if the swarming OR operator is
|
||||
# being used.
|
||||
if 'gpu' in d:
|
||||
gpus = d['gpu'].split('|')
|
||||
for gpu in gpus:
|
||||
if gpu.startswith('8086'):
|
||||
return ['--jobs=1']
|
||||
|
||||
if os_type in ['lacros', 'linux', 'mac', 'win']:
|
||||
return ['--jobs=4']
|
||||
|
@ -178,9 +178,9 @@ class GPUParallelJobs(unittest.TestCase):
|
||||
|
||||
def testWebGPUCTSWindowsIntelSerialJobs(self):
|
||||
intel_config = CreateConfigWithGpus(['8086:device1-driver'])
|
||||
amd_config = CreateConfigWithGpus(['1002:device1-driver'])
|
||||
nvidia_config = CreateConfigWithGpus(['10de:device1-driver'])
|
||||
|
||||
for gpu_config in [intel_config, amd_config]:
|
||||
for gpu_config in [intel_config, nvidia_config]:
|
||||
for name, telemetry_test_name in [('webgpu_cts', None),
|
||||
(None, 'webgpu_cts')]:
|
||||
is_intel = intel_config == gpu_config
|
||||
@ -197,48 +197,6 @@ class GPUParallelJobs(unittest.TestCase):
|
||||
else:
|
||||
self.assertEqual(retval, ['--jobs=4'])
|
||||
|
||||
def testWebGLWindowsIntelParallelJobs(self):
|
||||
intel_config = CreateConfigWithGpus(['8086:device1-driver'])
|
||||
amd_config = CreateConfigWithGpus(['1002:device1-driver'])
|
||||
|
||||
for gpu_config in [intel_config, amd_config]:
|
||||
for name, telemetry_test_name in [('webgl_conformance', None),
|
||||
(None, 'webgl_conformance')]:
|
||||
is_intel = intel_config == gpu_config
|
||||
c = gpu_config.copy()
|
||||
if name:
|
||||
c['name'] = name
|
||||
if telemetry_test_name:
|
||||
c['telemetry_test_name'] = telemetry_test_name
|
||||
for os_type in ['lacros', 'linux', 'mac', 'win']:
|
||||
retval = magic_substitutions.GPUParallelJobs(c, None,
|
||||
{'os_type': os_type})
|
||||
if is_intel and os_type == 'win':
|
||||
self.assertEqual(retval, ['--jobs=2'])
|
||||
else:
|
||||
self.assertEqual(retval, ['--jobs=4'])
|
||||
|
||||
def testWebGLMacNvidiaParallelJobs(self):
|
||||
amd_config = CreateConfigWithGpus(['1002:device1-driver'])
|
||||
nvidia_config = CreateConfigWithGpus(['10de:device1-driver'])
|
||||
|
||||
for gpu_config in [nvidia_config, amd_config]:
|
||||
for name, telemetry_test_name in [('webgl_conformance', None),
|
||||
(None, 'webgl_conformance')]:
|
||||
is_nvidia = gpu_config == nvidia_config
|
||||
c = gpu_config.copy()
|
||||
if name:
|
||||
c['name'] = name
|
||||
if telemetry_test_name:
|
||||
c['telemetry_test_name'] = telemetry_test_name
|
||||
for os_type in ['lacros', 'linux', 'mac', 'win']:
|
||||
retval = magic_substitutions.GPUParallelJobs(c, None,
|
||||
{'os_type': os_type})
|
||||
if is_nvidia and os_type == 'mac':
|
||||
self.assertEqual(retval, ['--jobs=3'])
|
||||
else:
|
||||
self.assertEqual(retval, ['--jobs=4'])
|
||||
|
||||
|
||||
def CreateConfigWithDeviceTypes(device_types):
|
||||
dimension_sets = []
|
||||
|
@ -1278,7 +1278,7 @@
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d11 --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--webgl-conformance-version=2.0.1",
|
||||
"--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json",
|
||||
"--jobs=2"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
@ -1317,7 +1317,7 @@
|
||||
"--stable-jobs",
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d11 --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json",
|
||||
"--jobs=2"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
@ -1356,7 +1356,7 @@
|
||||
"--stable-jobs",
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d9 --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json",
|
||||
"--jobs=2"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
@ -1394,7 +1394,7 @@
|
||||
"-v",
|
||||
"--stable-jobs",
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=vulkan --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--jobs=2"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
|
@ -16609,7 +16609,7 @@
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--webgl-conformance-version=2.0.1",
|
||||
"--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json",
|
||||
"--jobs=3"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
@ -16651,7 +16651,7 @@
|
||||
"--stable-jobs",
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=gl --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json",
|
||||
"--jobs=3"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
@ -16693,7 +16693,7 @@
|
||||
"--stable-jobs",
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=swiftshader --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--test-filter=conformance/rendering/gl-drawelements.html",
|
||||
"--jobs=3"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
@ -19538,7 +19538,7 @@
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d11 --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--webgl-conformance-version=2.0.1",
|
||||
"--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json",
|
||||
"--jobs=2"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
@ -19577,7 +19577,7 @@
|
||||
"--stable-jobs",
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d11 --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json",
|
||||
"--jobs=2"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
@ -19616,7 +19616,7 @@
|
||||
"--stable-jobs",
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d9 --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json",
|
||||
"--jobs=2"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
@ -19654,7 +19654,7 @@
|
||||
"-v",
|
||||
"--stable-jobs",
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=vulkan --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--jobs=2"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
|
@ -665,7 +665,7 @@
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d11 --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--webgl-conformance-version=2.0.1",
|
||||
"--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl2_conformance_tests_output.json",
|
||||
"--jobs=2"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
@ -744,7 +744,7 @@
|
||||
"--stable-jobs",
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d11 --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json",
|
||||
"--jobs=2"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
@ -823,7 +823,7 @@
|
||||
"--stable-jobs",
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-gl=angle --use-angle=d3d9 --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json",
|
||||
"--jobs=2"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
@ -900,7 +900,7 @@
|
||||
"-v",
|
||||
"--stable-jobs",
|
||||
"--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-angle=vulkan --use-cmd-decoder=passthrough --force_high_performance_gpu",
|
||||
"--jobs=2"
|
||||
"--jobs=4"
|
||||
],
|
||||
"isolate_name": "telemetry_gpu_integration_test",
|
||||
"merge": {
|
||||
|
Reference in New Issue
Block a user