Skip to content

Commit 4021903

Browse files
authored
Merge pull request #177 from reacher-z/fix/59-sysconf-on-windows
Fix/59 sysconf on windows
2 parents 82bc9c3 + 30e4b2e commit 4021903

8 files changed

Lines changed: 129 additions & 6 deletions

File tree

.github/workflows/static-check.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ jobs:
4646
- name: Ruff format check
4747
run: uv run --frozen ruff format --check .
4848

49+
- name: Pyright check
50+
run: uv run --frozen pyright src/clawbench tests
51+
4952
- name: Build package
5053
env:
5154
UV_FROZEN: "true"

.pre-commit-config.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,10 @@ repos:
55
- id: ruff-check
66
- id: ruff-format
77
args: [--check]
8+
- repo: local
9+
hooks:
10+
- id: pyright
11+
name: pyright
12+
entry: uv run --frozen pyright src/clawbench tests
13+
language: system
14+
pass_filenames: false

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
1010
### Changed
1111
- More data are stored in the `run-meta.json` for better post-hoc analysis and reproducibility, including the hash of the configs, runtime info, and flags used.
1212

13+
### Fixed
14+
- Fixed several compatibility issues on Windows platforms.
15+
1316
## [0.3.2] - 2026-05-15
1417
### Added
1518
- Added the logic to remove the `.log` files from the generated `data/` directory to remove noise.

pyproject.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,19 @@ exclude = [
6262
[tool.ruff]
6363
target-version = "py311"
6464

65+
[tool.pyright]
66+
include = ["src/clawbench", "tests"]
67+
exclude = [
68+
".venv",
69+
"src/clawbench/runtime/extension-server",
70+
"src/clawbench/runtime/harnesses",
71+
]
72+
6573
[dependency-groups]
6674
dev = [
6775
"jsonschema>=4.26.0",
6876
"pre-commit>=4.6.0",
77+
"pyright>=1.1.407",
6978
"pytest>=9.0.3",
7079
"ruff>=0.15.12",
7180
]

src/clawbench/runner/batch.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,7 @@ async def async_main(args: argparse.Namespace) -> int:
630630

631631
def on_signal() -> None:
632632
nonlocal sigint_count
633+
assert shutdown_event is not None
633634
sigint_count += 1
634635
shutdown_event.set()
635636

src/clawbench/tui.py

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,13 +384,55 @@ def load_cases(cases_dir_name: str = "test-cases") -> list[str]:
384384
# ---------------------------------------------------------------------------
385385

386386

387-
def _recommend_concurrent() -> int:
388-
cpus = multiprocessing.cpu_count()
387+
def _windows_physical_memory_gb() -> float | None:
388+
try:
389+
import ctypes
390+
except ImportError:
391+
return None
392+
393+
windll = getattr(ctypes, "windll", None)
394+
if windll is None:
395+
return None
396+
397+
class MEMORYSTATUSEX(ctypes.Structure):
398+
_fields_ = [
399+
("dwLength", ctypes.c_ulong),
400+
("dwMemoryLoad", ctypes.c_ulong),
401+
("ullTotalPhys", ctypes.c_ulonglong),
402+
("ullAvailPhys", ctypes.c_ulonglong),
403+
("ullTotalPageFile", ctypes.c_ulonglong),
404+
("ullAvailPageFile", ctypes.c_ulonglong),
405+
("ullTotalVirtual", ctypes.c_ulonglong),
406+
("ullAvailVirtual", ctypes.c_ulonglong),
407+
("ullAvailExtendedVirtual", ctypes.c_ulonglong),
408+
]
409+
410+
status = MEMORYSTATUSEX()
411+
status.dwLength = ctypes.sizeof(status)
412+
try:
413+
ok = windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(status))
414+
except (AttributeError, OSError):
415+
return None
416+
if not ok:
417+
return None
418+
return status.ullTotalPhys / (1024**3)
419+
420+
421+
def _physical_memory_gb() -> float:
422+
if platform.system() == "Windows":
423+
mem_gb = _windows_physical_memory_gb()
424+
if mem_gb is not None:
425+
return mem_gb
389426
try:
390427
mem_bytes = os.sysconf("SC_PAGE_SIZE") * os.sysconf("SC_PHYS_PAGES")
391-
mem_gb = mem_bytes / (1024**3)
392-
except (ValueError, OSError):
393-
mem_gb = 8
428+
return mem_bytes / (1024**3)
429+
except (AttributeError, ValueError, OSError):
430+
return 8
431+
432+
433+
def _recommend_concurrent() -> int:
434+
cpus = multiprocessing.cpu_count()
435+
mem_gb = _physical_memory_gb()
394436
by_cpu = cpus // 2
395437
by_ram = int(mem_gb // 2)
396438
recommended = max(1, min(by_cpu, by_ram))
@@ -1270,7 +1312,7 @@ def _run_streamed(cmd: list[str], *, status_msg: str) -> int:
12701312
return rc
12711313

12721314

1273-
def _fix_engine(engine: str, status: str, detail: str) -> bool:
1315+
def _fix_engine(engine: str | None, status: str, detail: str) -> bool:
12741316
"""Show an actionable panel for the engine problem and offer a fix.
12751317
12761318
Returns True if the engine is now usable, False otherwise. Safe to
@@ -1530,6 +1572,7 @@ def main() -> None:
15301572
console.print()
15311573
console.print("[bold]Welcome to ClawBench.[/]")
15321574
theme = _pick_theme()
1575+
assert theme is not None
15331576
STYLE = _make_style(theme)
15341577
# Apple HIG: Indigo for headers, Blue for inline accents
15351578
if theme == "light":

tests/test_tui_helpers.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
import subprocess
66
import sys
7+
import types
78
from pathlib import Path
9+
from typing import Any
810

911
import pytest
1012

@@ -242,6 +244,46 @@ def test_tui_recommend_concurrent_returns_positive_value(
242244
assert tui._recommend_concurrent() >= 1
243245

244246

247+
def test_tui_recommend_concurrent_uses_windows_memory(
248+
monkeypatch: pytest.MonkeyPatch,
249+
) -> None:
250+
monkeypatch.setattr(tui.platform, "system", lambda: "Windows")
251+
monkeypatch.setattr(tui.multiprocessing, "cpu_count", lambda: 16)
252+
monkeypatch.setattr(tui, "_windows_physical_memory_gb", lambda: 4)
253+
254+
assert tui._recommend_concurrent() == 2
255+
256+
257+
def test_tui_windows_physical_memory_uses_global_memory_status(
258+
monkeypatch: pytest.MonkeyPatch,
259+
) -> None:
260+
class Kernel32:
261+
def GlobalMemoryStatusEx(self, status: Any) -> int:
262+
status.ullTotalPhys = 12 * 1024**3
263+
return 1
264+
265+
fake_ctypes: Any = types.ModuleType("ctypes")
266+
fake_ctypes.Structure = object
267+
fake_ctypes.c_ulong = object()
268+
fake_ctypes.c_ulonglong = object()
269+
fake_ctypes.sizeof = lambda _status: 64
270+
fake_ctypes.byref = lambda status: status
271+
fake_ctypes.windll = types.SimpleNamespace(kernel32=Kernel32())
272+
monkeypatch.setitem(sys.modules, "ctypes", fake_ctypes)
273+
274+
assert tui._windows_physical_memory_gb() == 12
275+
276+
277+
def test_tui_physical_memory_falls_back_when_unavailable(
278+
monkeypatch: pytest.MonkeyPatch,
279+
) -> None:
280+
monkeypatch.setattr(tui.platform, "system", lambda: "Windows")
281+
monkeypatch.setattr(tui, "_windows_physical_memory_gb", lambda: None)
282+
monkeypatch.delattr(tui.os, "sysconf", raising=False)
283+
284+
assert tui._physical_memory_gb() == 8
285+
286+
245287
def test_tui_main_single_run_flow_builds_runner_command(
246288
monkeypatch: pytest.MonkeyPatch,
247289
) -> None:

uv.lock

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)