forked from 1b-agent/opencadstudio-upstream
fix(gpu): #1540 follow-up — only this run's report, only the device's words
- Process ids are reused: report_for_pid now takes the sentinel's arm time and ignores a report written before it, so an old crash of an unrelated run with the same pid no longer costs a backend. The test plants such a stale report. - is_device_failure drops "buffer" and "surface": drawing code and the modelling kernel panic with those words too. It keeps wgpu, out of memory and device lost, and adds wgpu's "validation error". Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
1ef5c40c3f
commit
60e23a43a6
2 files changed
+38
-9
No files matched your search
+24
-2
@@ -357,7 +357,12 @@ fn crash_report_blames_the_device(sentinel: &str) -> bool {
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
crate::sys::crash_log::report_for_pid(pid)
|
||||
let armed = sentinel
|
||||
.lines()
|
||||
.find_map(|line| line.strip_prefix("t="))
|
||||
.and_then(|value| value.trim().parse::<u64>().ok())
|
||||
.unwrap_or(0);
|
||||
crate::sys::crash_log::report_for_pid(pid, armed)
|
||||
.is_some_and(|report| crate::sys::crash_log::is_device_failure(&report))
|
||||
}
|
||||
|
||||
@@ -1129,7 +1134,14 @@ mod tests {
|
||||
|
||||
let reports = crate::sys::crash_log::directory().expect("a config directory");
|
||||
let _ = std::fs::create_dir_all(&reports);
|
||||
let report = reports.join(format!("crash-1-{}.log", std::process::id()));
|
||||
let now = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map(|d| d.as_secs())
|
||||
.unwrap_or(0);
|
||||
// A report older than the run, left by another process that once
|
||||
// had this id, blames nobody.
|
||||
let stale = reports.join(format!("crash-1-{}.log", std::process::id()));
|
||||
let report = reports.join(format!("crash-{}-{}.log", now + 1, std::process::id()));
|
||||
|
||||
arm_sentinel("dx12");
|
||||
mark_sentinel_survived();
|
||||
@@ -1138,6 +1150,16 @@ mod tests {
|
||||
crashed_backends().is_empty(),
|
||||
"with no crash report, a survived run blames nobody"
|
||||
);
|
||||
std::fs::write(
|
||||
&stale,
|
||||
crate::sys::crash_log::report_from("Out of Memory", "wgpu-29.0.4/src/lib.rs:1:1", 1),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(
|
||||
crashed_backends().is_empty(),
|
||||
"a report from before the run belongs to another process"
|
||||
);
|
||||
let _ = std::fs::remove_file(&stale);
|
||||
|
||||
// The run left a report, and it is the device's own failure.
|
||||
std::fs::write(
|
||||
|
||||
+14
-7
@@ -435,17 +435,22 @@ pub mod crash_log {
|
||||
/// a process id from somewhere else — the GPU crash sentinel does — can
|
||||
/// ask what killed that exact run instead of guessing from the newest
|
||||
/// file, which on a busy machine may belong to a different one.
|
||||
pub fn report_for_pid(pid: u32) -> Option<String> {
|
||||
///
|
||||
/// Process ids are reused, so only a report written at or after
|
||||
/// `not_before` (Unix seconds — when that run started) counts: an old
|
||||
/// report from an unrelated run that once had the same id does not.
|
||||
pub fn report_for_pid(pid: u32, not_before: u64) -> Option<String> {
|
||||
let directory = directory()?;
|
||||
let suffix = format!("-{pid}.log");
|
||||
let entry = std::fs::read_dir(directory)
|
||||
.ok()?
|
||||
.flatten()
|
||||
.find(|entry| {
|
||||
entry
|
||||
.file_name()
|
||||
.to_string_lossy()
|
||||
.ends_with(suffix.as_str())
|
||||
let name = entry.file_name().to_string_lossy().into_owned();
|
||||
name.strip_prefix("crash-")
|
||||
.and_then(|rest| rest.strip_suffix(suffix.as_str()))
|
||||
.and_then(|when| when.parse::<u64>().ok())
|
||||
.is_some_and(|when| when >= not_before)
|
||||
})?;
|
||||
std::fs::read_to_string(entry.path()).ok()
|
||||
}
|
||||
@@ -468,9 +473,11 @@ pub mod crash_log {
|
||||
}
|
||||
// The message wgpu panics with names the call, and the location names
|
||||
// wgpu itself; either alone is enough, since a stripped build can
|
||||
// leave the message terse.
|
||||
// leave the message terse. Plain words like "buffer" or "surface"
|
||||
// are not: drawing code and the modelling kernel panic with those
|
||||
// too, and that is no reason to give up a working backend.
|
||||
let haystack = format!("{panic_line} {at_line}").to_ascii_lowercase();
|
||||
["wgpu", "out of memory", "buffer", "surface", "device lost"]
|
||||
["wgpu", "out of memory", "device lost", "validation error"]
|
||||
.iter()
|
||||
.any(|needle| haystack.contains(needle))
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user