use anyhow::Result;
#[cfg(feature = "gpu-tracing")]
use crate::otlp_exporter::GpuKernel;
use crate::otlp_exporter::OtlpExporter;
#[derive(Debug, Clone)]
pub struct GpuTracerConfig {
pub threshold_us: u64,
pub trace_all: bool,
}
impl Default for GpuTracerConfig {
fn default() -> Self {
GpuTracerConfig {
threshold_us: 100, trace_all: false, }
}
}
#[cfg(feature = "gpu-tracing")]
pub struct GpuProfilerWrapper {
profiler: wgpu_profiler::GpuProfiler,
otlp_exporter: Option<std::sync::Arc<OtlpExporter>>,
config: GpuTracerConfig,
}
#[cfg(feature = "gpu-tracing")]
impl GpuProfilerWrapper {
pub fn new(
otlp_exporter: Option<std::sync::Arc<OtlpExporter>>,
config: GpuTracerConfig,
) -> Result<Self> {
let settings = wgpu_profiler::GpuProfilerSettings::default();
let profiler = wgpu_profiler::GpuProfiler::new(settings)?;
Ok(GpuProfilerWrapper { profiler, otlp_exporter, config })
}
pub fn profiler_mut(&mut self) -> &mut wgpu_profiler::GpuProfiler {
&mut self.profiler
}
pub fn export_frame(&mut self, timestamp_period: f32) {
if let Some(frame_data) = self.profiler.process_finished_frame(timestamp_period) {
for scope in &frame_data {
let duration_us = if let Some(ref time_range) = scope.time {
((time_range.end - time_range.start) * 1_000_000.0) as u64
} else {
continue;
};
if self.config.trace_all || duration_us >= self.config.threshold_us {
if let Some(ref exporter) = self.otlp_exporter {
let kernel = GpuKernel {
kernel: scope.label.clone(),
duration_us,
backend: "wgpu",
workgroup_size: None, elements: None, is_slow: duration_us > self.config.threshold_us,
};
exporter.record_gpu_kernel(kernel);
}
}
}
}
}
}
#[cfg(not(feature = "gpu-tracing"))]
pub struct GpuProfilerWrapper;
#[cfg(not(feature = "gpu-tracing"))]
impl GpuProfilerWrapper {
pub fn new(
_otlp_exporter: Option<std::sync::Arc<OtlpExporter>>,
_config: GpuTracerConfig,
) -> Result<Self> {
anyhow::bail!("GPU tracing support not compiled in. Enable the 'gpu-tracing' feature.");
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gpu_tracer_config_defaults() {
let config = GpuTracerConfig::default();
assert_eq!(config.threshold_us, 100); assert!(!config.trace_all); }
#[test]
fn test_gpu_tracer_config_custom() {
let config = GpuTracerConfig {
threshold_us: 1000, trace_all: true, };
assert_eq!(config.threshold_us, 1000);
assert!(config.trace_all);
}
}