Skip to content

Commit 2dbba83

Browse files
committed
buildbot-dev: fix calculating memory on macOS
1 parent 31925a9 commit 2dbba83

File tree

2 files changed

+91
-11
lines changed

2 files changed

+91
-11
lines changed

packages/buildbot-dev.nix

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
python,
1717
writeShellScriptBin,
1818
stdenv,
19+
darwin,
1920
}:
2021
let
2122
pythonEnv = python.withPackages (
@@ -47,6 +48,7 @@ writeShellScriptBin "buildbot-dev" ''
4748
buildbot-effects
4849
]
4950
++ lib.optional stdenv.isLinux buildbot-effects
51+
++ lib.optional stdenv.isDarwin darwin.system_cmds
5052
)
5153
}
5254
mkdir -p "$git_root/.buildbot-dev"

packages/master.cfg.py

Lines changed: 89 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
)
66
import getpass
77
import os
8+
import platform
9+
import subprocess
810
import multiprocessing
911
from buildbot.plugins import util
1012
from buildbot.process.factory import BuildFactory
@@ -17,20 +19,76 @@ class EvalWorkerConfig:
1719
max_memory_mib: int
1820

1921

20-
def calculate_eval_workers() -> EvalWorkerConfig:
21-
"""Calculate optimal eval workers based on system resources."""
22-
# Get system resources
23-
cpu_count = multiprocessing.cpu_count()
22+
@dataclass
23+
class MemoryInfo:
24+
total_memory_mib: int
25+
available_memory_mib: int
26+
zfs_arc_used: int = 0
27+
28+
29+
def get_memory_info_macos() -> MemoryInfo:
30+
"""Get memory information on macOS using vm_stat and sysctl."""
31+
try:
32+
# Use vm_stat to get memory information on macOS
33+
result = subprocess.run(["vm_stat"], capture_output=True, text=True, check=True)
34+
35+
# Parse vm_stat output
36+
lines = result.stdout.strip().split("\n")
37+
page_size = None
38+
free_pages = 0
39+
inactive_pages = 0
40+
41+
for line in lines:
42+
if "page size of" in line:
43+
# Extract page size from "Mach Virtual Memory Statistics: (page size of 4096 bytes)"
44+
page_size = int(line.split("page size of ")[1].split(" bytes")[0])
45+
elif line.startswith("Pages free:"):
46+
free_pages = int(line.split(":")[1].strip().rstrip("."))
47+
elif line.startswith("Pages inactive:"):
48+
inactive_pages = int(line.split(":")[1].strip().rstrip("."))
49+
50+
if page_size is None:
51+
raise ValueError("Could not determine page size from vm_stat")
52+
53+
# Available memory is free + inactive pages
54+
available_memory_bytes = (free_pages + inactive_pages) * page_size
55+
available_memory_mib = available_memory_bytes // (1024 * 1024)
56+
57+
# Get total memory using sysctl
58+
result = subprocess.run(
59+
["sysctl", "-n", "hw.memsize"], capture_output=True, text=True, check=True
60+
)
61+
total_memory_bytes = int(result.stdout.strip())
62+
total_memory_mib = total_memory_bytes // (1024 * 1024)
63+
64+
return MemoryInfo(total_memory_mib, available_memory_mib)
65+
66+
except (subprocess.CalledProcessError, ValueError, IndexError) as e:
67+
print(f"Warning: Could not get accurate memory info on macOS: {e}")
68+
# Fallback to conservative estimates
69+
return MemoryInfo(8192, 4096) # 8GB total, 4GB available
70+
71+
72+
def get_memory_info_linux() -> MemoryInfo:
73+
"""Get memory information on Linux using os.sysconf and ZFS ARC detection."""
74+
try:
75+
# Try Linux-specific methods first
76+
total_pages = os.sysconf("SC_PHYS_PAGES")
77+
page_size = os.sysconf("SC_PAGE_SIZE")
78+
available_pages = os.sysconf("SC_AVPHYS_PAGES")
2479

25-
# Get memory using os.sysconf()
26-
total_pages = os.sysconf("SC_PHYS_PAGES")
27-
page_size = os.sysconf("SC_PAGE_SIZE")
28-
available_pages = os.sysconf("SC_AVPHYS_PAGES")
80+
total_memory_mib = (total_pages * page_size) // (1024 * 1024)
81+
available_memory_mib = (available_pages * page_size) // (1024 * 1024)
2982

30-
total_memory_mib = (total_pages * page_size) // (1024 * 1024)
31-
available_memory_mib = (available_pages * page_size) // (1024 * 1024)
83+
except (ValueError, OSError):
84+
# Fallback for other systems
85+
print(
86+
"Warning: Could not get memory info via sysconf, using conservative estimates"
87+
)
88+
total_memory_mib = 8192 # 8GB default
89+
available_memory_mib = 4096 # 4GB available
3290

33-
# Check for ZFS ARC usage
91+
# Check for ZFS ARC usage on Linux
3492
zfs_arc_used = 0
3593
try:
3694
with open("/proc/spl/kstat/zfs/arcstats", "r") as f:
@@ -45,6 +103,26 @@ def calculate_eval_workers() -> EvalWorkerConfig:
45103
# Not a ZFS system or can't read ARC stats
46104
pass
47105

106+
return MemoryInfo(total_memory_mib, available_memory_mib, zfs_arc_used)
107+
108+
109+
def calculate_eval_workers() -> EvalWorkerConfig:
110+
"""Calculate optimal eval workers based on system resources."""
111+
# Get system resources
112+
cpu_count = multiprocessing.cpu_count()
113+
114+
# Get memory using platform-specific methods
115+
system = platform.system()
116+
117+
if system == "Darwin": # macOS
118+
memory_info = get_memory_info_macos()
119+
else: # Linux and other Unix-like systems
120+
memory_info = get_memory_info_linux()
121+
122+
total_memory_mib = memory_info.total_memory_mib
123+
available_memory_mib = memory_info.available_memory_mib
124+
zfs_arc_used = memory_info.zfs_arc_used
125+
48126
# If ZFS is present, account for ARC cache which can be reclaimed
49127
effective_available_memory = available_memory_mib
50128
if zfs_arc_used > 0:

0 commit comments

Comments
 (0)