use burn_core::tensor::TensorReadError;
use burn_std::ExecutionError;
use crate::metric::{MetricName, store::Split};
#[derive(Debug)]
pub struct MetricError {
pub metric: MetricName,
pub split: Split,
pub source: TensorReadError,
}
impl core::fmt::Display for MetricError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match &self.split {
Split::Test(Some(name)) => write!(f, "test/{name}/{}: {}", self.metric, self.source),
split => write!(f, "{split}/{}: {}", self.metric, self.source),
}
}
}
impl core::error::Error for MetricError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
Some(&self.source)
}
}
#[derive(Debug)]
pub enum EventProcessorFailure {
Metric(MetricError),
Sync {
split: Split,
source: ExecutionError,
},
}
impl EventProcessorFailure {
pub fn is_device_poisoned(&self) -> bool {
match self {
Self::Metric(error) => {
matches!(&error.source, TensorReadError::Execution(err) if err.is_device_poisoned())
}
Self::Sync { source, .. } => source.is_device_poisoned(),
}
}
}
impl core::fmt::Display for EventProcessorFailure {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Metric(error) => write!(f, "{error}"),
Self::Sync {
split: Split::Test(Some(name)),
source,
} => write!(f, "test/{name}: the event could not be synced: {source}"),
Self::Sync { split, source } => {
write!(f, "{split}: the event could not be synced: {source}")
}
}
}
}
impl core::error::Error for EventProcessorFailure {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Metric(error) => Some(error),
Self::Sync { source, .. } => Some(source),
}
}
}
impl From<MetricError> for EventProcessorFailure {
fn from(error: MetricError) -> Self {
Self::Metric(error)
}
}
#[derive(Debug)]
pub struct EventProcessorError {
failures: Vec<EventProcessorFailure>,
}
impl EventProcessorError {
pub(crate) fn from_errors(errors: Vec<MetricError>) -> Result<(), Self> {
match errors.is_empty() {
true => Ok(()),
false => Err(Self {
failures: errors
.into_iter()
.map(EventProcessorFailure::Metric)
.collect(),
}),
}
}
pub(crate) fn sync(split: Split, source: ExecutionError) -> Self {
Self {
failures: vec![EventProcessorFailure::Sync { split, source }],
}
}
pub(crate) fn merge(&mut self, other: Self) {
self.failures.extend(other.failures);
}
pub fn failures(&self) -> &[EventProcessorFailure] {
&self.failures
}
pub fn into_failures(self) -> Vec<EventProcessorFailure> {
self.failures
}
pub fn is_device_poisoned(&self) -> bool {
self.failures
.iter()
.any(EventProcessorFailure::is_device_poisoned)
}
}
impl core::fmt::Display for EventProcessorError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.failures.as_slice() {
[failure] => write!(f, "Event processing failed: {failure}"),
failures => {
write!(f, "Event processing failed {} times:", failures.len())?;
for failure in failures {
write!(f, "\n {failure}")?;
}
Ok(())
}
}
}
}
impl core::error::Error for EventProcessorError {}