Files
darling-lol/tools/build-riot-cxx-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

69 lines
3.0 KiB
Python

#!/usr/bin/env python3
"""Rebuild libc++ and libc++abi with -O2.
The CMake tree has no build type, so both libraries are clang's -O0 output: the
game imports 131 functions from libc++.1.dylib (out-of-line std::string,
iostream, locale, shared_ptr/atomic refcounts, mutex, chrono, new/delete) and
13 from libc++abi.dylib, and neither has an overlay today.
This is tools/build-riot-cxx-optimized.py without -DNDEBUG: the configured
defines and includes are kept exactly, only the optimization level changes.
The earlier builder also compiles libc++ at -O2, but with assertions disabled,
which changes what the library checks at run time; the batch installer uses
this one so the shipped library differs from the configured build in code
generation only. Outputs build/riot-libc++.1.dylib and build/riot-libc++abi.dylib.
"""
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
import re
import shlex
import subprocess
import sys
sys.path.insert(0, str(Path(__file__).resolve().parent))
import riot_build_gate
root = Path(__file__).resolve().parent.parent
resource_dir = subprocess.check_output(["clang", "-print-resource-dir"], text=True).strip()
def current_clang(values):
return [re.sub(r"/usr/lib/clang/\d+/include", resource_dir + "/include", value) for value in values]
def build(library, object_dir, link_dir, output):
folder = root / "build/darling-src/build/src/external" / library
source = root / "build/darling-src/src/external" / library
flags = {}
for line in (folder / ("CMakeFiles/%s/flags.make" % object_dir)).read_text().splitlines():
if line.startswith("CXX_") and " = " in line:
key, value = line.split(" = ", 1)
flags[key] = current_clang(shlex.split(value))
link = shlex.split((folder / ("CMakeFiles/%s/link.txt" % link_dir)).read_text())
jobs = []
for index, argument in enumerate(link):
if argument.startswith("CMakeFiles/%s/" % object_dir) and argument.endswith(".o"):
relative = argument[len("CMakeFiles/%s/" % object_dir):-2]
obj = root / ("build/riot-opt-%s-%s.o" % (library, relative.replace("/", "_")))
jobs.append((relative, obj))
link[index] = str(obj)
print(library, "recompiling", len(jobs), "objects at -O2", flush=True)
def compile_one(job):
relative, obj = job
subprocess.run(["clang++", *flags["CXX_DEFINES"], *flags["CXX_INCLUDES"], *flags["CXX_FLAGS"],
"-O2", "-fno-strict-aliasing", "-c", str(source / relative), "-o", str(obj)],
check=True, capture_output=True)
riot_build_gate.wait_until_free()
with ThreadPoolExecutor(max_workers=6) as pool:
list(pool.map(compile_one, jobs))
link[link.index("-o") + 1] = str(root / "build" / output)
subprocess.run(link, cwd=folder, check=True)
print("built build/" + output, len(jobs), "objects at -O2", flush=True)
if __name__ == "__main__":
build("libcxxabi", "cxxabi_obj.dir", "cxxabi.dir", "riot-libc++abi.dylib")
build("libcxx", "cxx_obj.dir", "cxx.dir", "riot-libc++.1.dylib")