55)
66import getpass
77import os
8+ import platform
9+ import subprocess
810import multiprocessing
911from buildbot .plugins import util
1012from 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