Ember helper (F), from the 0.3.16 window on PC 1: the tune path wrote its request index as the wire sequence ("00 dev 1", "01 pl 160") below the cap path's unix-based numbers, so the helper skipped every tune command as stale and both climbs stopped on "the helper did not run sequence 1 within 15 s"; every writer now draws from one monotonic space (powertask::wire_seq), the acknowledgement matches the wire number; test
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 9007792742)
This commit is contained in:
parent
c88504b47b
commit
16ec189a0b
2 changed files with 21 additions and 4 deletions
|
|
@ -1905,7 +1905,7 @@ impl Engine {
|
|||
std::thread::spawn(move || {
|
||||
let r = crate::powertask::start().and_then(|_| {
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
let mut seq = crate::platform::unix_now() % 1_000_000;
|
||||
let mut seq = crate::powertask::wire_seq();
|
||||
let mut text = String::new();
|
||||
for (dev, w) in &pairs {
|
||||
seq += 1;
|
||||
|
|
@ -2583,7 +2583,7 @@ impl Engine {
|
|||
// under a scratch IGNEUM_APP_DATA), no prompt
|
||||
let hdir = crate::powertask::helper_dir();
|
||||
let _ = std::fs::create_dir_all(&hdir);
|
||||
let _ = std::fs::write(hdir.join("cmd.txt"), format!("{} dev {}\n", crate::platform::unix_now() % 1_000_000, c.device));
|
||||
let _ = std::fs::write(hdir.join("cmd.txt"), format!("{} dev {}\n", crate::powertask::wire_seq(), c.device));
|
||||
crate::powertask::start()?;
|
||||
self.shared.log("tune helper: the Igneum Power Helper task (no prompt)");
|
||||
self.sweep_helper = true;
|
||||
|
|
@ -2664,7 +2664,10 @@ impl Engine {
|
|||
return;
|
||||
}
|
||||
let dev = device.to_string();
|
||||
let cmd = format!("{seq}0 dev {dev}\n{seq}1 pl {w}\n{seq}2 {}\n{seq}3 {}\n", if clock > 0 { format!("lgc {clock}") } else { "rgc".to_string() }, if mem > 0 { format!("lmc {mem}") } else { "rmc".to_string() });
|
||||
// (F) the wire numbers come from the one monotonic space every writer uses (powertask::wire_seq);
|
||||
// `seq` (the run's request index) stays the engine's own id for the acknowledgement
|
||||
let wire = crate::powertask::wire_seq();
|
||||
let cmd = format!("{} dev {dev}\n{} pl {w}\n{} {}\n{} {}\n", wire, wire + 1, wire + 2, if clock > 0 { format!("lgc {clock}") } else { "rgc".to_string() }, wire + 3, if mem > 0 { format!("lmc {mem}") } else { "rmc".to_string() });
|
||||
let dir = self.helper_cmd_dir();
|
||||
let is_task = self.sweep_helper_is_task;
|
||||
// 6 October 2026, PC 1: (B) the task's helper had exited while the engine's flag still said it ran,
|
||||
|
|
@ -2674,7 +2677,7 @@ impl Engine {
|
|||
// is started and a fresh heartbeat awaited BEFORE the command is written; and the acknowledgement
|
||||
// is the helper's own log line for this sequence (`<seq>3 nvidia-smi ...`), read for up to 15 s;
|
||||
// a missing line is a failure with that reason
|
||||
let want = format!(" {seq}3 nvidia-smi");
|
||||
let want = format!(" {} nvidia-smi", wire + 3);
|
||||
let log_file = dir.join("helper.log");
|
||||
std::thread::spawn(move || {
|
||||
if is_task {
|
||||
|
|
|
|||
|
|
@ -119,6 +119,17 @@ pub fn parse_line(line: &str) -> Option<(u64, HelperCmd)> {
|
|||
}
|
||||
}
|
||||
|
||||
/// The sequence number a command line carries on the wire. The helper runs a line only when its number is above
|
||||
/// every number it has seen (its `last_seq`, seeded from the file at its start), so every writer must draw from
|
||||
/// ONE monotonic space: the unix time modulo a million (six digits, what `parse_line` accepts), plus a small
|
||||
/// offset per line. (F) 6 October 2026, 22:19Z on PC 1: the tune path wrote its request index ("00 dev 1", "01 pl
|
||||
/// 160", ...) while the cap path had written 305327 and up, so the helper skipped every tune command as stale and
|
||||
/// both climbs stopped on "the helper did not run sequence 1 within 15 s". Wraps every 11.6 days; the helper's
|
||||
/// idle exit (20 minutes) re-seeds it from the file, so a wrap costs at most one tune step.
|
||||
pub fn wire_seq() -> u64 {
|
||||
crate::platform::unix_now() % 999_990
|
||||
}
|
||||
|
||||
/// The commands a helper acts on: the lines added after its start (`skip` = the line count at the start, 0 again
|
||||
/// when the file shrank). A stale `quit` or `remove` from an earlier engine is never a command.
|
||||
pub fn commands_after(text: &str, skip: usize) -> Vec<(u64, HelperCmd)> {
|
||||
|
|
@ -360,6 +371,9 @@ mod tests {
|
|||
assert_eq!(commands_after("5 dev 0\n6 pl 460\nquit\n7 dev 1\n", 3), vec![(7, HelperCmd::Dev("1".into()))]);
|
||||
assert_eq!(commands_after("quit\n", 3), vec![(0, HelperCmd::Quit)]);
|
||||
// the heartbeat: fresh within ALIVE_MAX_S, dead after, dead when unreadable
|
||||
// (F) every wire number parses (six digits at most) and leaves room for the four lines of a tune step
|
||||
let w = wire_seq();
|
||||
assert!(w + 3 <= 999_999 && parse_line(&format!("{} rmc", w + 3)).is_some());
|
||||
assert!(alive_at("1791309325", 1791309325 + ALIVE_MAX_S));
|
||||
assert!(!alive_at("1791309325", 1791309325 + ALIVE_MAX_S + 1));
|
||||
assert!(!alive_at("", 1791309325));
|
||||
|
|
|
|||
Loading…
Reference in a new issue