Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions ansible/roles/developer-rust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,15 @@ developer installed is their call.
`build.build-dir` is stable from Rust 1.91. On an older toolchain the setup tool
says so and leaves the per-project layout alone, so the default stays safe.

## Bounding concurrent builds
## The build governor

`hyperi-rust-govern` is installed as `~/.local/bin/cargo`, ahead of the real
cargo on PATH, so a developer or an agent who knows none of this runs
`cargo build` and is governed: it holds one of N slots sized from the memory
budget, and on Linux with a live user manager also lands in `rust-build.slice`.
How N is chosen, what happens at saturation, and why it needs the `zram_swap`
role are in [docs/rust-build-governor.md](../../../docs/rust-build-governor.md).
`cargo build` and is governed: nice 19, and on Linux with a live user manager
`rustbuild.slice`, which bounds memory and sits below the desktop for CPU.
Which instrument yields on which host, and why it needs the `zram_swap` role,
are in
[docs/rust-build-governor.md](../../../docs/rust-build-governor.md).
The host-wide picture is
[docs/concurrent-dev-cache.md](../../../docs/concurrent-dev-cache.md).

Expand Down
53 changes: 16 additions & 37 deletions ansible/roles/developer-rust/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,32 +107,18 @@ rust_sccache_service_manage: true
# Concurrent cargo/rustc across several projects can OOM a host outright --
# observed taking down a 30G build box. Opt-OUT: disabling it removes the
# shim, the slice and the config.
rust_governor_enabled: true

# How many rust builds may be resident at once, per user. A memory semaphore,
# not a queue length: memory is spent per CRATE rather than per job, so the
# thing worth bounding is concurrent BUILDS and the bound is the slice's memory
# budget divided by what one build costs.
#
# auto derive from this host's RAM (see rust_governor_build_allowance_gb)
# <int> pin the count; 1 is a global mutex, which is what this used to be
# 0 no semaphore at all
# MEMORY is BOUNDED, by rustbuild.slice: MemoryHigh throttles by reclaim and
# MemoryMax kills the build rather than the host. Both are percentages of the
# host's own RAM, so one number fits a laptop and a build box.
#
# `auto` on a 32 GB host computes 1, which is the check that the model
# reproduces the behaviour that is known to work.
rust_governor_slots: auto

# What one build is assumed to cost, in GB: the largest single rustc plus
# headroom. Derived from an 11.6 GB peak on one workspace, so it is a starting
# point rather than a constant -- a codebase whose memory scales with the job
# count instead of with one huge crate will want a different number.
rust_governor_build_allowance_gb: 14

# Seconds to wait for a slot. On expiry the build proceeds at the FLOOR job
# count, still inside the slice -- it degrades, it is not released. Waiting the
# full time and then building unbounded would drop the limit at exactly the
# moment contention is highest.
rust_governor_lock_wait_seconds: 1800
# CPU is not bounded at all -- it is DEFERRED. Builds run at nice 19 under a
# below-desktop CPUWeight, so they take every core while nobody else wants one
# and drop to about a quarter the moment the desktop does. Nothing withholds
# cores and nothing sets a job count: cargo's own default is already every
# core, and rationing CPU costs throughput on an idle machine to buy
# responsiveness that only matters on a busy one.
rust_governor_enabled: true

# Whether governed builds run with CARGO_INCREMENTAL=0, so sccache can cache
# them. sccache refuses to cache any rustc call carrying -C incremental.
Expand Down Expand Up @@ -160,24 +146,17 @@ rust_governor_memory_high_pct: 50
rust_governor_memory_max_pct: 70
rust_governor_swap_max_pct: 25

# Weight is contention-only: the desktop always wins under load, and an idle
# machine still gives builds full speed. 100 is the systemd default weight.
# Contention-only: the desktop wins under load, and an idle machine still gives
# builds every core. 100 is the systemd default, so 30 is a bit under a third of
# the desktop's share when both want the CPU at once. This, not the shim's nice
# 19, is what makes a build yield on Linux -- rustbuild.slice.j2 says why.
rust_governor_cpu_weight: 30

# Cores held back from builds on any host with 4 or more; smaller hosts keep
# every core. Taken off the top BEFORE the remainder is divided between
# concurrent builds, so the desktop keeps its share at every slot count.
rust_governor_cpu_reserve_cores: 2

# macOS has no cgroups; builds run under this taskpolicy QoS clamp instead.
# `utility` sits below the desktop without background's disk-IO throttle and
# E-core pinning.
rust_governor_macos_qos: utility

# The user manager's runtime directory, for every `systemctl --user` call the
# role makes. Defined once because the fallback is wrong on a fleet box:
# actual_user_uid is set by the developer role's init, which does not run under
# a --tags run, so every call then falls back to the CONNECTION user's uid.
# When that is fixed it is fixed here, in one place.
developer_rust_uid: "{{ actual_user_uid | default(ansible_facts['user_uid']) }}"
developer_rust_user_env:
XDG_RUNTIME_DIR: "/run/user/{{ actual_user_uid | default(ansible_facts['user_uid']) }}"
XDG_RUNTIME_DIR: "/run/user/{{ developer_rust_uid }}"
Loading
Loading