pub fn evaluate<'a>(criterion: &'a Criterion, data: &Observation<'a>) -> Outcome<'a> {
    let (status, message) = match criterion {
        Criterion::GPIO(criterion) => {
            match criterion {
                GPIOCriterion::Any(_pin) => (Status::Complete, None),
            }
        },

        Criterion::Energy(criterion) => {
            match criterion.get_stat() {
                EnergyStat::Total => {
                    // Should exist in map because criterion stated it should be tracked.
                    let samples = data.energy_metrics()
                        .get(criterion.get_meter())
                        .unwrap();

                    let execution_duration = data.execution_result()
                        .as_ref()
                    // Evaluation results are only relevant when the exec_result is Ok(...).
                        .expect("Attempted to evaluate criterion when execution result failed")
                        .duration();
                    let sample_count = samples.len();
                    // Approximate the time slice of each sample from the number of samples taken.
                    let sample_time_repr: Duration = execution_duration / sample_count as u32;
                    let rate_to_total_factor: f64 = sample_time_repr.as_micros() as f64
                        / Duration::from_secs(1).as_micros() as f64;

                    let mut total = 0f64;
                    for sample in samples.iter().map(|(_t, s)| s).copied() {
                        // mJ/s * fraction of the second the sample accounts for
                        total += sample as f64 * rate_to_total_factor;
                    }

                    let status = if let Some(violated) = criterion.violated(total as f32) {
                        if violated {
                            Status::Fail
                        } else {
                            Status::Pass
                        }
                    } else {
                        Status::Complete
                    };

                    (status, Some(format!("{:.2}mJ consumed", total)))
                },

                EnergyStat::Average => {
                    let samples = data.energy_metrics().get(criterion.get_meter()).unwrap();
                    // ASSUMPTION: timer intervals represented by all samples are equal.
                    let avg: f32 = samples.iter().map(|(_t, s)| s).sum::<f32>() / samples.len() as f32;

                    let status = if let Some(violated) = criterion.violated(avg as f32) {
                        if violated {
                            Status::Fail
                        } else {
                            Status::Pass
                        }
                    } else {
                        Status::Complete
                    };

                    (status, Some(format!("{:.2}mJ/s average", avg)))
                },

                EnergyStat::Max => {
                    let samples = data.energy_metrics().get(criterion.get_meter()).unwrap();
                    let max = samples.iter()
                        .map(|(_t, sample)| sample)
                        .copied()
                        .fold(0f32, |curr, n| if n > curr { n } else { curr });

                    let status = if let Some(violated) = criterion.violated(max as f32) {
                        if violated {
                            Status::Fail
                        } else {
                            Status::Pass
                        }
                    } else {
                        Status::Complete
                    };

                    (status, Some(format!("{:.2}mJ/s max", max)))
                },

                EnergyStat::Min => {
                    let samples = data.energy_metrics().get(criterion.get_meter()).unwrap();
                    let min = if samples.len() > 0 {
                        samples.iter()
                            .map(|(_t, sample)| sample)
                            .copied()
                            .fold(f32::MAX, |curr, n| if n < curr { n } else { curr })
                    } else {
                        0f32
                    };

                    let status = if let Some(violated) = criterion.violated(min as f32) {
                        if violated {
                            Status::Fail
                        } else {
                            Status::Pass
                        }
                    } else {
                        Status::Complete
                    };

                    (status, Some(format!("{:.2}mJ/s min", min)))
                },
            }
        },

        Criterion::SerialTrace(trace_criterion) => {
            let execution_t0 = data.execution_result()
                .as_ref()
                .expect("Attempted to evaluate serial tracing criterion when execution result failed")
                .get_start();
            if let Some(aligned_traces) = trace_criterion.align(execution_t0, data.traces().as_slice()) {
                let count = aligned_traces.len();
                let mut message = "Satisfied by: ".to_string();
                let it = aligned_traces.into_iter()
                    .map(|t| format!("@{:?}", t.get_offset(execution_t0)));
                for (msg, no) in it.zip(1..) {
                    message.push_str(&msg);
                    if no < count {
                        message.push_str(" → ");
                    }
                }
                (Status::Pass, Some(message))
            } else {
                (Status::Fail, None)
            }
        },
    };

    Outcome::new(criterion, status, message)
}
/// Evaluate criterion defined within Clockwise.
Evaluate criterion defined within Clockwise.
Evaluate criterion defined within Clockwise .
pub fn evaluate<'a>(criterion: &'a Criterion, data: &Observation<'a>) -> Outcome<'a> {
    let (status, message) = match criterion {
        Criterion::GPIO(criterion) => {
            match criterion {
                GPIOCriterion::Any(_pin) => (Status::Complete, None),
            }
        },
        Criterion::Energy(criterion) => {
            match criterion.get_stat() {
                EnergyStat::Total => {
                    // Should exist in map because criterion stated it should be tracked.
                    let samples = data.energy_metrics()
                        .get(criterion.get_meter())
                        .unwrap();
                    let execution_duration = data.execution_result()
                        .as_ref()
                    // Evaluation results are only relevant when the exec_result is Ok(...).
                        .expect("Attempted to evaluate criterion when execution result failed")
                        .duration();
                    let sample_count = samples.len();
                    // Approximate the time slice of each sample from the number of samples taken.
                    let sample_time_repr: Duration = execution_duration / sample_count as u32;
                    let rate_to_total_factor: f64 = sample_time_repr.as_micros() as f64
                        / Duration::from_secs(1).as_micros() as f64;
                    let mut total = 0f64;
                    for sample in samples.iter().map(|(_t, s)| s).copied() {
                        // mJ/s * fraction of the second the sample accounts for
                        total += sample as f64 * rate_to_total_factor;
                    }
                    let status = if let Some(violated) = criterion.violated(total as f32) {
                        if violated {
                            Status::Fail
                        } else {
                            Status::Pass
                        }
                    } else {
                        Status::Complete
                    };
                    (status, Some(format!("{:.2}mJ consumed", total)))
                },
                EnergyStat::Average => {
                    let samples = data.energy_metrics().get(criterion.get_meter()).unwrap();
                    // ASSUMPTION: timer intervals represented by all samples are equal.
                    let avg: f32 = samples.iter().map(|(_t, s)| s).sum::<f32>() / samples.len() as f32;
                    let status = if let Some(violated) = criterion.violated(avg as f32) {
                        if violated {
                            Status::Fail
                        } else {
                            Status::Pass
                        }
                    } else {
                        Status::Complete
                    };
                    (status, Some(format!("{:.2}mJ/s average", avg)))
                },
                EnergyStat::Max => {
                    let samples = data.energy_metrics().get(criterion.get_meter()).unwrap();
                    let max = samples.iter()
                        .map(|(_t, sample)| sample)
                        .copied()
                        .fold(0f32, |curr, n| if n > curr { n } else { curr });
                    let status = if let Some(violated) = criterion.violated(max as f32) {
                        if violated {
                            Status::Fail
                        } else {
                            Status::Pass
                        }
                    } else {
                        Status::Complete
                    };
                    (status, Some(format!("{:.2}mJ/s max", max)))
                },
                EnergyStat::Min => {
                    let samples = data.energy_metrics().get(criterion.get_meter()).unwrap();
                    let min = if samples.len() > 0 {
                        samples.iter()
                            .map(|(_t, sample)| sample)
                            .copied()
                            .fold(f32::MAX, |curr, n| if n < curr { n } else { curr })
                    } else {
                        0f32
                    };
                    let status = if let Some(violated) = criterion.violated(min as f32) {
                        if violated {
                            Status::Fail
                        } else {
                            Status::Pass
                        }
                    } else {
                        Status::Complete
                    };
                    (status, Some(format!("{:.2}mJ/s min", min)))
                },
            }
        },
        Criterion::SerialTrace(trace_criterion) => {
            let execution_t0 = data.execution_result()
                .as_ref()
                .expect("Attempted to evaluate serial tracing criterion when execution result failed")
                .get_start();
            if let Some(aligned_traces) = trace_criterion.align(execution_t0, data.traces().as_slice()) {
                let count = aligned_traces.len();
                let mut message = "Satisfied by: ".to_string();
                let it = aligned_traces.into_iter()
                    .map(|t| format!("@{:?}", t.get_offset(execution_t0)));
                for (msg, no) in it.zip(1..) {
                    message.push_str(&msg);
                    if no < count {
                        message.push_str(" → ");
                    }
                }
                (Status::Pass, Some(message))
            } else {
                (Status::Fail, None)
            }
        },
    };
    Outcome::new(criterion, status, message)
}
pub fn evaluate < ' a > ( criterion : & ' a Criterion , data : & Observation < ' a > ) -> Outcome < ' a > { let ( status , message ) = match criterion { Criterion :: GPIO ( criterion ) => { match criterion { GPIOCriterion :: Any ( _pin ) => ( Status :: Complete , None ) , } } , Criterion :: Energy ( criterion ) => { match criterion . get_stat ( ) { EnergyStat :: Total => { // Should exist in map because criterion stated it should be tracked. let samples = data . energy_metrics ( ) . get ( criterion . get_meter ( ) ) . unwrap ( ) ; let execution_duration = data . execution_result ( ) . as_ref ( ) // Evaluation results are only relevant when the exec_result is Ok(...). . expect ( " " ) . duration ( ) ; let sample_count = samples . len ( ) ; // Approximate the time slice of each sample from the number of samples taken. let sample_time_repr : Duration = execution_duration / sample_count as u32 ; let rate_to_total_factor : f64 = sample_time_repr . as_micros ( ) as f64 / Duration :: from_secs ( 1 ) . as_micros ( ) as f64 ; let mut total = 0f64 ; for sample in samples . iter ( ) . map ( | ( _t , s ) | s ) . copied ( ) { // mJ/s * fraction of the second the sample accounts for total += sample as f64 * rate_to_total_factor ; } let status = if let Some ( violated ) = criterion . violated ( total as f32 ) { if violated { Status :: Fail } else { Status :: Pass } } else { Status :: Complete } ; ( status , Some ( format ! ( " " total ) ) ) } , EnergyStat :: Average => { let samples = data . energy_metrics ( ) . get ( criterion . get_meter ( ) ) . unwrap ( ) ; // ASSUMPTION: timer intervals represented by all samples are equal. let avg : f32 = samples . iter ( ) . map ( | ( _t , s ) | s ) . sum :: < f32 > ( ) / samples . len ( ) as f32 ; let status = if let Some ( violated ) = criterion . violated ( avg as f32 ) { if violated { Status :: Fail } else { Status :: Pass } } else { Status :: Complete } ; ( status , Some ( format ! ( " " avg ) ) ) } , EnergyStat :: Max => { let samples = data . energy_metrics ( ) . get ( criterion . get_meter ( ) ) . unwrap ( ) ; let max = samples . iter ( ) . map ( | ( _t , sample ) | sample ) . copied ( ) . fold ( 0f32 , | curr , n | if n > curr { n } else { curr } ) ; let status = if let Some ( violated ) = criterion . violated ( max as f32 ) { if violated { Status :: Fail } else { Status :: Pass } } else { Status :: Complete } ; ( status , Some ( format ! ( " " max ) ) ) } , EnergyStat :: Min => { let samples = data . energy_metrics ( ) . get ( criterion . get_meter ( ) ) . unwrap ( ) ; let min = if samples . len ( ) > 0 { samples . iter ( ) . map ( | ( _t , sample ) | sample ) . copied ( ) . fold ( f32 :: MAX , | curr , n | if n < curr { n } else { curr } ) } else { 0f32 } ; let status = if let Some ( violated ) = criterion . violated ( min as f32 ) { if violated { Status :: Fail } else { Status :: Pass } } else { Status :: Complete } ; ( status , Some ( format ! ( " " min ) ) ) } , } } , Criterion :: SerialTrace ( trace_criterion ) => { let execution_t0 = data . execution_result ( ) . as_ref ( ) . expect ( " " ) . get_start ( ) ; if let Some ( aligned_traces ) = trace_criterion . align ( execution_t0 , data . traces ( ) . as_slice ( ) ) { let count = aligned_traces . len ( ) ; let mut message = " " . to_string ( ) ; let it = aligned_traces . into_iter ( ) . map ( | t | format ! ( " " t get_offset ( execution_t0 ) ) ) ; for ( msg , no ) in it . zip ( 1 .. ) { message . push_str ( & msg ) ; if no < count { message . push_str ( " ; } } ( Status :: Pass , Some ( message ) ) } else { ( Status :: Fail , None ) } } , } ; Outcome :: new ( criterion , status , message ) }
Evaluate criterion defined within Clockwise.
Evaluate criterion defined within Clockwise .
criterion
&'a Criterion
data
&Observation<'a>
criterion
&'a Criterion
data
&Observation<'a>