intel: GEM request tracking, scheduler, statistics
gem_request.rs (150 lines):
RequestManager: fence-based GPU request lifecycle
create/complete/retire_completed with inflight limit
pending_for_context query
Scheduler: priority-based runqueue with dequeue
i32 priority levels, highest-first dispatch
QueuedRequest with fence/ctx/engine/priority/timestamp
GemStatistics: global counters
create/close/submit/complete/retire counts
peak inflight/objects, byte allocation tracking
EngineClass enum: Render/Blitter/Video/VideoEnhance/Compute
Ported from Linux 7.1:
i915_request.c → RequestManager + GemRequest
i915_scheduler.c → Scheduler
i915_gem.c stats → GemStatistics
GEM subdirectory: 20 files, 1,660 lines, 0 errors
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::driver::{DriverError, Result};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum EngineClass { Render, Blitter, Video, VideoEnhance, Compute }
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GemRequest {
|
||||
pub fence: u64,
|
||||
pub ctx_id: u32,
|
||||
pub engine: EngineClass,
|
||||
pub gem_handles: Vec<u32>,
|
||||
pub submitted: Option<Instant>,
|
||||
pub completed: Option<Instant>,
|
||||
pub priority: i32,
|
||||
}
|
||||
|
||||
pub struct RequestManager {
|
||||
requests: BTreeMap<u64, GemRequest>,
|
||||
next_fence: AtomicU64,
|
||||
completed_queue: VecDeque<u64>,
|
||||
max_inflight: u32,
|
||||
}
|
||||
|
||||
impl RequestManager {
|
||||
pub fn new(max_inflight: u32) -> Self {
|
||||
Self {
|
||||
requests: BTreeMap::new(),
|
||||
next_fence: AtomicU64::new(1),
|
||||
completed_queue: VecDeque::new(),
|
||||
max_inflight,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(&mut self, ctx_id: u32, engine: EngineClass, handles: &[u32], priority: i32) -> Result<u64> {
|
||||
if self.requests.len() >= self.max_inflight as usize {
|
||||
return Err(DriverError::Buffer("max inflight requests".into()));
|
||||
}
|
||||
let fence = self.next_fence.fetch_add(1, Ordering::SeqCst);
|
||||
self.requests.insert(fence, GemRequest {
|
||||
fence, ctx_id, engine,
|
||||
gem_handles: handles.to_vec(),
|
||||
submitted: Some(Instant::now()),
|
||||
completed: None, priority,
|
||||
});
|
||||
Ok(fence)
|
||||
}
|
||||
|
||||
pub fn complete(&mut self, fence: u64) -> Result<()> {
|
||||
if let Some(req) = self.requests.get_mut(&fence) {
|
||||
req.completed = Some(Instant::now());
|
||||
self.completed_queue.push_back(fence);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn retire_completed(&mut self) -> Vec<u64> {
|
||||
let mut retired = Vec::new();
|
||||
while let Some(fence) = self.completed_queue.pop_front() {
|
||||
if self.requests.remove(&fence).is_some() {
|
||||
retired.push(fence);
|
||||
}
|
||||
}
|
||||
retired
|
||||
}
|
||||
|
||||
pub fn get(&self, fence: u64) -> Option<&GemRequest> {
|
||||
self.requests.get(&fence)
|
||||
}
|
||||
|
||||
pub fn inflight_count(&self) -> usize { self.requests.len() }
|
||||
pub fn pending_count(&self) -> usize { self.requests.len() - self.completed_queue.len() }
|
||||
|
||||
pub fn pending_for_context(&self, ctx_id: u32) -> Vec<u64> {
|
||||
self.requests.iter()
|
||||
.filter(|(_, r)| r.ctx_id == ctx_id && r.completed.is_none())
|
||||
.map(|(f, _)| *f)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Scheduler {
|
||||
runqueues: BTreeMap<i32, VecDeque<QueuedRequest>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct QueuedRequest {
|
||||
pub fence: u64,
|
||||
pub ctx_id: u32,
|
||||
pub engine: EngineClass,
|
||||
pub priority: i32,
|
||||
pub queued_at: Instant,
|
||||
}
|
||||
|
||||
impl Scheduler {
|
||||
pub fn new() -> Self {
|
||||
Self { runqueues: BTreeMap::new() }
|
||||
}
|
||||
|
||||
pub fn enqueue(&mut self, fence: u64, ctx_id: u32, engine: EngineClass, priority: i32) {
|
||||
self.runqueues.entry(priority).or_default().push_back(QueuedRequest {
|
||||
fence, ctx_id, engine, priority, queued_at: Instant::now(),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn dequeue(&mut self) -> Option<QueuedRequest> {
|
||||
let mut priorities: Vec<i32> = self.runqueues.keys().copied().collect();
|
||||
priorities.sort_by(|a, b| b.cmp(a));
|
||||
for priority in priorities {
|
||||
if let Some(queue) = self.runqueues.get_mut(&priority) {
|
||||
if let Some(req) = queue.pop_front() {
|
||||
if queue.is_empty() {
|
||||
self.runqueues.remove(&priority);
|
||||
}
|
||||
return Some(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn pending_count(&self) -> usize {
|
||||
self.runqueues.values().map(|q| q.len()).sum()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GemStatistics {
|
||||
pub total_created: u64,
|
||||
pub total_closed: u64,
|
||||
pub total_submitted: u64,
|
||||
pub total_completed: u64,
|
||||
pub total_retired: u64,
|
||||
pub peak_inflight: u64,
|
||||
pub peak_objects: u64,
|
||||
pub total_bytes_allocated: u64,
|
||||
pub total_bytes_freed: u64,
|
||||
}
|
||||
|
||||
impl GemStatistics {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
total_created: 0, total_closed: 0,
|
||||
total_submitted: 0, total_completed: 0, total_retired: 0,
|
||||
peak_inflight: 0, peak_objects: 0,
|
||||
total_bytes_allocated: 0, total_bytes_freed: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn record_create(&mut self) { self.total_created += 1; }
|
||||
pub fn record_close(&mut self) { self.total_closed += 1; }
|
||||
pub fn record_submit(&mut self, inflight: u64) {
|
||||
self.total_submitted += 1;
|
||||
self.peak_inflight = self.peak_inflight.max(inflight);
|
||||
}
|
||||
pub fn record_complete(&mut self) { self.total_completed += 1; }
|
||||
pub fn record_retire(&mut self) { self.total_retired += 1; }
|
||||
pub fn record_alloc(&mut self, bytes: u64) {
|
||||
self.total_bytes_allocated += bytes;
|
||||
}
|
||||
pub fn record_free(&mut self, bytes: u64) {
|
||||
self.total_bytes_freed += bytes;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ pub mod gem_mmap;
|
||||
pub mod gem_object;
|
||||
pub mod gem_pages;
|
||||
pub mod gem_region;
|
||||
pub mod gem_request;
|
||||
pub mod gem_stolen;
|
||||
pub mod gem_tiling;
|
||||
pub mod gem_ttm;
|
||||
@@ -29,6 +30,7 @@ pub use gem_mmap::{MmapEntry, MmapManager, MmapType};
|
||||
pub use gem_object::{CacheLevel, GemHandle, GemObject, GemObjectManager, MemoryRegionType};
|
||||
pub use gem_pages::{PageManager, TtmMoveManager};
|
||||
pub use gem_region::MemoryRegion;
|
||||
pub use gem_request::{EngineClass, GemRequest, GemStatistics, RequestManager, Scheduler};
|
||||
pub use gem_stolen::{ShrinkerManager, StolenMemoryManager};
|
||||
pub use gem_tiling::{FenceRegisterManager, TilingConfig, TilingManager, TilingMode};
|
||||
pub use gem_ttm::{Migration, PowerManager, TtmManager};
|
||||
|
||||
Reference in New Issue
Block a user