208 lines
7.7 KiB
Python
208 lines
7.7 KiB
Python
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
# SPDX-FileCopyrightText: 2011-2024 Blender Authors
|
|
# <pep8 compliant>
|
|
|
|
import os
|
|
import pathlib
|
|
import platform
|
|
import psutil
|
|
import shutil
|
|
|
|
from typing import List, Tuple
|
|
|
|
import worker.utils
|
|
|
|
|
|
def get_os_release() -> str:
|
|
if platform.system() == "Darwin":
|
|
return "macOS " + platform.mac_ver()[0]
|
|
else:
|
|
return platform.version()
|
|
|
|
|
|
def get_cpu_info() -> str:
|
|
if platform.system() == "Darwin":
|
|
return worker.utils.check_output(
|
|
["/usr/sbin/sysctl", "-n", "machdep.cpu.brand_string"]
|
|
)
|
|
elif platform.system() == "Linux":
|
|
cpuinfo = pathlib.Path("/proc/cpuinfo").read_text()
|
|
for line in cpuinfo.splitlines():
|
|
if line.find("model name") != -1:
|
|
return line.split(":")[1].strip()
|
|
|
|
return platform.processor()
|
|
|
|
|
|
def disk_free_in_gb(builder: worker.utils.Builder) -> float:
|
|
_, _, disk_free = shutil.disk_usage(builder.track_path)
|
|
return disk_free / (1024.0**3)
|
|
|
|
|
|
def get_thread_count(thread_memory_in_GB: float) -> int:
|
|
num_threads = psutil.cpu_count()
|
|
memory_in_GB = psutil.virtual_memory().total / (1024**3)
|
|
|
|
return min(int(memory_in_GB / thread_memory_in_GB), num_threads)
|
|
|
|
|
|
def clean(builder: worker.utils.Builder) -> None:
|
|
# Remove build folders to make space.
|
|
delete_paths: List[pathlib.Path] = []
|
|
optional_delete_paths: List[pathlib.Path] = []
|
|
|
|
branches_config = builder.get_branches_config()
|
|
tracks = branches_config.track_major_minor_versions.keys()
|
|
|
|
# TODO: don't hardcode these folder and track names
|
|
for track in tracks:
|
|
track_path = builder.tracks_root_path / ("blender-manual-" + track)
|
|
optional_delete_paths += [track_path / "build"]
|
|
|
|
for track in tracks:
|
|
track_path = builder.tracks_root_path / ("blender-" + track)
|
|
delete_paths += [track_path / "build_download"]
|
|
delete_paths += [track_path / "build_linux"]
|
|
delete_paths += [track_path / "build_darwin"]
|
|
delete_paths += [track_path / "build_package"]
|
|
delete_paths += [track_path / "build_source"]
|
|
delete_paths += [track_path / "build_debug"]
|
|
delete_paths += [track_path / "build_arm64_debug"]
|
|
delete_paths += [track_path / "build_x86_64_debug"]
|
|
delete_paths += [track_path / "build_sanitizer"]
|
|
delete_paths += [track_path / "build_arm64_sanitizer"]
|
|
delete_paths += [track_path / "build_x86_64_sanitizer"]
|
|
delete_paths += [track_path / "install_release"]
|
|
delete_paths += [track_path / "install_asserts"]
|
|
delete_paths += [track_path / "install_sanitizer"]
|
|
delete_paths += [track_path / "install_debug"]
|
|
delete_paths += [track_path / "benchmark"]
|
|
optional_delete_paths += [track_path / "build_release"]
|
|
optional_delete_paths += [track_path / "build_arm64_release"]
|
|
optional_delete_paths += [track_path / "build_x86_64_release"]
|
|
optional_delete_paths += [track_path / "build_asserts"]
|
|
optional_delete_paths += [track_path / "build_arm64_asserts"]
|
|
optional_delete_paths += [track_path / "build_x86_64_asserts"]
|
|
|
|
for delete_path in delete_paths:
|
|
worker.utils.remove_dir(delete_path)
|
|
|
|
# Cached build folders only if we are low on disk space
|
|
if builder.platform == "darwin":
|
|
# On macOS APFS this is not reliable, it makes space on demand.
|
|
# This should be ok still.
|
|
required_space_gb = 12.0
|
|
else:
|
|
required_space_gb = 25.0
|
|
|
|
free_space_gb = disk_free_in_gb(builder)
|
|
if free_space_gb < required_space_gb:
|
|
worker.utils.warning(
|
|
f"Trying to delete cached builds for disk space (free {free_space_gb:.2f} GB)"
|
|
)
|
|
sorted_paths: List[Tuple[float, pathlib.Path]] = []
|
|
for delete_path in optional_delete_paths:
|
|
try:
|
|
sorted_paths.append((os.path.getmtime(delete_path), delete_path))
|
|
except (FileNotFoundError, PermissionError) as e:
|
|
worker.utils.warning(f"Unable to access {delete_path}: {e}")
|
|
|
|
for _, delete_path in sorted(sorted_paths):
|
|
worker.utils.remove_dir(delete_path)
|
|
if disk_free_in_gb(builder) >= required_space_gb:
|
|
break
|
|
|
|
# Might be left over from git command hanging
|
|
stack_dump_file_path = builder.code_path / "sh.exe.stackdump"
|
|
worker.utils.remove_file(stack_dump_file_path)
|
|
|
|
|
|
def configure_machine(builder: worker.utils.Builder) -> None:
|
|
worker_config = builder.get_worker_config()
|
|
|
|
clean(builder)
|
|
|
|
# Print system information.
|
|
processor = get_cpu_info()
|
|
|
|
worker.utils.info("System information")
|
|
print(f"System: {platform.system()}")
|
|
print(f"Release: {get_os_release()}")
|
|
print(f"Version: {platform.version()}")
|
|
print(f"Processor: {processor}")
|
|
print(
|
|
f"Cores: {psutil.cpu_count()} logical, {psutil.cpu_count(logical=False)} physical"
|
|
)
|
|
print(f"Total Memory: {psutil.virtual_memory().total / (1024**3):.2f} GB")
|
|
print(f"Available Memory: {psutil.virtual_memory().available / (1024**3):.2f} GB")
|
|
|
|
disk_total, disk_used, disk_free = shutil.disk_usage(builder.track_path)
|
|
print(
|
|
f"Disk: total {disk_total / (1024**3):.2f} GB, "
|
|
f"used {disk_used / (1024**3):.2f} GB, "
|
|
f"free {disk_free / (1024**3):.2f} GB"
|
|
)
|
|
|
|
# Check dependencies and provision
|
|
worker.utils.info("Checking installable software cache")
|
|
avilable_software_artifacts = worker_config.software_cache_path.glob("*/*")
|
|
for artifact in avilable_software_artifacts:
|
|
print(artifact)
|
|
|
|
# Check packages
|
|
if builder.platform == "linux":
|
|
etc_rocky = pathlib.Path("/etc/rocky-release")
|
|
|
|
if etc_rocky.exists():
|
|
worker.utils.call(["yum", "updateinfo"])
|
|
worker.utils.call(["yum", "list", "updates"])
|
|
else:
|
|
worker.utils.call(["apt", "list", "--upgradable"])
|
|
|
|
elif builder.platform == "windows":
|
|
choco_version_str = worker.utils.check_output(["choco", "--version"])
|
|
choco_version = [int(x) for x in choco_version_str.split(".")]
|
|
if choco_version[0] >= 2:
|
|
# In the newer Chocolatey versions `choco list` behavior got changed
|
|
# to only list installed package, and the --localonly flag has been
|
|
# removed.
|
|
worker.utils.call(["choco", "list"])
|
|
else:
|
|
worker.utils.call(["choco", "list", "--lo"])
|
|
worker.utils.call(["choco", "outdated"])
|
|
|
|
# Not an actual command, disabled for now.
|
|
# worker.utils.call(["scoop", "list"])
|
|
# worker.utils.call(["scoop", "status"])
|
|
|
|
elif builder.platform == "darwin":
|
|
worker.utils.call(["brew", "update"])
|
|
worker.utils.call(["brew", "outdated", "--cask"])
|
|
worker.utils.call(["xcrun", "--show-sdk-path"])
|
|
|
|
# XXX Windows builder debug code
|
|
if builder.platform == "windows":
|
|
# Ensure the idiff.exe process is stopped.
|
|
# It might be hanging there since the previously failed build and it will
|
|
# prevent removal of the install directory for the new build (due to held
|
|
# open DLLs).
|
|
worker.utils.info("Stopping idiff.exe if running")
|
|
|
|
dump_folder = pathlib.Path("C:\\tmp\\dump\\")
|
|
os.makedirs(dump_folder, exist_ok=True)
|
|
|
|
worker.utils.call(["procdump", "idiff.exe", dump_folder], exit_on_error=False)
|
|
|
|
for proc in psutil.process_iter():
|
|
if proc.name() == "idiff.exe":
|
|
proc.kill()
|
|
|
|
for proc in psutil.process_iter():
|
|
if proc.name().lower() in [
|
|
"blender",
|
|
"blender.exe",
|
|
"blender_test",
|
|
"blender_test.exe",
|
|
]:
|
|
worker.utils.warning("Killing stray Blender process")
|
|
proc.kill()
|