use crate::{
error::CudaError,
memory::{
CudaBufferPoolReuseGuard, CudaDeviceBuffer, CudaDeviceBufferRange, CudaPooledDeviceBuffer,
},
};
#[doc(hidden)]
#[derive(Debug)]
pub struct CudaKernelOutput {
pub(crate) buffer: CudaDeviceBuffer,
pub(crate) execution: CudaExecutionStats,
}
#[doc(hidden)]
#[derive(Debug)]
pub struct CudaKernelBatchOutput {
pub(crate) outputs: Vec<CudaDeviceBuffer>,
pub(crate) execution: CudaExecutionStats,
}
#[doc(hidden)]
#[derive(Debug)]
pub struct CudaKernelContiguousBatchOutput {
pub(crate) output: CudaDeviceBuffer,
pub(crate) ranges: Vec<CudaDeviceBufferRange>,
pub(crate) execution: CudaExecutionStats,
}
#[doc(hidden)]
#[derive(Debug)]
pub struct CudaPooledKernelOutput {
pub(crate) buffer: CudaPooledDeviceBuffer,
pub(crate) execution: CudaExecutionStats,
}
#[doc(hidden)]
#[derive(Debug)]
#[must_use = "queued CUDA work must be finished or retained until Drop synchronizes it"]
pub struct CudaQueuedExecution {
pub(crate) resources: Vec<CudaPooledDeviceBuffer>,
pub(crate) execution: CudaExecutionStats,
pub(crate) pool_reuse_guard: Option<CudaBufferPoolReuseGuard>,
}
impl CudaQueuedExecution {
pub fn execution(&self) -> CudaExecutionStats {
self.execution
}
pub fn resource_count(&self) -> usize {
self.resources.len()
}
pub fn finish(mut self) -> Result<CudaExecutionStats, CudaError> {
let completion_result = self
.pool_reuse_guard
.take()
.map_or(Ok(()), CudaBufferPoolReuseGuard::synchronize_and_release);
self.resources.clear();
completion_result?;
Ok(self.execution)
}
#[doc(hidden)]
pub unsafe fn release_pool_reuse_after_completion(&mut self) -> Result<(), CudaError> {
self.resources.clear();
if let Some(guard) = self.pool_reuse_guard.take() {
guard.release()?;
}
Ok(())
}
}
impl Drop for CudaQueuedExecution {
fn drop(&mut self) {
let Some(guard) = self.pool_reuse_guard.take() else {
return;
};
let outcome = guard.synchronize_pool_context();
self.resources.clear();
if outcome.completion_established() {
let _ = guard.release();
} else {
guard.abandon();
}
}
}
impl CudaKernelOutput {
pub fn buffer(&self) -> &CudaDeviceBuffer {
&self.buffer
}
pub fn execution(&self) -> CudaExecutionStats {
self.execution
}
pub fn into_parts(self) -> (CudaDeviceBuffer, CudaExecutionStats) {
(self.buffer, self.execution)
}
}
impl CudaKernelBatchOutput {
pub fn outputs(&self) -> &[CudaDeviceBuffer] {
&self.outputs
}
pub fn execution(&self) -> CudaExecutionStats {
self.execution
}
pub fn into_parts(self) -> (Vec<CudaDeviceBuffer>, CudaExecutionStats) {
(self.outputs, self.execution)
}
}
impl CudaKernelContiguousBatchOutput {
pub fn output(&self) -> &CudaDeviceBuffer {
&self.output
}
pub fn ranges(&self) -> &[CudaDeviceBufferRange] {
&self.ranges
}
pub fn execution(&self) -> CudaExecutionStats {
self.execution
}
pub fn into_parts(
self,
) -> (
CudaDeviceBuffer,
Vec<CudaDeviceBufferRange>,
CudaExecutionStats,
) {
(self.output, self.ranges, self.execution)
}
}
impl CudaPooledKernelOutput {
pub fn buffer(&self) -> Option<&CudaDeviceBuffer> {
self.buffer.as_device_buffer()
}
pub fn execution(&self) -> CudaExecutionStats {
self.execution
}
pub fn into_parts(self) -> (CudaPooledDeviceBuffer, CudaExecutionStats) {
(self.buffer, self.execution)
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct CudaExecutionStats {
pub(crate) kernel_dispatches: usize,
pub(crate) copy_kernel_dispatches: usize,
pub(crate) decode_kernel_dispatches: usize,
pub(crate) hardware_decode: bool,
}
impl CudaExecutionStats {
pub fn kernel_dispatches(self) -> usize {
self.kernel_dispatches
}
pub fn copy_kernel_dispatches(self) -> usize {
self.copy_kernel_dispatches
}
pub fn decode_kernel_dispatches(self) -> usize {
self.decode_kernel_dispatches
}
pub fn used_hardware_decode(self) -> bool {
self.hardware_decode
}
}