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
5 changes: 4 additions & 1 deletion drivers/gpu/drm/asahi/g17/runtime/render/submit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,11 @@ impl Backend {
self.shared.queue_events();
self.admission_open()?;
let started = super::super::now_ns();
// Backing frees only as other owners' pairs and pools are released, which takes far
// longer than one poll under concurrent clients: wait as long as a compute queue
// waits for capacity (and a render channel for its retirement).
let remaining = self
.wait_deadline(clock, super::super::WORK_RING_WAIT_NS)?
.wait_deadline(clock, crate::g17::preparation::QUEUE_WAIT_NS)?
.saturating_sub(started);
if remaining == 0 {
return Err(EBUSY);
Expand Down
14 changes: 8 additions & 6 deletions tools/asahi/g17-capacity-backoff-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def fixture(source):
parts = [const(source, 'CAPACITY_PAUSE_MIN_NS'), const(source, 'CAPACITY_PAUSE_MAX_NS'),
'#[derive(Default)]\n' + item(source, 'struct WaitClock'), item(source, 'impl WaitClock'),
'impl Backend {\n' + item(source, 'fn wait_render_capacity(') + '\n}']
code = '\n'.join(parts).replace('super::super::', 'rt::')
code = '\n'.join(parts).replace('super::super::', 'rt::').replace('crate::g17::preparation::', 'rt::')
return r'''
#![allow(dead_code)]
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
Expand All @@ -47,7 +47,7 @@ def fixture(source):
const STORM:usize=0; const QUIET:usize=1; const RELEASE:usize=2;
const RELEASE_AT:u64=5_000_000;
fn recovery_wait_ns()->u64 {10_000_000_000}
mod rt {pub fn now_ns()->u64 {crate::NOW.load(crate::Ordering::SeqCst)} pub const WORK_RING_WAIT_NS:u64=2_000_000_000;}
mod rt {pub fn now_ns()->u64 {crate::NOW.load(crate::Ordering::SeqCst)} pub const WORK_RING_WAIT_NS:u64=2_000_000_000; pub const QUEUE_WAIT_NS:u64=30_000_000_000;}
struct Delta(i64);
impl Delta {fn from_nanos(n:i64)->Self {Delta(n)}}
fn fsleep(d:Delta) {assert!(d.0>0); NOW.fetch_add(d.0 as u64,Ordering::SeqCst);}
Expand Down Expand Up @@ -78,7 +78,8 @@ def fixture(source):
NOW.store(0,Ordering::SeqCst); GEN.store(0,Ordering::SeqCst); ATTEMPTS.store(0,Ordering::SeqCst); MODE.store(mode,Ordering::SeqCst);
let b=Backend{shared:Shared{renders:Renders}};
let (mut observed,mut clock)=(None,WaitClock::default());
let deadline=rt::WORK_RING_WAIT_NS;
// The wait's own bound: QUEUE_WAIT_NS from its start, at most the recovery wait.
let deadline=rt::QUEUE_WAIT_NS.min(recovery_wait_ns());
let result=loop {
// One refused placement attempt of the caller's loop.
NOW.fetch_add(200,Ordering::SeqCst);
Expand All @@ -90,18 +91,19 @@ def fixture(source):
(result,rt::now_ns(),ATTEMPTS.load(Ordering::SeqCst))
}
fn main() {
let bound=rt::QUEUE_WAIT_NS.min(recovery_wait_ns());
let (r,t,n)=run(STORM);
assert_eq!(r,Err(EBUSY)); assert!(t>=2_000_000_000 && t<2_003_000_000,"storm ends at {t}"); assert!(n<=3_200,"storm attempts {n}");
assert_eq!(r,Err(EBUSY)); assert!(t>=bound && t<bound+3_000_000,"storm ends at {t}"); assert!(n<=16_000,"storm attempts {n}");
println!("storm: EBUSY at {:.3} s after {} attempts",t as f64/1e9,n);
let (r,t,n)=run(QUIET);
assert_eq!(r,Err(EBUSY)); assert!(t>=2_000_000_000 && t<2_011_000_000); assert!(n<=420,"quiet attempts {n}");
assert_eq!(r,Err(EBUSY)); assert!(t>=bound && t<bound+11_000_000); assert!(n<=2_100,"quiet attempts {n}");
println!("quiet: EBUSY at {:.3} s after {} attempts",t as f64/1e9,n);
let (r,t,n)=run(RELEASE);
assert_eq!(r,Ok(())); assert!(t<RELEASE_AT+CAPACITY_PAUSE_MAX_NS+10_000,"release seen at {t}");
println!("release: placed {:.3} ms after a 5 ms release wait, {} attempts",t as f64/1e6,n);
let mut c=WaitClock::default(); assert!(c.fast_retry()); assert!(!c.fast_retry());
assert!(matches!(b_fallback(),Err(FALLBACK)));
println!("PASS production render capacity wait: storm/quiet keep the 2 s bound with bounded attempts; a release is seen within one pause");
println!("PASS production render capacity wait: storm/quiet keep the wait's bound (QUEUE_WAIT_NS, at most the recovery wait) with bounded attempts; a release is seen within one pause");
}
fn b_fallback()->Result {let b=Backend{shared:Shared{renders:Renders}}; b.wait_render_capacity(&mut None,&mut WaitClock::default(),false)}
'''
Expand Down
Loading