Ember helper, two bugs from PC 1 on 6 October 2026: (A) a helper acts only on lines added after its start, so a stale quit or remove never kills a later start (commands_after + test); (B) the engine starts the task again before every task-path step and the acknowledgement is the helper's own log line for the sequence (up to 15 s), a missing line fails the step with that reason instead of a blind 4-second ack. Playbooks read the app log from <data root>\logs, where it lives
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
14dc093549
commit
0659fab5f2
4 changed files with 55 additions and 11 deletions
|
|
@ -2567,11 +2567,36 @@ impl Engine {
|
|||
}
|
||||
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() });
|
||||
let _ = std::fs::write(self.helper_cmd_dir().join("cmd.txt"), cmd);
|
||||
// the helper polls twice a second and nvidia-smi answers within a second or two
|
||||
let dir = self.helper_cmd_dir();
|
||||
let is_task = self.sweep_helper_is_task;
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
let _ = std::fs::write(dir.join("cmd.txt"), cmd);
|
||||
// 6 October 2026, PC 1 18:18Z: the task's helper had exited (20 idle minutes) while the engine's flag
|
||||
// still said it ran, so the commands went to nobody and a blind 4-second sleep called them
|
||||
// acknowledged. Now: the task is started again before every step (Start-ScheduledTask ignores a
|
||||
// start while one runs), 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
|
||||
if is_task {
|
||||
if let Err(e) = crate::powertask::start() {
|
||||
self.shared.log(&format!("tune helper: the task could not be started ({e})"));
|
||||
}
|
||||
}
|
||||
let want = format!(" {seq}3 nvidia-smi");
|
||||
let log_file = dir.join("helper.log");
|
||||
std::thread::spawn(move || {
|
||||
std::thread::sleep(Duration::from_secs(4));
|
||||
shared.send(Cmd::TuneSet(seq, Ok("helper".into())));
|
||||
let until = Instant::now() + Duration::from_secs(if is_task { 15 } else { 6 });
|
||||
loop {
|
||||
std::thread::sleep(Duration::from_millis(500));
|
||||
let text = std::fs::read_to_string(&log_file).unwrap_or_default();
|
||||
if let Some(line) = text.lines().rev().find(|l| l.contains(&want)) {
|
||||
shared.send(Cmd::TuneSet(seq, Ok(format!("helper: {}", line.trim()))));
|
||||
return;
|
||||
}
|
||||
if Instant::now() >= until {
|
||||
shared.send(Cmd::TuneSet(seq, Err(format!("the helper did not run sequence {seq} within {} s (no line in {})", if is_task { 15 } else { 6 }, log_file.display()))));
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
"amd" => {
|
||||
|
|
|
|||
|
|
@ -79,6 +79,13 @@ pub fn parse_line(line: &str) -> Option<(u64, HelperCmd)> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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)> {
|
||||
let skip = if text.lines().count() < skip { 0 } else { skip };
|
||||
text.lines().skip(skip).filter_map(parse_line).collect()
|
||||
}
|
||||
|
||||
/// The nvidia-smi arguments a command becomes (None for the verbs that run nothing).
|
||||
pub fn smi_args(dev: &str, c: &HelperCmd) -> Option<Vec<String>> {
|
||||
match c {
|
||||
|
|
@ -195,17 +202,25 @@ pub fn run_helper(dir: &Path) -> i32 {
|
|||
}
|
||||
};
|
||||
log("helper started (scheduled task, elevated)");
|
||||
// a stale file from an earlier run is not a command: only lines after the start count
|
||||
let mut last_seq: u64 = std::fs::read_to_string(&cmd_file).ok().and_then(|t| t.lines().filter_map(parse_line).map(|(s, _)| s).max()).unwrap_or(0);
|
||||
let mut last_text = String::new();
|
||||
// a stale file from an earlier run is not a command: only lines ADDED after the start count. 6 October 2026,
|
||||
// PC 1 17:55:55Z: a helper that started after an engine had written `quit` read that line and exited in the
|
||||
// same second, and every later start did the same; so the lines present at the start are skipped whole
|
||||
// (quit and remove included), and a file that shrinks starts the count again
|
||||
let initial = std::fs::read_to_string(&cmd_file).unwrap_or_default();
|
||||
let mut last_seq: u64 = initial.lines().filter_map(parse_line).map(|(s, _)| s).max().unwrap_or(0);
|
||||
let mut skip = initial.lines().count();
|
||||
let mut last_text = initial;
|
||||
let mut dev = "0".to_string();
|
||||
let mut idle = Instant::now();
|
||||
let smi = crate::platform::tool("nvidia-smi");
|
||||
loop {
|
||||
let text = std::fs::read_to_string(&cmd_file).unwrap_or_default();
|
||||
if text != last_text {
|
||||
if text.lines().count() < skip {
|
||||
skip = 0;
|
||||
}
|
||||
last_text = text.clone();
|
||||
for (seq, c) in text.lines().filter_map(parse_line) {
|
||||
for (seq, c) in commands_after(&text, skip) {
|
||||
match c {
|
||||
HelperCmd::Quit => {
|
||||
log("quit");
|
||||
|
|
@ -296,6 +311,10 @@ mod tests {
|
|||
assert_eq!(parse_line("quit"), Some((0, HelperCmd::Quit)));
|
||||
assert_eq!(parse_line("remove"), Some((0, HelperCmd::Remove)));
|
||||
assert_eq!(parse_line("12 reregister"), Some((12, HelperCmd::Reregister)));
|
||||
// a stale quit present at the start is skipped; a quit added later counts; a rewritten (shorter) file counts whole
|
||||
assert_eq!(commands_after("5 dev 0\n6 pl 460\nquit\n", 3), vec![]);
|
||||
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)]);
|
||||
assert_eq!(parse_line("12 reregister C:\\evil.exe"), None, "no path argument: the helper picks the install folder itself");
|
||||
assert_eq!(smi_args("0", &HelperCmd::Reregister), None);
|
||||
assert!(readback_command().contains("Actions[0].Execute"));
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ if (-not (Post 'api/tune/goal' '{"goal":"balanced","climb":true}')) { Write-Outp
|
|||
Start-Sleep -Seconds 2
|
||||
$order = @($cards | Where-Object { $_.vendor -eq 'amd' }) + @($cards | Where-Object { $_.vendor -eq 'nvidia' })
|
||||
$deadline = (Get-Date).AddMinutes(27)
|
||||
$logs = Join-Path $appDir 'logs'
|
||||
$logs = Join-Path $env:LOCALAPPDATA 'igneum\logs' # the app's log folder is <data root>\logs (platform::log_dir), not app\logs (6 October 2026: the first window read no log at all)
|
||||
function LogMark() { $l = Get-ChildItem -Path $logs -Filter 'app-*.log' -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1; if ($l) { return @{ f = $l.FullName; n = (Get-Content -LiteralPath $l.FullName).Count } } else { return @{ f = ''; n = 0 } } }
|
||||
function LogSince($m) { if (-not $m.f) { return @() }; $all = @(Get-Content -LiteralPath $m.f -ErrorAction SilentlyContinue); if ($all.Count -le $m.n) { return @() }; return @($all[$m.n..($all.Count - 1)]) }
|
||||
$rows = 0
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
# last two hours from the Security log. Never writes, quits, pauses or resumes anything.
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$a = Join-Path $env:LOCALAPPDATA 'igneum\app'
|
||||
$l = Get-ChildItem (Join-Path $a 'logs') -Filter 'app-*.log' -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
||||
$l = Get-ChildItem (Join-Path $env:LOCALAPPDATA 'igneum\logs') -Filter 'app-*.log' -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
||||
if ($l) {
|
||||
Write-Output ('RESULT PROOF log=' + $l.FullName)
|
||||
Get-Content -LiteralPath $l.FullName | Where-Object { $_ -match 'power cap|Power Helper|elevat|UAC|runas|tune' } | Select-Object -Last 24 | ForEach-Object { Write-Output ('RESULT PROOF applog ' + $_) }
|
||||
Get-Content -LiteralPath $l.FullName | Where-Object { $_ -match 'power cap|Power Helper|elevat|UAC|runas|tune' } | Select-Object -Last 60 | ForEach-Object { Write-Output ('RESULT PROOF applog ' + $_) }
|
||||
}
|
||||
$h = Join-Path $a 'sweep\helper.log'
|
||||
if (Test-Path -LiteralPath $h) { Get-Content -LiteralPath $h | Select-Object -Last 15 | ForEach-Object { Write-Output ('RESULT PROOF helper ' + $_) } } else { Write-Output 'RESULT PROOF helper none' }
|
||||
|
|
|
|||
Loading…
Reference in a new issue