use std::{fmt::Write, sync::Arc};
use datafusion::prelude::SessionConfig;
use super::{
CandidateOutcomeKind, ExecutionPlan, FinalPlanDisposition, MetricsSet, NATIVE_TPCDS_PARITY_TSV_COLUMNS,
NATIVE_TPCDS_PARITY_TSV_HEADER, NativeDataFusionExecutionMetrics, NativeDataFusionRuntimeOutcome,
NativePlanningDiagnostics, NativePlanningFailure, ParityCompareOptions, ParityRowOrdering, RecordBatch, SchemaRef,
StatisticalAggregateExecutionMode, TsvRow, WorkloadDatasetMetadata, compare_record_batches_with_options,
fingerprint_batches, post_native_plan_coverage, sql_row_ordering, stable_tsv_field, unsupported_category,
write_workload_dataset_metadata,
};
use crate::report::CandidateOutcome;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParityStatus {
Matched,
Mismatched,
CpuFailed,
NativeRejected,
NativeFailed,
NotCompared,
}
impl ParityStatus {
pub const fn as_str(self) -> &'static str {
match self {
Self::Matched => "matched",
Self::Mismatched => "mismatched",
Self::CpuFailed => "cpu_failed",
Self::NativeRejected => "native_rejected",
Self::NativeFailed => "native_failed",
Self::NotCompared => "not_compared",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParityComparisonMode {
OrderedExact,
UnorderedExact,
OrderedFloatTolerant,
UnorderedFloatTolerant,
NotApplicable,
}
impl ParityComparisonMode {
pub const fn as_str(self) -> &'static str {
match self {
Self::OrderedExact => "ordered_exact",
Self::UnorderedExact => "unordered_exact",
Self::OrderedFloatTolerant => "ordered_float_tolerant",
Self::UnorderedFloatTolerant => "unordered_float_tolerant",
Self::NotApplicable => "not_applicable",
}
}
pub const fn select(ordered: bool, float_tolerant: bool) -> Self {
match (ordered, float_tolerant) {
(true, false) => Self::OrderedExact,
(false, false) => Self::UnorderedExact,
(true, true) => Self::OrderedFloatTolerant,
(false, true) => Self::UnorderedFloatTolerant,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ParityFloatTolerance {
pub absolute: f64,
pub relative: f64,
}
impl ParityFloatTolerance {
pub const fn exact() -> Self {
Self { absolute: 0.0, relative: 0.0 }
}
pub const fn new(absolute: f64, relative: f64) -> Self {
Self { absolute, relative }
}
pub fn is_enabled(self) -> bool {
self.absolute > 0.0 || self.relative > 0.0
}
}
impl Default for ParityFloatTolerance {
fn default() -> Self {
Self::exact()
}
}
#[derive(Debug, Clone)]
pub struct NativeTpcdsParityRow {
pub query_id: String,
pub cpu_planning_status: ParityStageStatus,
pub cpu_runtime_status: ParityStageStatus,
pub native_planning_outcome: Option<CandidateOutcomeKind>,
pub native_reason_code: Option<String>,
pub native_unsupported_category: Option<String>,
pub final_disposition: Option<FinalPlanDisposition>,
pub native_plan_fragment_count: Option<usize>,
pub host_datafusion_boundary_count: Option<usize>,
pub native_runtime_started: bool,
pub native_runtime_outcome: NativeDataFusionRuntimeOutcome,
pub parity_status: ParityStatus,
pub parity_detail: Option<String>,
pub cpu_output_rows: Option<usize>,
pub native_output_rows: Option<usize>,
pub cpu_output_batches: Option<usize>,
pub native_output_batches: Option<usize>,
pub cpu_output_fingerprint: Option<String>,
pub native_output_fingerprint: Option<String>,
pub comparison_mode: ParityComparisonMode,
pub duckdb_output: NativeTpcdsParityExternalOutputSummary,
pub native_retry_count: Option<usize>,
pub native_runtime_failure: Option<String>,
}
impl TsvRow for NativeTpcdsParityRow {
const COLUMNS: &'static [&'static str] = NATIVE_TPCDS_PARITY_TSV_COLUMNS;
fn fields(&self) -> Vec<String> {
vec![
self.query_id.clone(),
self.cpu_planning_status.as_str().to_string(),
self.cpu_runtime_status.as_str().to_string(),
self.native_planning_outcome.map_or_else(|| "none".to_string(), |outcome| outcome.as_str().to_string()),
self.native_reason_code.as_deref().unwrap_or("none").to_string(),
self.native_unsupported_category.as_deref().unwrap_or("none").to_string(),
self.final_disposition.map_or_else(|| "none".to_string(), |d| d.as_str().to_string()),
self.native_plan_fragment_count.map_or_else(|| "none".to_string(), |c| c.to_string()),
self.host_datafusion_boundary_count.map_or_else(|| "none".to_string(), |c| c.to_string()),
self.native_runtime_started.to_string(),
self.native_runtime_outcome.as_str().to_string(),
self.parity_status.as_str().to_string(),
self.parity_detail.as_deref().map(stable_tsv_field).unwrap_or_else(|| "none".to_string()),
format_optional_usize(self.cpu_output_rows),
format_optional_usize(self.native_output_rows),
format_optional_usize(self.cpu_output_batches),
format_optional_usize(self.native_output_batches),
self.cpu_output_fingerprint.as_deref().unwrap_or("none").to_string(),
self.native_output_fingerprint.as_deref().unwrap_or("none").to_string(),
self.comparison_mode.as_str().to_string(),
self.duckdb_output.status.as_str().to_string(),
self.duckdb_output.cpu_parity_status.as_str().to_string(),
self.duckdb_output.cpu_parity_detail.as_deref().map(stable_tsv_field).unwrap_or_else(|| "none".to_string()),
format_optional_usize(self.duckdb_output.output_rows),
format_optional_usize(self.duckdb_output.output_batches),
self.duckdb_output.output_fingerprint.as_deref().unwrap_or("none").to_string(),
format_optional_usize(self.native_retry_count),
self.native_runtime_failure.as_deref().map(stable_tsv_field).unwrap_or_else(|| "none".to_string()),
]
}
}
impl NativeTpcdsParityRow {
pub fn from_workload_item(item: NativeTpcdsParityWorkloadItem, float_tolerance: ParityFloatTolerance) -> Self {
parity_row_for_item(item, float_tolerance)
}
pub fn to_tsv_line(&self) -> String {
<Self as TsvRow>::to_tsv_line(self)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParityStageStatus {
Succeeded,
Failed,
NotStarted,
}
impl ParityStageStatus {
pub const fn as_str(self) -> &'static str {
match self {
Self::Succeeded => "succeeded",
Self::Failed => "failed",
Self::NotStarted => "not_started",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NativeTpcdsParityExternalOutputStatus {
NotConfigured,
Succeeded,
Failed,
}
impl NativeTpcdsParityExternalOutputStatus {
pub const fn as_str(self) -> &'static str {
match self {
Self::NotConfigured => "not_configured",
Self::Succeeded => "succeeded",
Self::Failed => "failed",
}
}
}
#[derive(Debug, Clone)]
pub struct NativeTpcdsParityExternalOutputSummary {
pub status: NativeTpcdsParityExternalOutputStatus,
pub cpu_parity_status: ParityStatus,
pub cpu_parity_detail: Option<String>,
pub output_rows: Option<usize>,
pub output_batches: Option<usize>,
pub output_fingerprint: Option<String>,
}
impl NativeTpcdsParityExternalOutputSummary {
pub fn not_configured() -> Self {
Self {
status: NativeTpcdsParityExternalOutputStatus::NotConfigured,
cpu_parity_status: ParityStatus::NotCompared,
cpu_parity_detail: None,
output_rows: None,
output_batches: None,
output_fingerprint: None,
}
}
}
#[derive(Debug, Clone)]
pub struct NativeTpcdsParityReport {
pub rows: Vec<NativeTpcdsParityRow>,
pub workload_dataset: Option<WorkloadDatasetMetadata>,
pub float_tolerance: ParityFloatTolerance,
pub statistical_aggregate_execution_mode: Option<StatisticalAggregateExecutionMode>,
pub cpu_target_partitions: Option<usize>,
pub cpu_batch_size: Option<usize>,
}
impl NativeTpcdsParityReport {
pub fn from_rows(rows: Vec<NativeTpcdsParityRow>, float_tolerance: ParityFloatTolerance) -> Self {
Self {
rows,
workload_dataset: None,
float_tolerance,
statistical_aggregate_execution_mode: None,
cpu_target_partitions: None,
cpu_batch_size: None,
}
}
pub fn collect(
items: impl IntoIterator<Item = NativeTpcdsParityWorkloadItem>,
float_tolerance: ParityFloatTolerance,
) -> Self {
let rows =
items.into_iter().map(|item| NativeTpcdsParityRow::from_workload_item(item, float_tolerance)).collect();
Self {
rows,
workload_dataset: None,
float_tolerance,
statistical_aggregate_execution_mode: None,
cpu_target_partitions: None,
cpu_batch_size: None,
}
}
pub fn with_workload_dataset_metadata(mut self, metadata: WorkloadDatasetMetadata) -> Self {
self.workload_dataset = Some(metadata);
self
}
pub fn with_statistical_aggregate_execution_mode(mut self, mode: StatisticalAggregateExecutionMode) -> Self {
self.statistical_aggregate_execution_mode = Some(mode);
self
}
pub fn with_cpu_session_config(mut self, config: &SessionConfig) -> Self {
self.cpu_target_partitions = Some(config.target_partitions());
self.cpu_batch_size = Some(config.batch_size());
self
}
pub fn matched_count(&self) -> usize {
self.rows.iter().filter(|row| row.parity_status == ParityStatus::Matched).count()
}
pub fn mismatched_count(&self) -> usize {
self.rows.iter().filter(|row| row.parity_status == ParityStatus::Mismatched).count()
}
pub fn to_tsv(&self) -> String {
let mut output = String::new();
let _ = writeln!(output, "# parity_float_tolerance_absolute={}", self.float_tolerance.absolute);
let _ = writeln!(output, "# parity_float_tolerance_relative={}", self.float_tolerance.relative);
if let Some(mode) = self.statistical_aggregate_execution_mode {
let _ = writeln!(output, "# statistical_aggregate_execution_mode={}", mode.as_str());
let _ =
writeln!(output, "# statistical_aggregate_tolerance_contract={}", mode.tolerance_contract().as_str());
}
if let Some(target_partitions) = self.cpu_target_partitions {
let _ = writeln!(output, "# cpu_target_partitions={target_partitions}");
}
if let Some(batch_size) = self.cpu_batch_size {
let _ = writeln!(output, "# cpu_batch_size={batch_size}");
}
write_workload_dataset_metadata(&mut output, self.workload_dataset.as_ref());
debug_assert_eq!(NativeTpcdsParityRow::COLUMNS.join("\t"), NATIVE_TPCDS_PARITY_TSV_HEADER);
output.push_str(NATIVE_TPCDS_PARITY_TSV_HEADER);
output.push('\n');
for row in &self.rows {
let _ = writeln!(output, "{}", row.to_tsv_line());
}
output
}
}
fn format_optional_usize(value: Option<usize>) -> String {
value.map_or_else(|| "none".to_string(), |value| value.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tpcds_parity_row_contract_header_matches_public_constant() {
assert_eq!(NativeTpcdsParityRow::COLUMNS.join("\t"), NATIVE_TPCDS_PARITY_TSV_HEADER);
}
#[test]
fn tpcds_parity_row_fields_match_columns() {
let row = NativeTpcdsParityRow {
query_id: "q01".to_string(),
cpu_planning_status: ParityStageStatus::Succeeded,
cpu_runtime_status: ParityStageStatus::Succeeded,
native_planning_outcome: Some(CandidateOutcomeKind::NotSupported),
native_reason_code: Some("unsupported_operator".to_string()),
native_unsupported_category: Some("operator_join".to_string()),
final_disposition: Some(FinalPlanDisposition::DataFusion),
native_plan_fragment_count: Some(0),
host_datafusion_boundary_count: Some(0),
native_runtime_started: false,
native_runtime_outcome: NativeDataFusionRuntimeOutcome::NotStarted,
parity_status: ParityStatus::NativeRejected,
parity_detail: None,
cpu_output_rows: Some(0),
native_output_rows: None,
cpu_output_batches: Some(0),
native_output_batches: None,
cpu_output_fingerprint: None,
native_output_fingerprint: None,
comparison_mode: ParityComparisonMode::NotApplicable,
duckdb_output: NativeTpcdsParityExternalOutputSummary::not_configured(),
native_retry_count: None,
native_runtime_failure: None,
};
assert_eq!(row.fields().len(), NativeTpcdsParityRow::COLUMNS.len());
assert_eq!(
row.to_tsv_line(),
"q01\tsucceeded\tsucceeded\tnot_supported\tunsupported_operator\toperator_join\tdatafusion\t0\t0\tfalse\tnot_started\tnative_rejected\tnone\t0\tnone\t0\tnone\tnone\tnone\tnot_applicable\tnot_configured\tnot_compared\tnone\tnone\tnone\tnone\tnone\tnone"
);
}
}
#[derive(Debug, Clone)]
pub struct NativeTpcdsParityWorkloadItem {
pub query_id: String,
pub sql: String,
pub cpu_outcome: NativeTpcdsParityCpuOutcome,
pub native_planning: NativeTpcdsParityNativePlanningOutcome,
pub native_runtime: NativeTpcdsParityNativeRuntimeOutcome,
pub duckdb_output: NativeTpcdsParityExternalOutput,
}
#[derive(Debug, Clone)]
pub enum NativeTpcdsParityCpuOutcome {
Succeeded {
schema: SchemaRef,
batches: Vec<RecordBatch>,
},
PlanningFailed(NativePlanningFailure),
ExecutionFailed {
message: String,
},
}
#[derive(Debug, Clone)]
pub enum NativeTpcdsParityNativePlanningOutcome {
Planned {
accepted: bool,
planned_plan: Arc<dyn ExecutionPlan>,
diagnostics: Box<NativePlanningDiagnostics>,
},
PlanningFailed(NativePlanningFailure),
}
#[derive(Debug, Clone)]
pub enum NativeTpcdsParityNativeRuntimeOutcome {
NotStarted,
Succeeded {
schema: SchemaRef,
batches: Vec<RecordBatch>,
metrics: MetricsSet,
},
Failed {
message: String,
},
}
#[derive(Debug, Clone)]
pub enum NativeTpcdsParityExternalOutput {
NotConfigured,
Succeeded {
schema: SchemaRef,
batches: Vec<RecordBatch>,
},
Failed {
message: String,
},
}
fn parity_row_for_item(
item: NativeTpcdsParityWorkloadItem,
float_tolerance: ParityFloatTolerance,
) -> NativeTpcdsParityRow {
let (cpu_planning_status, cpu_runtime_status, cpu_batches, cpu_schema, cpu_runtime_failure) = match item.cpu_outcome
{
NativeTpcdsParityCpuOutcome::Succeeded { schema, batches } => {
(ParityStageStatus::Succeeded, ParityStageStatus::Succeeded, Some(batches), Some(schema), None)
},
NativeTpcdsParityCpuOutcome::PlanningFailed(failure) => {
(ParityStageStatus::Failed, ParityStageStatus::NotStarted, None, None, Some(failure.message))
},
NativeTpcdsParityCpuOutcome::ExecutionFailed { message } => {
(ParityStageStatus::Succeeded, ParityStageStatus::Failed, None, None, Some(message))
},
};
let ordering = sql_row_ordering(&item.sql, cpu_schema.as_deref());
let (
native_planning_outcome,
native_reason_code,
native_unsupported_category,
final_disposition,
native_plan_fragment_count,
host_datafusion_boundary_count,
native_planning_failure_message,
) = match &item.native_planning {
NativeTpcdsParityNativePlanningOutcome::Planned { accepted, planned_plan, diagnostics } => {
let (outcome, reason_code, unsupported_category) = planning_outcome_diagnostics(diagnostics, *accepted);
let coverage = post_native_plan_coverage(planned_plan.as_ref());
(
outcome,
reason_code,
unsupported_category,
Some(coverage.disposition()),
Some(coverage.native_fragment_count()),
Some(coverage.datafusion_boundary_count()),
None,
)
},
NativeTpcdsParityNativePlanningOutcome::PlanningFailed(failure) => (
None,
Some(failure.reason_code.clone()),
Some("planning".to_string()),
None,
None,
None,
Some(failure.message.clone()),
),
};
let (native_runtime_started, native_runtime_outcome, native_batches, native_schema, native_metrics, native_failure) =
match item.native_runtime {
NativeTpcdsParityNativeRuntimeOutcome::NotStarted => {
(false, NativeDataFusionRuntimeOutcome::NotStarted, None, None, None, native_planning_failure_message)
},
NativeTpcdsParityNativeRuntimeOutcome::Succeeded { schema, batches, metrics } => {
(true, NativeDataFusionRuntimeOutcome::Succeeded, Some(batches), Some(schema), Some(metrics), None)
},
NativeTpcdsParityNativeRuntimeOutcome::Failed { message } => {
(true, NativeDataFusionRuntimeOutcome::Failed, None, None, None, Some(message))
},
};
let native_metrics_summary = native_metrics.as_ref().map(NativeDataFusionExecutionMetrics::from_metrics);
let (parity_status, comparison_mode, parity_detail, cpu_fingerprint, native_fingerprint) =
derive_parity_outcome(ParityInputs {
cpu_planning_status,
cpu_runtime_status,
native_planning_outcome,
native_runtime_started,
native_runtime_outcome,
cpu_schema: cpu_schema.as_ref(),
cpu_batches: cpu_batches.as_deref(),
native_schema: native_schema.as_ref(),
native_batches: native_batches.as_deref(),
ordering: &ordering,
float_tolerance,
});
let duckdb_output = summarize_external_output(
item.duckdb_output,
cpu_schema.as_ref(),
cpu_batches.as_deref(),
&ordering,
float_tolerance,
);
NativeTpcdsParityRow {
query_id: item.query_id,
cpu_planning_status,
cpu_runtime_status,
native_planning_outcome,
native_reason_code,
native_unsupported_category,
final_disposition,
native_plan_fragment_count,
host_datafusion_boundary_count,
native_runtime_started,
native_runtime_outcome,
parity_status,
parity_detail,
cpu_output_rows: cpu_batches.as_ref().map(|batches| total_rows(batches)),
native_output_rows: native_batches.as_ref().map(|batches| total_rows(batches)),
cpu_output_batches: cpu_batches.as_ref().map(Vec::len),
native_output_batches: native_batches.as_ref().map(Vec::len),
cpu_output_fingerprint: cpu_fingerprint,
native_output_fingerprint: native_fingerprint,
comparison_mode,
duckdb_output,
native_retry_count: native_metrics_summary.as_ref().map(|m| m.retry_count),
native_runtime_failure: cpu_runtime_failure.or(native_failure),
}
}
fn summarize_external_output(
output: NativeTpcdsParityExternalOutput,
cpu_schema: Option<&SchemaRef>,
cpu_batches: Option<&[RecordBatch]>,
ordering: &ParityRowOrdering,
float_tolerance: ParityFloatTolerance,
) -> NativeTpcdsParityExternalOutputSummary {
match output {
NativeTpcdsParityExternalOutput::NotConfigured => NativeTpcdsParityExternalOutputSummary::not_configured(),
NativeTpcdsParityExternalOutput::Failed { message } => NativeTpcdsParityExternalOutputSummary {
status: NativeTpcdsParityExternalOutputStatus::Failed,
cpu_parity_status: ParityStatus::NotCompared,
cpu_parity_detail: Some(message),
output_rows: None,
output_batches: None,
output_fingerprint: None,
},
NativeTpcdsParityExternalOutput::Succeeded { schema, batches } => {
let output_rows = Some(total_rows(&batches));
let output_batches = Some(batches.len());
let output_fingerprint = Some(fingerprint_batches(schema.as_ref(), &batches));
let Some(cpu_schema) = cpu_schema else {
return NativeTpcdsParityExternalOutputSummary {
status: NativeTpcdsParityExternalOutputStatus::Succeeded,
cpu_parity_status: ParityStatus::NotCompared,
cpu_parity_detail: Some("missing CPU schema".to_string()),
output_rows,
output_batches,
output_fingerprint,
};
};
let Some(cpu_batches) = cpu_batches else {
return NativeTpcdsParityExternalOutputSummary {
status: NativeTpcdsParityExternalOutputStatus::Succeeded,
cpu_parity_status: ParityStatus::NotCompared,
cpu_parity_detail: Some("missing CPU batches".to_string()),
output_rows,
output_batches,
output_fingerprint,
};
};
let comparison = compare_record_batches_with_options(
cpu_schema.as_ref(),
cpu_batches,
schema.as_ref(),
&batches,
ordering,
float_tolerance,
ParityCompareOptions::cross_engine_oracle(),
);
NativeTpcdsParityExternalOutputSummary {
status: NativeTpcdsParityExternalOutputStatus::Succeeded,
cpu_parity_status: comparison.status,
cpu_parity_detail: comparison.detail,
output_rows,
output_batches,
output_fingerprint: Some(comparison.native_fingerprint),
}
},
}
}
fn planning_outcome_diagnostics(
diagnostics: &NativePlanningDiagnostics,
accepted: bool,
) -> (Option<CandidateOutcomeKind>, Option<String>, Option<String>) {
if accepted {
return (Some(CandidateOutcomeKind::Selected), None, None);
}
for outcome in diagnostics.report.outcomes() {
match outcome {
CandidateOutcome::Selected { .. } => {},
CandidateOutcome::NotSupported { capability_reason, detail, .. } => {
return (
Some(CandidateOutcomeKind::NotSupported),
Some(capability_reason.code().to_string()),
Some(unsupported_category(*capability_reason, detail)),
);
},
CandidateOutcome::NotSelectedByCost { cost_reason, .. } => {
return (Some(CandidateOutcomeKind::NotSelectedByCost), Some(cost_reason.code().to_string()), None);
},
}
}
(None, None, None)
}
fn total_rows(batches: &[RecordBatch]) -> usize {
batches.iter().map(RecordBatch::num_rows).sum()
}
struct ParityInputs<'a> {
cpu_planning_status: ParityStageStatus,
cpu_runtime_status: ParityStageStatus,
native_planning_outcome: Option<CandidateOutcomeKind>,
native_runtime_started: bool,
native_runtime_outcome: NativeDataFusionRuntimeOutcome,
cpu_schema: Option<&'a SchemaRef>,
cpu_batches: Option<&'a [RecordBatch]>,
native_schema: Option<&'a SchemaRef>,
native_batches: Option<&'a [RecordBatch]>,
ordering: &'a ParityRowOrdering,
float_tolerance: ParityFloatTolerance,
}
fn derive_parity_outcome(
inputs: ParityInputs<'_>,
) -> (ParityStatus, ParityComparisonMode, Option<String>, Option<String>, Option<String>) {
if inputs.cpu_planning_status != ParityStageStatus::Succeeded
|| inputs.cpu_runtime_status != ParityStageStatus::Succeeded
{
return (ParityStatus::CpuFailed, ParityComparisonMode::NotApplicable, None, None, None);
}
match inputs.native_planning_outcome {
Some(CandidateOutcomeKind::NotSupported | CandidateOutcomeKind::NotSelectedByCost) | None => {
return (ParityStatus::NativeRejected, ParityComparisonMode::NotApplicable, None, None, None);
},
Some(CandidateOutcomeKind::Selected) => {},
}
if !inputs.native_runtime_started {
return (ParityStatus::NativeRejected, ParityComparisonMode::NotApplicable, None, None, None);
}
if inputs.native_runtime_outcome != NativeDataFusionRuntimeOutcome::Succeeded {
return (ParityStatus::NativeFailed, ParityComparisonMode::NotApplicable, None, None, None);
}
let (Some(cpu_schema), Some(cpu_batches), Some(native_schema), Some(native_batches)) =
(inputs.cpu_schema, inputs.cpu_batches, inputs.native_schema, inputs.native_batches)
else {
return (
ParityStatus::NotCompared,
ParityComparisonMode::NotApplicable,
Some("missing comparison inputs".to_string()),
None,
None,
);
};
let result = compare_record_batches_with_options(
cpu_schema.as_ref(),
cpu_batches,
native_schema.as_ref(),
native_batches,
inputs.ordering,
inputs.float_tolerance,
ParityCompareOptions::strict_native(),
);
(result.status, result.mode, result.detail, Some(result.cpu_fingerprint), Some(result.native_fingerprint))
}