Files
darling-lol/tools/install-riot-libs-runtime.py
T
lucannez64andClaude Opus 5.5 4370f375cd Cut Darling overhead in League fights and add passive match capture
Game process (ARAM Hexgate: 84 -> 127 FPS average, slowest stretches ~110):
- Local pthread mutexes, condition variables and Mach semaphores are on by
  default in the game process only, with /tmp/rclol-no-local-* opt-outs.
  The main thread's darlingserver waits fell from 1.36 to 0.10 ms per frame.
- Local semaphores: the count and the slot generation change in one
  compare-exchange, a destroy leaves a negative marker, the table is reset
  after fork, and names the table did not create go to the server.
- Metal: drop identical re-binds (keyed on the Indium object, depth-stencil
  retained), pass blit resources by reference, and stop resetting vertex
  descriptors twice.
- Core isolation of the main thread is opt-in (/tmp/rclol-core-isolation);
  it lowered FPS in its only match.
- Optimized libc/libc++/Foundation overlays, AVX2 string primitives, real CPU
  topology and their installers and offline checks.

Tools and docs:
- tools/riot-match-capture: passive /proc sampler, user-space IP profiler and
  reports, plus a comparison against the game's netstats.
- tools/riot-lsem-model and tools/riot-metal-bind-model: host models that
  extract the shipped code and check it.
- tools/install-riot-metal-pair.sh installs Metal and Indium together.
- Status, setup, testing and troubleshooting docs updated with the measured
  matches and the switch table; manifest file counts match the patches.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 16:48:34 +02:00

214 lines
10 KiB
Python

#!/usr/bin/env python3
"""Install the optimized libc, libc++ and libsystem_platform overlays.
The guest finds a library by leaf name in DYLD_LIBRARY_PATH before its install
path (dyld3/PathOverrides.cpp:forEachPathVariant), so a file in the per-user
RuntimeLibraries directory replaces the copy in the prefix and in the installed
SDK without touching either. The overlays installed here are exactly the
artifacts built by tools/build-riot-*.py; each is staged next to its
destination, verified against the built file, and renamed over the old one
after the old one is backed up. --rollback restores every file this installer
replaced and removes the ones it created.
This installer was checked offline (tools/riot-libs-installer-offline-check.py)
and is never run against the real prefix by the build. Nothing is activated
until the guest processes are restarted.
"""
import argparse
import hashlib
import json
import os
from pathlib import Path
import shutil
import stat
import tempfile
ROOT = Path(__file__).resolve().parent.parent
# (built artifact, file name in the guest's RuntimeLibraries directory). The
# artifacts are the ones tools/build-riot-libs-runtime.sh builds.
# libsystem_m is deliberately absent: its C sources are built at -O0 upstream and an
# -O2 rebuild made the Riot client UI render a black window (2026-10-13).
LIBRARIES = [
("build/riot-libsystem_c.dylib", "libsystem_c.dylib"),
("build/riot-libc++.1.dylib", "libc++.1.dylib"),
("build/riot-libc++abi.dylib", "libc++abi.dylib"),
("build/riot-libsystem_platform.dylib", "libsystem_platform.dylib"),
]
def digest(path):
with path.open("rb") as input:
return hashlib.file_digest(input, "sha256").hexdigest()
def destinations(prefix, guest_home):
folder = Path(prefix) / guest_home.lstrip("/") / "RuntimeLibraries"
return [(ROOT / artifact, folder / name) for artifact, name in LIBRARIES]
def existing_records(backup_folder):
"""What the previous installation recorded, so a second run keeps the
state from before the first one instead of overwriting it."""
manifest = backup_folder / "manifest.json"
if not manifest.is_file():
return {}
return {record["path"]: record for record in json.loads(manifest.read_text())["libraries"]}
def install(libraries, backup_folder):
previous_records = existing_records(backup_folder)
expected = {}
for artifact, destination in libraries:
if not artifact.is_file():
raise ValueError("The artifact does not exist: " + str(artifact))
with artifact.open("rb") as input:
if input.read(4) not in (b"\xcf\xfa\xed\xfe", b"\xce\xfa\xed\xfe"):
raise ValueError("Expected a 64-bit Mach-O library: " + str(artifact))
expected[destination] = digest(artifact)
records, staged = [], []
try:
for index, (artifact, destination) in enumerate(libraries):
earlier = previous_records.get(str(destination))
current = digest(destination) if destination.is_file() else None
if current == expected[destination]:
# keep the state from before the first installation, if any
records.append({"path": str(destination), "already_current": True,
"existed": earlier["existed"] if earlier else destination.is_file(),
"previous_sha256": earlier["previous_sha256"] if earlier else current,
"backup": earlier.get("backup") if earlier else None,
"sha256": expected[destination]})
continue
existed = earlier["existed"] if earlier else destination.is_file()
previous = earlier["previous_sha256"] if earlier else current
backup = Path(earlier["backup"]) if earlier and earlier.get("backup") else None
if backup is None and current is not None:
backup_folder.mkdir(parents=True, exist_ok=True)
backup = backup_folder / ("%d-%s.dylib" % (index, current))
if backup.exists():
if digest(backup) != current:
raise ValueError("The existing backup has unexpected contents: " + str(backup))
else:
shutil.copy2(destination, backup)
metadata = destination.stat() if destination.is_file() else None
descriptor, temporary = tempfile.mkstemp(prefix="." + destination.name + "-staged-",
dir=destination.parent)
staged.append((Path(temporary), destination))
with os.fdopen(descriptor, "wb") as output, artifact.open("rb") as input:
shutil.copyfileobj(input, output)
output.flush()
if metadata is not None:
os.fchmod(output.fileno(), stat.S_IMODE(metadata.st_mode))
os.fchown(output.fileno(), metadata.st_uid, metadata.st_gid)
else:
os.fchmod(output.fileno(), 0o755)
os.fsync(output.fileno())
if digest(Path(temporary)) != expected[destination]:
raise ValueError("The staged library does not match the build: " + str(artifact))
records.append({"path": str(destination), "backup": str(backup) if backup else None,
"existed": existed, "sha256": expected[destination],
"previous_sha256": previous})
for temporary, destination in staged:
os.replace(temporary, destination)
directory = os.open(destination.parent, os.O_DIRECTORY)
try:
os.fsync(directory)
finally:
os.close(directory)
for record in records:
path = Path(record["path"])
if not path.is_file() or digest(path) != record["sha256"]:
raise ValueError("Installed library verification failed: " + str(path))
backup_folder.mkdir(parents=True, exist_ok=True)
manifest = backup_folder / "manifest.json"
manifest.write_text(json.dumps({"libraries": records}, indent=1) + "\n")
finally:
for temporary, _ in staged:
if temporary.exists():
temporary.unlink()
return {"installed": True, "libraries": records, "restart_performed": False,
"manifest": str(backup_folder / "manifest.json"),
"activation": "Exit the game and the clients, then start them again; a running guest keeps the library it already loaded."}
def rollback(backup_folder):
manifest = backup_folder / "manifest.json"
if not manifest.is_file():
raise ValueError("No installation manifest in " + str(backup_folder))
records = json.loads(manifest.read_text())["libraries"]
restored, removed = [], []
for record in reversed(records):
destination = Path(record["path"])
if record.get("previous_sha256") is None:
# the installer created this file; removing it restores the SDK copy
if destination.is_file() and digest(destination) == record["sha256"]:
destination.unlink()
removed.append(str(destination))
else:
backup = Path(record["backup"])
if not backup.is_file():
raise ValueError("The backup is missing: " + str(backup))
if digest(backup) != record["previous_sha256"]:
raise ValueError("The backup has unexpected contents: " + str(backup))
descriptor, temporary = tempfile.mkstemp(prefix="." + destination.name + "-restore-",
dir=destination.parent)
with os.fdopen(descriptor, "wb") as output, backup.open("rb") as input:
shutil.copyfileobj(input, output)
output.flush()
os.fchmod(output.fileno(), 0o755)
os.fsync(output.fileno())
os.replace(temporary, destination)
restored.append(str(destination))
return {"rolled_back": True, "restored": restored, "removed": removed,
"activation": "Exit the game and the clients, then start them again."}
def parse_arguments(argv=None):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--prefix", type=Path, default=None,
help="guest prefix (default: build/config.json)")
parser.add_argument("--guest-home", default=None)
parser.add_argument("--backup-dir", type=Path, default=ROOT / "build/libs-runtime-backups")
parser.add_argument("--only", default=None,
help="comma-separated library names to install instead of all of them "
"(to isolate a faulty overlay; run --rollback before changing the set)")
parser.add_argument("--rollback", action="store_true",
help="restore every file this installer replaced and remove the ones it created")
return parser, parser.parse_args(argv)
def main(argv=None):
parser, arguments = parse_arguments(argv)
if arguments.rollback:
try:
print(json.dumps(rollback(arguments.backup_dir)))
except (ValueError, OSError) as error:
parser.exit(1, str(error) + "\n")
return
config = json.loads((ROOT / "build/config.json").read_text())
prefix = arguments.prefix or config["prefix"]
guest_home = arguments.guest_home or config["guest_home"]
libraries = destinations(prefix, guest_home)
if arguments.only:
wanted = set(arguments.only.split(","))
unknown = wanted - {name for _, name in LIBRARIES}
if unknown:
parser.exit(1, "Unknown library: " + ", ".join(sorted(unknown)) + "\n")
libraries = [(artifact, destination) for artifact, destination in libraries
if destination.name in wanted]
for artifact, _ in libraries:
if not artifact.is_file():
parser.exit(1, "The library to install does not exist: " + str(artifact)
+ "; build it first: sh build/runtime/tools/build-riot-libs-runtime.sh\n")
try:
result = install(libraries, arguments.backup_dir)
except PermissionError as error:
parser.exit(1, "Cannot write " + str(error.filename) + "; choose a writable --backup-dir or run "
"the installer with sudo.\n")
result["prefix"] = str(prefix)
print(json.dumps(result))
if __name__ == "__main__":
main()