mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-01 07:33:45 -06:00
feat: take the host probe lock per run
core_probe takes probe.lock itself around one execution, load check included, and releases it when the run ends. A campaign pass never holds it between runs, so two passes interleave. RETROBIOS_PROBE_LOCK names another file, RETROBIOS_PROBE_LOCK_HELD says the caller holds it. Tests use their own lock file.
This commit is contained in:
1 parent
b6ed5ba0a1
commit
fabd431adb
6 files changed
+129
-3
No files matched your search
+40
-1
@@ -21,6 +21,7 @@ import argparse
|
||||
import contextlib
|
||||
import ctypes
|
||||
import datetime as dt
|
||||
import fcntl
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
@@ -35,7 +36,7 @@ import sys
|
||||
import tempfile
|
||||
import time
|
||||
import zlib
|
||||
from collections.abc import Iterable, Sequence
|
||||
from collections.abc import Iterable, Iterator, Sequence
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
|
||||
@@ -73,6 +74,39 @@ PRINTF_SPEC = re.compile(r"%(?P<flags>[-+ #0]*)(?P<width>\*|\d+)?(?:\.(?P<prec>\
|
||||
r"(?P<len>hh|h|ll|l|j|z|t|L)?(?P<conv>[diouxXeEfFgGaAcspn%])")
|
||||
|
||||
|
||||
# One measurement at a time on the host: each core_probe execution takes this
|
||||
# lock itself, its load check included, and releases it when it ends. A pass
|
||||
# of many runs never holds it between them, so two passes interleave.
|
||||
PROBE_LOCK_ENV = "RETROBIOS_PROBE_LOCK"
|
||||
PROBE_LOCK_HELD_ENV = "RETROBIOS_PROBE_LOCK_HELD"
|
||||
DEFAULT_PROBE_LOCK = Path.home() / ".local" / "state" / "retrobios" / "probe.lock"
|
||||
|
||||
|
||||
def probe_lock_path() -> Path:
|
||||
return Path(os.environ.get(PROBE_LOCK_ENV) or DEFAULT_PROBE_LOCK)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def host_probe_lock() -> Iterator[None]:
|
||||
"""The host's probe lock for one execution. A caller that already holds
|
||||
it for this run says so with RETROBIOS_PROBE_LOCK_HELD."""
|
||||
if os.environ.get(PROBE_LOCK_HELD_ENV):
|
||||
yield
|
||||
return
|
||||
path = probe_lock_path()
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with path.open("a") as handle:
|
||||
try:
|
||||
fcntl.flock(handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||
except BlockingIOError:
|
||||
print(f"waiting for {path}: another measurement is running", file=sys.stderr)
|
||||
fcntl.flock(handle, fcntl.LOCK_EX)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
fcntl.flock(handle, fcntl.LOCK_UN)
|
||||
|
||||
|
||||
class ProbeError(RuntimeError):
|
||||
"""A run that cannot produce a trustworthy result."""
|
||||
|
||||
@@ -1355,6 +1389,11 @@ def probe(args: argparse.Namespace) -> int:
|
||||
for problem in problems:
|
||||
print(f"ERROR: {problem}", file=sys.stderr)
|
||||
return 2
|
||||
with host_probe_lock():
|
||||
return _probe(args)
|
||||
|
||||
|
||||
def _probe(args: argparse.Namespace) -> int:
|
||||
max_load = args.max_load if args.max_load is not None else (os.cpu_count() or 1) / 4
|
||||
load_before = load_average()
|
||||
if args.record and load_before and load_before[0] > max_load:
|
||||
|
||||
Reference in new issue
Block a user