from __future__ import annotations
import json
import os
import subprocess
import tempfile
import time
from pathlib import Path
def main() -> int:
with tempfile.TemporaryDirectory(prefix="bot-forge-cargo-stress-") as directory:
root = Path(directory)
members = []
for index in range(20):
name = f"stress-{index}"
members.append(f'"{name}"')
crate = root / name
(crate / "src" / "bin").mkdir(parents=True)
build = 'build = "build.rs"\n' if index == 0 else ""
(crate / "Cargo.toml").write_text(
f'[package]\nname = "{name}"\nversion = "0.1.0"\nedition = "2021"\n{build}'
f'[[bin]]\nname = "{name}"\npath = "src/main.rs"\n'
f'[[bin]]\nname = "shared-{index}"\npath = "src/bin/shared.rs"\n',
encoding="utf-8",
)
(crate / "src" / "main.rs").write_text("fn main() {}\n", encoding="utf-8")
(crate / "src" / "bin" / "shared.rs").write_text("fn main() {}\n", encoding="utf-8")
if index == 0:
(crate / "build.rs").write_text('fn main() { println!("cargo:rerun-if-changed=build.rs"); }\n', encoding="utf-8")
(root / "Cargo.toml").write_text(
f'[workspace]\nresolver = "2"\nmembers = [{", ".join(members)}]\n',
encoding="utf-8",
)
env = os.environ.copy()
env["CARGO_BUILD_JOBS"] = str(min(4, os.cpu_count() or 1))
target = root / "target"
command = ["cargo", "build", "--workspace", "--locked", "--offline", "--target-dir", str(target)]
serial_command = command + ["--jobs", "1"]
subprocess.run(["cargo", "generate-lockfile", "--offline"], cwd=root, env=env, check=True)
serial_target = root / "serial-target"
serial_command[serial_command.index(str(target))] = str(serial_target)
serial_started = time.perf_counter()
subprocess.run(serial_command, cwd=root, env=env, check=True, stdout=subprocess.DEVNULL)
serial_ms = round((time.perf_counter() - serial_started) * 1000, 3)
samples = []
for _ in range(2):
started = time.perf_counter()
subprocess.run(command, cwd=root, env=env, check=True, stdout=subprocess.DEVNULL)
samples.append(round((time.perf_counter() - started) * 1000, 3))
binaries = sum(1 for path in (target / "debug").iterdir() if path.is_file() and path.suffix not in {".d", ".rlib"})
if binaries < 40:
raise SystemExit(f"expected at least 40 binaries, found {binaries}")
if samples[1] > max(1000, samples[0] * 0.5):
raise SystemExit(f"warm Cargo build did not reuse cache: cold={samples[0]} warm={samples[1]}")
print(json.dumps({"crates": 20, "binaries": binaries, "serial_ms": serial_ms, "parallel_cold_ms": samples[0], "warm_ms": samples[1]}))
return 0
if __name__ == "__main__":
raise SystemExit(main())