pub use burn_std::profile::{ProfileDuration, ProfileTicks, TimingMethod};
use burn_std::{ExecutionError, backtrace::BackTrace, profile::Instant};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct ProfileOptions {
flush: bool,
}
impl ProfileOptions {
pub fn flush(mut self) -> Self {
self.flush = true;
self
}
pub fn flushes(&self) -> bool {
self.flush
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct ProfileToken {
pub id: u64,
#[serde(default)]
pub opened_on: u64,
}
pub fn profile_system_time<B: crate::Backend, O: Send + 'static>(
device: &B::Device,
func: impl FnOnce() -> O + Send,
) -> Result<(O, ProfileDuration), crate::ExecutionError> {
B::sync(device)?;
let start = Instant::now();
let out = func();
B::sync(device)?;
Ok((out, ProfileDuration::new_system_time(start, Instant::now())))
}
pub fn profile_with_tokens<B: crate::Backend, O: Send + 'static>(
device: &B::Device,
options: ProfileOptions,
func: impl FnOnce() -> O + Send,
) -> Result<(O, ProfileDuration), ExecutionError> {
let opened = match B::profile_start(device) {
Ok(Some(token)) => token,
Ok(None) => return profile_system_time::<B, O>(device, func),
Err(err) => {
func();
return Err(err);
}
};
let mut window = OpenWindow::<B> {
device,
token: Some(opened),
};
let out = func();
let token = window
.token
.take()
.expect("the window is held from opening until here");
let duration = B::profile_end(device, token, options)?;
Ok((out, duration))
}
struct OpenWindow<'a, B: crate::Backend> {
device: &'a B::Device,
token: Option<ProfileToken>,
}
impl<B: crate::Backend> Drop for OpenWindow<'_, B> {
fn drop(&mut self) {
if let Some(token) = self.token.take() {
B::profile_abandon(self.device, token);
}
}
}
pub(crate) fn profile_unsupported() -> ExecutionError {
ExecutionError::Generic {
reason: alloc::string::String::from(
"profiling windows are not supported by this backend; use `profile`",
),
backtrace: BackTrace::capture(),
}
}