mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
[Tools, Test] (tools/cts, MG_Test): make the CTS runner's chunk timeout idle-based so a healthy 20-minute invocation is no longer killed and its in-flight case mis-recorded as a crash, and link MSVC test executables with /WHOLEARCHIVE so the dllimport gl* references in GetProcAddress.cpp resolve
This commit is contained in:
@@ -64,6 +64,15 @@ set(LINK_LIBRARIES
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(SanityTest DISCOVERY_TIMEOUT 30 PROPERTIES LABELS unit)
|
||||
|
||||
if (MSVC)
|
||||
# The GL headers declare gl* as dllimport on Windows, so any test that pulls
|
||||
# GetProcAddress.cpp out of the static library references __imp_gl*, which only
|
||||
# resolves when the in-library entry-point definitions are part of the link.
|
||||
# Applies to every test executable below, the way the DirectVulkan and
|
||||
# integration test targets already do it for themselves.
|
||||
add_link_options(/WHOLEARCHIVE:MobileGL_s)
|
||||
endif()
|
||||
|
||||
add_subdirectory(BackendLoader)
|
||||
add_subdirectory(Buffer)
|
||||
# The heap-address-is-not-an-identity invariant the backends' per-object memos
|
||||
|
||||
@@ -23,6 +23,17 @@ target_link_libraries(
|
||||
${LINK_LIBRARIES}
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
# This test compiles library sources of its own; pulling the whole static
|
||||
# library in as well (the directory-wide MG_Test link option) would define
|
||||
# them twice, so that option is dropped for this one target.
|
||||
get_target_property(_program_util_link_options ProgramUtilTest LINK_OPTIONS)
|
||||
if (_program_util_link_options)
|
||||
list(REMOVE_ITEM _program_util_link_options /WHOLEARCHIVE:MobileGL_s)
|
||||
set_target_properties(ProgramUtilTest PROPERTIES LINK_OPTIONS "${_program_util_link_options}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_executable(
|
||||
ProgramTest
|
||||
ProgramTest.cpp
|
||||
|
||||
@@ -51,6 +51,48 @@ def wait_for_device(serial, attempts=20, delay=15):
|
||||
return False
|
||||
|
||||
|
||||
def device_file_size(serial, path):
|
||||
r = adb(serial, "shell", f"stat -c %s {path} 2>/dev/null || echo 0", timeout=30)
|
||||
m = re.search(r"(\d+)", r.stdout or "")
|
||||
return int(m.group(1)) if m else 0
|
||||
|
||||
|
||||
def run_chunk(serial, cmd, dev_qpa, dev_list, idle_timeout, poll_interval=15):
|
||||
"""Run one glcts invocation; give up only when the log stops growing.
|
||||
|
||||
A chunk is thousands of cases and legitimately runs for an hour, so a fixed
|
||||
wall-clock cap would kill healthy invocations and record whichever case was
|
||||
in flight as a crash. A GPU hang, by contrast, stops the .qpa from growing.
|
||||
The timeout is therefore measured from the last observed growth of the
|
||||
device-side log. On expiry the device-side glcts is killed (matched by the
|
||||
caselist path this runner alone uses, so other processes are left alone) and
|
||||
returncode 124 is reported, the same signal a hard timeout used to give.
|
||||
"""
|
||||
proc = subprocess.Popen(["adb", "-s", serial, "shell", cmd],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
last_size = -1
|
||||
last_growth = time.time()
|
||||
while True:
|
||||
try:
|
||||
out, err = proc.communicate(timeout=poll_interval)
|
||||
return subprocess.CompletedProcess(proc.args, proc.returncode, out, err)
|
||||
except subprocess.TimeoutExpired:
|
||||
pass
|
||||
size = device_file_size(serial, dev_qpa)
|
||||
now = time.time()
|
||||
if size != last_size:
|
||||
last_size = size
|
||||
last_growth = now
|
||||
elif now - last_growth > idle_timeout:
|
||||
adb(serial, "shell", f"pkill -f {dev_list}", timeout=30)
|
||||
proc.kill()
|
||||
try:
|
||||
proc.communicate(timeout=30)
|
||||
except subprocess.TimeoutExpired:
|
||||
pass
|
||||
return subprocess.CompletedProcess(proc.args, 124, "", "idle timeout")
|
||||
|
||||
|
||||
def mem_available_kb(serial):
|
||||
r = adb(serial, "shell", "grep MemAvailable /proc/meminfo", timeout=30)
|
||||
m = re.search(r"(\d+)", r.stdout or "")
|
||||
@@ -152,7 +194,8 @@ def main():
|
||||
ap.add_argument("--min-mem-kb", type=int, default=400000,
|
||||
help="pause when the device drops below this much available memory")
|
||||
ap.add_argument("--chunk-timeout", type=int, default=900,
|
||||
help="seconds before giving up on one glcts invocation (a GPU hang never returns)")
|
||||
help="seconds without any growth of the device-side .qpa before the glcts "
|
||||
"invocation is declared hung and killed (a GPU hang never returns)")
|
||||
ap.add_argument("--skip-file", default=None,
|
||||
help="file of case names to exclude, e.g. cases known to hang the device")
|
||||
ap.add_argument("--env", action="append", default=[], metavar="K=V",
|
||||
@@ -239,10 +282,10 @@ def main():
|
||||
f"--deqp-log-images=disable --deqp-log-shader-sources=disable "
|
||||
f"--deqp-log-filename={dev_qpa} > /dev/null 2>&1; rc=$?; sync; echo RC=$rc"
|
||||
)
|
||||
run = adb(args.serial, "shell", cmd, timeout=args.chunk_timeout)
|
||||
run = run_chunk(args.serial, cmd, dev_qpa, dev_list, args.chunk_timeout)
|
||||
if run.returncode == 124:
|
||||
print(f"[run_cts] chunk {chunk:04d} timed out after {args.chunk_timeout}s "
|
||||
f"(likely a GPU hang)", file=sys.stderr)
|
||||
print(f"[run_cts] chunk {chunk:04d}: no log growth for {args.chunk_timeout}s "
|
||||
f"(likely a GPU hang); killed glcts", file=sys.stderr)
|
||||
|
||||
# Some cases hang the GPU hard enough to reboot the device. The log on
|
||||
# /data/local/tmp survives that, so wait for the device to come back and
|
||||
|
||||
Reference in New Issue
Block a user