atagen

roundabout

public
Star0
Watch0
052a1a49371c39019ad2acebf23b58977d2fa829
1
ssh://brewery@pls.lobotomise.me:33/atagen/roundabout.git

Blame: src/history.rs

6f5b84fad3efatagen2026-09-27 03:59 UTC1
use std::{
6f5b84fad3efatagen2026-09-27 03:59 UTC2
    collections::BTreeMap,
6f5b84fad3efatagen2026-09-27 03:59 UTC3
    path::Path,
6f5b84fad3efatagen2026-09-27 03:59 UTC4
    time::{Duration, SystemTime, UNIX_EPOCH},
6f5b84fad3efatagen2026-09-27 03:59 UTC5
};
6f5b84fad3efatagen2026-09-27 03:59 UTC6
6f5b84fad3efatagen2026-09-27 03:59 UTC7
use serde::{Deserialize, Serialize};
6f5b84fad3efatagen2026-09-27 03:59 UTC8
6f5b84fad3efatagen2026-09-27 03:59 UTC9
use crate::{sched::Need, store, units::Bytes};
6f5b84fad3efatagen2026-09-27 03:59 UTC10
6f5b84fad3efatagen2026-09-27 03:59 UTC11
const KEEP: usize = 1000;
6f5b84fad3efatagen2026-09-27 03:59 UTC12
6f5b84fad3efatagen2026-09-27 03:59 UTC13
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
6f5b84fad3efatagen2026-09-27 03:59 UTC14
pub struct Record {
6f5b84fad3efatagen2026-09-27 03:59 UTC15
    pub runs: u32,
6f5b84fad3efatagen2026-09-27 03:59 UTC16
    pub peak_rss: Bytes,
6f5b84fad3efatagen2026-09-27 03:59 UTC17
    /// ewma, so one freak run doesn't define the command forever
6f5b84fad3efatagen2026-09-27 03:59 UTC18
    pub wall: u64,
6f5b84fad3efatagen2026-09-27 03:59 UTC19
    pub cpu: u64,
6f5b84fad3efatagen2026-09-27 03:59 UTC20
    pub cores: u32,
6f5b84fad3efatagen2026-09-27 03:59 UTC21
    pub last: u64,
6f5b84fad3efatagen2026-09-27 03:59 UTC22
}
6f5b84fad3efatagen2026-09-27 03:59 UTC23
6f5b84fad3efatagen2026-09-27 03:59 UTC24
type History = BTreeMap<String, Record>;
6f5b84fad3efatagen2026-09-27 03:59 UTC25
6f5b84fad3efatagen2026-09-27 03:59 UTC26
pub fn key(root: &Path, cmd: &[String]) -> String {
6f5b84fad3efatagen2026-09-27 03:59 UTC27
    let mut k = format!("{}\t{}", root.display(), cmd.join(" "));
6f5b84fad3efatagen2026-09-27 03:59 UTC28
    k.truncate(k.floor_char_boundary(400));
6f5b84fad3efatagen2026-09-27 03:59 UTC29
    k
6f5b84fad3efatagen2026-09-27 03:59 UTC30
}
6f5b84fad3efatagen2026-09-27 03:59 UTC31
6f5b84fad3efatagen2026-09-27 03:59 UTC32
fn now() -> u64 {
6f5b84fad3efatagen2026-09-27 03:59 UTC33
    SystemTime::now()
6f5b84fad3efatagen2026-09-27 03:59 UTC34
        .duration_since(UNIX_EPOCH)
6f5b84fad3efatagen2026-09-27 03:59 UTC35
        .map_or(0, |d| d.as_secs())
6f5b84fad3efatagen2026-09-27 03:59 UTC36
}
6f5b84fad3efatagen2026-09-27 03:59 UTC37
6f5b84fad3efatagen2026-09-27 03:59 UTC38
pub fn record(key: String, peak_rss: Bytes, wall: Duration, cpu: Duration, cores: u32) {
6f5b84fad3efatagen2026-09-27 03:59 UTC39
    let _ = store::update("history", |h: &mut History| {
6f5b84fad3efatagen2026-09-27 03:59 UTC40
        let wall = wall.as_secs();
6f5b84fad3efatagen2026-09-27 03:59 UTC41
        h.entry(key)
6f5b84fad3efatagen2026-09-27 03:59 UTC42
            .and_modify(|r| {
6f5b84fad3efatagen2026-09-27 03:59 UTC43
                r.runs += 1;
6f5b84fad3efatagen2026-09-27 03:59 UTC44
                r.peak_rss = r.peak_rss.max(peak_rss);
6f5b84fad3efatagen2026-09-27 03:59 UTC45
                r.wall = (r.wall * 7 + wall * 3) / 10;
6f5b84fad3efatagen2026-09-27 03:59 UTC46
                r.cpu = cpu.as_secs();
6f5b84fad3efatagen2026-09-27 03:59 UTC47
                r.cores = cores;
6f5b84fad3efatagen2026-09-27 03:59 UTC48
                r.last = now();
6f5b84fad3efatagen2026-09-27 03:59 UTC49
            })
6f5b84fad3efatagen2026-09-27 03:59 UTC50
            .or_insert_with(|| Record {
6f5b84fad3efatagen2026-09-27 03:59 UTC51
                runs: 1,
6f5b84fad3efatagen2026-09-27 03:59 UTC52
                peak_rss,
6f5b84fad3efatagen2026-09-27 03:59 UTC53
                wall,
6f5b84fad3efatagen2026-09-27 03:59 UTC54
                cpu: cpu.as_secs(),
6f5b84fad3efatagen2026-09-27 03:59 UTC55
                cores,
6f5b84fad3efatagen2026-09-27 03:59 UTC56
                last: now(),
6f5b84fad3efatagen2026-09-27 03:59 UTC57
            });
6f5b84fad3efatagen2026-09-27 03:59 UTC58
        if h.len() > KEEP {
6f5b84fad3efatagen2026-09-27 03:59 UTC59
            let mut ages: Vec<_> = h.iter().map(|(k, r)| (r.last, k.clone())).collect();
6f5b84fad3efatagen2026-09-27 03:59 UTC60
            ages.sort();
6f5b84fad3efatagen2026-09-27 03:59 UTC61
            for (_, k) in ages.into_iter().take(h.len() - KEEP) {
6f5b84fad3efatagen2026-09-27 03:59 UTC62
                h.remove(&k);
6f5b84fad3efatagen2026-09-27 03:59 UTC63
            }
6f5b84fad3efatagen2026-09-27 03:59 UTC64
        }
6f5b84fad3efatagen2026-09-27 03:59 UTC65
    });
6f5b84fad3efatagen2026-09-27 03:59 UTC66
}
6f5b84fad3efatagen2026-09-27 03:59 UTC67
6f5b84fad3efatagen2026-09-27 03:59 UTC68
pub fn lookup(key: &str) -> Option<Record> {
6f5b84fad3efatagen2026-09-27 03:59 UTC69
    store::load::<History>("history").get(key).copied()
6f5b84fad3efatagen2026-09-27 03:59 UTC70
}
6f5b84fad3efatagen2026-09-27 03:59 UTC71
6f5b84fad3efatagen2026-09-27 03:59 UTC72
/// padded, since the agent that under-asks is the one that ooms the video.
6f5b84fad3efatagen2026-09-27 03:59 UTC73
/// nix builds happen in nix-daemon, so their rss never shows up in ours and
6f5b84fad3efatagen2026-09-27 03:59 UTC74
/// the base estimate stands
6f5b84fad3efatagen2026-09-27 03:59 UTC75
pub fn suggest(rec: &Record, base: Need, cmd: &[String]) -> Need {
6f5b84fad3efatagen2026-09-27 03:59 UTC76
    let via_daemon = cmd
6f5b84fad3efatagen2026-09-27 03:59 UTC77
        .iter()
6f5b84fad3efatagen2026-09-27 03:59 UTC78
        .any(|t| t.contains("nix") || t.contains("home-manager"));
6f5b84fad3efatagen2026-09-27 03:59 UTC79
    Need {
6f5b84fad3efatagen2026-09-27 03:59 UTC80
        ram: if via_daemon {
6f5b84fad3efatagen2026-09-27 03:59 UTC81
            base.ram
6f5b84fad3efatagen2026-09-27 03:59 UTC82
        } else {
6f5b84fad3efatagen2026-09-27 03:59 UTC83
            Bytes(rec.peak_rss.0 + rec.peak_rss.0 / 4).max(Bytes::mib(256))
6f5b84fad3efatagen2026-09-27 03:59 UTC84
        },
6f5b84fad3efatagen2026-09-27 03:59 UTC85
        cores: rec.cores.max(1),
6f5b84fad3efatagen2026-09-27 03:59 UTC86
        time: Duration::from_secs((rec.wall * 3 / 2).max(30)),
6f5b84fad3efatagen2026-09-27 03:59 UTC87
        ..base
6f5b84fad3efatagen2026-09-27 03:59 UTC88
    }
6f5b84fad3efatagen2026-09-27 03:59 UTC89
}