use std::borrow::Cow;
use query_planning::error::{MemoryFailure, MemoryUsage, QueryError, QueryErrorCode, redact_uri_tokens};
pub fn cudf_query_error(operation: &'static str, message: impl Into<String>, source: cudf::Error) -> QueryError {
let error = cudf_query_error_without_source(operation, message, &source);
error.with_source(source)
}
pub fn cudf_query_error_without_source(
operation: &'static str,
message: impl Into<String>,
source: &cudf::Error,
) -> QueryError {
cudf_query_error_with_code(query_error_code_for_cudf_error(source), operation, message, source)
}
pub fn cudf_unsupported_type_error(
operation: &'static str,
message: impl Into<String>,
source: cudf::Error,
) -> QueryError {
let mut error = cudf_query_error_with_code(QueryErrorCode::UnsupportedType, operation, message, &source);
if let Some(reason) = source.detail_value("reason") {
error = error.with_fact("cudf_reason", reason);
}
error.with_source(source)
}
fn cudf_query_error_with_code(
code: QueryErrorCode,
operation: &'static str,
message: impl Into<String>,
source: &cudf::Error,
) -> QueryError {
let mut error = QueryError::new(code, operation, message)
.with_fact("cudf_code", source.code())
.with_fact("cudf_kind", source.kind())
.with_fact("cudf_status", source.status())
.with_fact("cudf_operation", source.operation());
error = with_cudf_ffi_detail_facts(error, source);
if let Some(detail) = source.budget_exhaustion() {
error = error.with_memory_failure(memory_failure(detail));
}
match cudf_message_fact(source) {
Some(cudf_message) => error.with_fact("cudf_message", cudf_message),
None => error,
}
}
pub fn query_error_code_for_cudf_error(error: &cudf::Error) -> QueryErrorCode {
match cudf::allocation_attribution(error) {
cudf::CudfAllocationAttribution::ConfirmedQueryLimit => {
return QueryErrorCode::QueryMemoryLimitExceeded;
},
cudf::CudfAllocationAttribution::ConfirmedPhysical => return QueryErrorCode::DeviceOutOfMemory,
cudf::CudfAllocationAttribution::UnattributedAllocationFailure => {
return QueryErrorCode::DeviceAllocationFailed;
},
cudf::CudfAllocationAttribution::NonAllocationFailure => {},
}
match cudf::classify_cudf_error(error) {
cudf::CudfErrorClassification::SizeOverflow => QueryErrorCode::SizeOverflow,
cudf::CudfErrorClassification::HostMaterializationLimitExceeded => {
QueryErrorCode::HostMaterializationLimitExceeded
},
cudf::CudfErrorClassification::ResourceExhausted => QueryErrorCode::DeviceAllocationFailed,
cudf::CudfErrorClassification::TemporaryFailure => QueryErrorCode::CudfTemporaryFailure,
cudf::CudfErrorClassification::PersistentFailure => QueryErrorCode::DeviceFault,
cudf::CudfErrorClassification::InvalidInput => QueryErrorCode::CudfInvalidInput,
cudf::CudfErrorClassification::Unsupported => QueryErrorCode::CudfUnsupported,
cudf::CudfErrorClassification::DependencyFailure => QueryErrorCode::CudfDependencyFailure,
cudf::CudfErrorClassification::InvariantViolation => QueryErrorCode::InternalInvariantViolation,
}
}
pub fn memory_failure(detail: &cudf::BudgetExhaustionDetail) -> MemoryFailure {
MemoryFailure {
boundary: Cow::Owned(detail.boundary().to_owned()),
operation: Cow::Borrowed(detail.operation()),
usage: detail.usage().map(|usage| MemoryUsage {
limit_bytes: usage.allocation_limit_bytes,
peak_bytes: usage.peak_bytes,
peak_aligned_bytes: usage.peak_aligned_bytes,
current_bytes: usage.current_bytes,
current_aligned_bytes: usage.current_aligned_bytes,
failed_allocation_count: usage.failed_allocation_count,
largest_failed_allocation_bytes: usage.largest_failed_allocation_bytes,
}),
}
}
pub fn cudf_message_fact(source: &cudf::Error) -> Option<String> {
let message = source.message().trim();
if message.is_empty() {
return None;
}
Some(redact_uri_tokens(message))
}
fn with_cudf_ffi_detail_facts(mut error: QueryError, source: &cudf::Error) -> QueryError {
let Some(detail) = source.ffi_detail() else {
return error;
};
error = error
.with_fact("failure_source", detail.failure_source)
.with_fact("requested_allocation_bytes", detail.requested_bytes)
.with_fact("allocation_alignment", detail.alignment)
.with_fact("cuda_status", detail.cuda_error);
if detail.domain_id != 0 {
error = error.with_fact("allocation_domain_id", detail.domain_id);
}
if detail.member_id != 0 {
error = error.with_fact("allocation_member_id", detail.member_id);
}
if detail.generation != 0 {
error = error.with_fact("allocation_domain_generation", detail.generation);
}
error
}
#[cfg(test)]
mod tests;