WIP: Tests: Add option to run GPU tests on buildbot #2

Closed
Brecht Van Lommel wants to merge 3 commits from gpu-tests into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
5 changed files with 76 additions and 5 deletions
Showing only changes of commit 2ea2d98140 - Show all commits

View File

@ -5,14 +5,18 @@
_worker_names = { _worker_names = {
"code-lint": ["localhost"], "code-lint": ["localhost"],
"linux-x86_64-code": ["localhost"], "linux-x86_64-code": ["localhost"],
"linux-x86_64-code-gpu": ["localhost"],
"linux-x86_64-doc-api": ["localhost"], "linux-x86_64-doc-api": ["localhost"],
"linux-x86_64-doc-studio-pipeline": ["localhost"], "linux-x86_64-doc-studio-pipeline": ["localhost"],
"linux-x86_64-general": ["localhost"], "linux-x86_64-general": ["localhost"],
"linux-x86_64-store-snap": ["localhost"], "linux-x86_64-store-snap": ["localhost"],
"linux-x86_64-store-steam": ["localhost"], "linux-x86_64-store-steam": ["localhost"],
"darwin-arm64-code": ["localhost"], "darwin-arm64-code": ["localhost"],
"darwin-arm64-code-gpu": ["localhost"],
"darwin-x86_64-code": ["localhost"], "darwin-x86_64-code": ["localhost"],
"darwin-x86_64-code-gpu": ["localhost"],
"windows-amd64-code": ["localhost"], "windows-amd64-code": ["localhost"],
"windows-amd64-code-gpu": [],
"windows-amd64-store-windows": ["localhost"], "windows-amd64-store-windows": ["localhost"],
} }

View File

@ -2,7 +2,9 @@
# SPDX-FileCopyrightText: 2011-2024 Blender Authors # SPDX-FileCopyrightText: 2011-2024 Blender Authors
# <pep8 compliant> # <pep8 compliant>
from functools import partial
import pathlib import pathlib
import random
import buildbot.plugins import buildbot.plugins
@ -133,6 +135,20 @@ scheduler_properties_common = [
strict=True, strict=True,
default=False, default=False,
), ),
buildbot.plugins.util.BooleanParameter(
name="needs_gpu_binaries",
label="GPU binaries -> build Cycles GPU kernels",
required=True,
strict=True,
default=False,
),
buildbot.plugins.util.BooleanParameter(
name="needs_gpu_tests",
label="GPU tests -> run EEVEE, Viewport and Cycles GPU tests",
required=True,
strict=True,
default=False,
),
] ]
# code-daily # code-daily
@ -209,6 +225,10 @@ def create_code_worker_command_args(props, devops_env_id, track_id, pipeline_typ
patch_id = pipeline.common.fetch_property(props, key="patch_id", default="") patch_id = pipeline.common.fetch_property(props, key="patch_id", default="")
override_branch_id = pipeline.common.fetch_property(props, key="override_branch_id", default="") override_branch_id = pipeline.common.fetch_property(props, key="override_branch_id", default="")
python_module = pipeline.common.fetch_property(props, key="python_module", default=False) python_module = pipeline.common.fetch_property(props, key="python_module", default=False)
needs_gpu_tests = pipeline.common.fetch_property(props, key="needs_gpu_tests", default=False)
needs_gpu_binaries = pipeline.common.fetch_property(
props, key="needs_gpu_binaries", default=False
)
build_configuration = pipeline.common.fetch_property( build_configuration = pipeline.common.fetch_property(
props, key="build_configuration", default="release" props, key="build_configuration", default="release"
) )
@ -246,8 +266,11 @@ def create_code_worker_command_args(props, devops_env_id, track_id, pipeline_typ
args += ["--python-module"] args += ["--python-module"]
if needs_full_clean: if needs_full_clean:
args += ["--needs-full-clean"] args += ["--needs-full-clean"]
if step_name in ["compile-install"] and needs_package_delivery: if step_name in ["compile-gpu", "compile-install"]:
args += ["--needs-gpu-binaries"] if needs_package_delivery or needs_gpu_binaries:
args += ["--needs-gpu-binaries"]
if needs_gpu_tests:
args += ["--needs-gpu-tests"]
args += [step_name] args += [step_name]
@ -380,6 +403,21 @@ def create_deliver_test_results_step(worker_config, track_id, pipeline_type):
) )
def next_worker_code(worker_names_gpu, builder, workers, request):
# Use a GPU worker if needed and supported for this platform.
if not workers:
return None
if not request.properties.getProperty("needs_gpu_tests", False) or not worker_names_gpu:
return random.choice(workers)
for worker in workers:
if worker.worker.workername in worker_names_gpu:
return worker
return None
def populate(devops_env_id): def populate(devops_env_id):
builders = [] builders = []
schedulers = [] schedulers = []
@ -478,8 +516,10 @@ def populate(devops_env_id):
print(f"Creating [{track_id}] [{pipeline_type}] [{platform_architecture}] builders") print(f"Creating [{track_id}] [{pipeline_type}] [{platform_architecture}] builders")
worker_group_id = f"{platform_architecture}-code" worker_group_id = f"{platform_architecture}-code"
worker_group_id_gpu = f"{platform_architecture}-code-gpu"
pipeline_worker_names = platform_worker_names[worker_group_id] pipeline_worker_names = platform_worker_names[worker_group_id]
pipeline_worker_names_gpu = platform_worker_names[worker_group_id_gpu]
if pipeline_worker_names: if pipeline_worker_names:
# Only create the builders if the worker exists # Only create the builders if the worker exists
pipeline_builder_name = ( pipeline_builder_name = (
@ -502,6 +542,7 @@ def populate(devops_env_id):
buildbot.plugins.util.BuilderConfig( buildbot.plugins.util.BuilderConfig(
name=pipeline_builder_name, name=pipeline_builder_name,
workernames=suitable_pipeline_worker_names, workernames=suitable_pipeline_worker_names,
nextWorker=partial(next_worker_code, pipeline_worker_names_gpu),
tags=pipeline_builder_tags, tags=pipeline_builder_tags,
factory=pipeline_build_factory, factory=pipeline_build_factory,
) )
@ -554,6 +595,8 @@ def populate(devops_env_id):
"needs_package_delivery": buildbot.plugins.util.Property( "needs_package_delivery": buildbot.plugins.util.Property(
"needs_package_delivery" "needs_package_delivery"
), ),
"needs_gpu_binaries": buildbot.plugins.util.Property("needs_gpu_binaries"),
"needs_gpu_tests": buildbot.plugins.util.Property("needs_gpu_tests"),
"needs_skip_tests": buildbot.plugins.util.Property("needs_skip_tests"), "needs_skip_tests": buildbot.plugins.util.Property("needs_skip_tests"),
"platform_architectures": buildbot.plugins.util.Property( "platform_architectures": buildbot.plugins.util.Property(
"platform_architectures" "platform_architectures"
@ -637,6 +680,7 @@ def populate(devops_env_id):
"python_module": False, "python_module": False,
"needs_skip_tests": False, "needs_skip_tests": False,
"needs_package_delivery": False, "needs_package_delivery": False,
"needs_gpu_binaries": False,
"build_configuration": "release", "build_configuration": "release",
"platform_architectures": code_tracked_platform_architectures[track_id], "platform_architectures": code_tracked_platform_architectures[track_id],
} }
@ -663,6 +707,7 @@ def populate(devops_env_id):
"python_module": False, "python_module": False,
"needs_skip_tests": False, "needs_skip_tests": False,
"needs_package_delivery": True, "needs_package_delivery": True,
"needs_gpu_binaries": True,
"build_configuration": "release", "build_configuration": "release",
"platform_architectures": code_tracked_platform_architectures[track_id], "platform_architectures": code_tracked_platform_architectures[track_id],
} }

View File

@ -20,6 +20,7 @@ class CodeBuilder(worker.utils.Builder):
super().__init__(args, "blender", "blender") super().__init__(args, "blender", "blender")
self.needs_full_clean = args.needs_full_clean self.needs_full_clean = args.needs_full_clean
self.needs_gpu_binaries = args.needs_gpu_binaries self.needs_gpu_binaries = args.needs_gpu_binaries
self.needs_gpu_tests = args.needs_gpu_tests
self.needs_ninja = True self.needs_ninja = True
self.python_module = args.python_module self.python_module = args.python_module
self.build_configuration = args.build_configuration self.build_configuration = args.build_configuration
@ -161,6 +162,7 @@ def create_argument_parser(steps: worker.utils.BuilderSteps) -> argparse.Argumen
parser = worker.utils.create_argument_parser(steps=steps) parser = worker.utils.create_argument_parser(steps=steps)
parser.add_argument("--needs-full-clean", action="store_true", required=False) parser.add_argument("--needs-full-clean", action="store_true", required=False)
parser.add_argument("--needs-gpu-binaries", action="store_true", required=False) parser.add_argument("--needs-gpu-binaries", action="store_true", required=False)
parser.add_argument("--needs-gpu-tests", action="store_true", required=False)
parser.add_argument("--python-module", action="store_true", required=False) parser.add_argument("--python-module", action="store_true", required=False)
parser.add_argument( parser.add_argument(
"--build-configuration", "--build-configuration",

View File

@ -224,9 +224,21 @@ def get_cmake_options(builder: worker.blender.CodeBuilder) -> worker.utils.CmdSe
else: else:
options += [f"-DWITH_CYCLES_ONEAPI_BINARIES=OFF"] options += [f"-DWITH_CYCLES_ONEAPI_BINARIES=OFF"]
options += [f"-DHIP_ROOT_DIR:PATH=/opt/rocm/hip"] options += [f"-DHIP_ROOT_DIR:PATH=/opt/rocm/hip"]
# GPU render tests support Linux + NVIDIA currently
if builder.needs_gpu_tests:
# TODO fails because missing vulkan headers?
# options += [f"-DWITH_GPU_DRAW_TESTS=ON"]
options += [f"-DWITH_GPU_RENDER_TESTS=ON"]
options += [f"-DWITH_GPU_RENDER_TESTS_SILENT=OFF"]
if builder.needs_gpu_binaries:
options += [f"-DCYCLES_TEST_DEVICES=CPU;OPTIX"]
elif builder.platform == "darwin": elif builder.platform == "darwin":
# Metal on macOS # Metal on macOS
if builder.architecture == "arm64": if builder.architecture == "arm64":
if builder.needs_gpu_tests:
options += [f"-DWITH_GPU_RENDER_TESTS=ON"]
options += [f"-DWITH_GPU_RENDER_TESTS_SILENT=OFF"]
options += [f"-DCYCLES_TEST_DEVICES=CPU;METAL"] options += [f"-DCYCLES_TEST_DEVICES=CPU;METAL"]
if "optix" in buildbotConfig: if "optix" in buildbotConfig:

View File

@ -18,8 +18,10 @@ def get_ctest_arguments(builder: worker.blender.CodeBuilder) -> List[str]:
# Run tests in single threads for tracks which has older OpenEXR/OpenImageIO, # Run tests in single threads for tracks which has older OpenEXR/OpenImageIO,
# This prevents idiff.exe dead-lock on exit. # This prevents idiff.exe dead-lock on exit.
if builder.platform != "windows" or builder.track_id != "v330": if not (builder.platform == "windows" and builder.track_id == "v330"):
args += ["--parallel", "4"] # GPU tests are currently slow and can cause timeouts.
if not builder.needs_gpu_tests:
args += ["--parallel", "4"]
args += ["-C", worker.blender.compile.get_cmake_build_type(builder)] args += ["-C", worker.blender.compile.get_cmake_build_type(builder)]
return args return args
@ -53,8 +55,14 @@ def test(builder: worker.blender.CodeBuilder) -> None:
os.chdir(builder.build_dir) os.chdir(builder.build_dir)
success = False success = False
env = os.environ.copy()
# Needed to successfully initialize EGL on Rocky Linux machine.
if builder.needs_gpu_tests and builder.platform == "linux":
env["DISPLAY"] = ":0"
try: try:
builder.call(["ctest"] + get_ctest_arguments(builder)) builder.call(["ctest"] + get_ctest_arguments(builder), env=env)
success = True success = True
finally: finally:
package_for_upload(builder, success) package_for_upload(builder, success)