use std::sync::Arc;
use xlog_cuda::device_runtime::{
AllocTag, AsyncCudaResource, DeviceMemoryResource, InMemorySink, LogAction, LogResult,
LoggingResource, LoggingSink, StreamId, StreamPool, XlogDeviceRuntime,
};
use xlog_cuda::CudaDevice;
#[test]
fn logging_resource_composed_through_runtime_records_full_lifecycle() {
let Some(device) = CudaDevice::new(0).ok().map(Arc::new) else {
eprintln!("Skipping: CUDA runtime unavailable");
return;
};
let pool = Arc::new(StreamPool::with_defaults(Arc::clone(&device)));
let stream_id = match pool.acquire() {
Ok(id) => id,
Err(e) => {
eprintln!("Skipping: StreamPool::acquire failed: {}", e);
return;
}
};
assert_ne!(stream_id, StreamId::DEFAULT);
let sink: Arc<InMemorySink> = Arc::new(InMemorySink::new());
let inner: Box<dyn DeviceMemoryResource + Send + Sync> = Box::new(AsyncCudaResource::new(
Arc::clone(&device),
0,
Arc::clone(&pool),
));
let logging: Box<dyn DeviceMemoryResource + Send + Sync> = Box::new(LoggingResource::new(
inner,
sink.clone() as Arc<dyn LoggingSink>,
));
let runtime =
XlogDeviceRuntime::with_resource(Arc::clone(&device), 0, Arc::clone(&pool), logging);
let block_a = runtime
.allocate(2048, stream_id, AllocTag("logging-rt-A"))
.expect("alloc A");
let block_b = runtime
.allocate(1024, StreamId::DEFAULT, AllocTag("logging-rt-B"))
.expect("alloc B");
let a_ptr = block_a.ptr;
let a_gen = block_a.generation;
let b_ptr = block_b.ptr;
let b_gen = block_b.generation;
runtime.deallocate(block_a).expect("dealloc A");
runtime.deallocate(block_b).expect("dealloc B");
runtime.reap_pending().expect("reap");
assert_eq!(runtime.bytes_outstanding(), 0);
let recs = sink.snapshot();
assert_eq!(
recs.len(),
5,
"expected 5 records (2 alloc + 2 dealloc + 1 reap), got {}: {:?}",
recs.len(),
recs
);
let mut last = 0u64;
for rec in &recs {
assert!(rec.order_counter > last);
last = rec.order_counter;
}
assert_eq!(recs[0].action, LogAction::Allocate);
assert_eq!(recs[0].result, LogResult::Ok);
assert_eq!(recs[0].stream_id, Some(stream_id));
assert_eq!(recs[0].bytes, Some(2048));
assert_eq!(recs[0].ptr, Some(a_ptr));
assert_eq!(recs[0].generation, Some(a_gen));
assert_eq!(recs[0].tag, Some(AllocTag("logging-rt-A")));
assert_eq!(recs[1].action, LogAction::Allocate);
assert_eq!(recs[1].result, LogResult::Ok);
assert_eq!(recs[1].stream_id, Some(StreamId::DEFAULT));
assert_eq!(recs[1].bytes, Some(1024));
assert_eq!(recs[1].ptr, Some(b_ptr));
assert_eq!(recs[1].generation, Some(b_gen));
assert_eq!(recs[2].action, LogAction::Deallocate);
assert_eq!(recs[2].result, LogResult::Ok);
assert_eq!(recs[2].ptr, Some(a_ptr));
assert_eq!(recs[2].generation, Some(a_gen));
assert_eq!(recs[2].stream_id, Some(stream_id));
assert_eq!(recs[3].action, LogAction::Deallocate);
assert_eq!(recs[3].result, LogResult::Ok);
assert_eq!(recs[3].ptr, Some(b_ptr));
assert_eq!(recs[3].generation, Some(b_gen));
assert_eq!(recs[3].stream_id, Some(StreamId::DEFAULT));
assert_eq!(recs[4].action, LogAction::ReapPending);
assert_eq!(recs[4].result, LogResult::Ok);
assert!(recs[4].stream_id.is_none());
assert!(recs[4].ptr.is_none());
assert!(recs[4].bytes.is_none());
for rec in &recs {
assert_eq!(rec.device_ordinal, 0);
}
}