fn wcet_rec(
    bkpts: &mut Vec<(Breakpoint, String, u32)>,
    stack: &mut Vec<EntryBreakpoint>,
) -> Result<(Vec<Trace>, (Breakpoint, String, u32))> {
    // This is the main result of this function
    let mut traces: Vec<Trace> = Vec::new();
    let (bkpt, name, cyccnt) = match bkpts.pop() {
        Some((b, n, c)) => (b, n, c),
        None => return Err(anyhow!("Breakpoint vector is empty")),
    };

    // Set the current scope's variables. These are always returned in the end.
    // Because the outer scope needs to be able to read the objects data.
    let curr_bkpt = bkpt.clone();
    let curr_name = name.clone();
    let curr_cyccnt = cyccnt.clone();

    match &curr_bkpt {
        Breakpoint::Entry(e) => {
            // Push this entry to the internal stack. Used to check
            // that the corresponding Entry, Exit are correct.
            stack.push(e.clone());

            // Build a new trace
            let name = curr_name.clone();
            let ttype = TraceType::from(e.clone());
            let start = curr_cyccnt.clone();
            let mut inner = Vec::<Trace>::new();

            // Inner loop
            let mut prev: Breakpoint;
            let mut end;
            loop {
                let (mut i, (last, _, e)) = wcet_rec(bkpts, stack).with_context(|| {
                    format!("Could not proceed with analysis after breakpoint {:?}", &e)
                })?;
                inner.append(&mut i);
                prev = last.clone();
                end = e;

                // If we get two Exits in a row, it means that we're exiting
                // the inner loop. It should also break if there are no more
                // objects in the bkpts vector
                if last.is_exit() && prev.is_exit() || bkpts.is_empty() {
                    break;
                }
            }
            let trace = Trace::new(name, ttype, start, inner, end);
            traces.push(trace);
        }
        Breakpoint::Exit(exit) => {
            // The stack should not be empty if we're exiting the analysis.
            // All corresponding Entry/Exit should add up to 255 if correct order.
            let entry = stack.pop().unwrap() as u32;
            let exit = exit.clone() as u32;
            if entry + exit != 255 {
                return Err(anyhow!(
                    "Breakpoint scope not matching! Got entry: {} and exit: {}",
                    entry,
                    exit
                ));
            }
        }
        // Should ignore the Default breakpoint instead of returning an error
        Breakpoint::Other(o) => {
            return Err(anyhow!("Unsupported breakpoint inside analysis: {:?}", o));
        }
    }

    Ok((traces, (curr_bkpt, curr_name, curr_cyccnt)))
}
// This function is not the most beautiful code ever written and quite unintuitive!
// Check the documenation for the analysis to get an understanding of how it works!
//
// The `bkpts` contains the tuple (Breakpoint, Name, CYCCNT) of each breakpoint, traced
// from the replay harness on actual hardware. The `stack` is used internally to keep
// track of the correct scopes. That is, that for each Entry a corresponding Exit exists.
This function is not the most beautiful code ever written and quite unintuitive.
Check the documenation for the analysis to get an understanding of how it works!

The `bkpts` contains the tuple (Breakpoint, Name, CYCCNT) of each breakpoint, traced
from the replay harness on actual hardware. The `stack` is used internally to keep
track of the correct scopes. That is, that for each Entry a corresponding Exit exists.
This function is not the most beautiful code ever written and quite unintuitive . Check the documenation for the analysis to get an understanding of how it works! The ` bkpts ` contains the tuple ( Breakpoint Name CYCCNT ) of each breakpoint traced from the replay harness on actual hardware . The ` stack ` is used internally to keep track of the correct scopes . That is that for each Entry a corresponding Exit exists .
fn wcet_rec(
    bkpts: &mut Vec<(Breakpoint, String, u32)>,
    stack: &mut Vec<EntryBreakpoint>,
) -> Result<(Vec<Trace>, (Breakpoint, String, u32))> {
    // This is the main result of this function
    let mut traces: Vec<Trace> = Vec::new();
    let (bkpt, name, cyccnt) = match bkpts.pop() {
        Some((b, n, c)) => (b, n, c),
        None => return Err(anyhow!("Breakpoint vector is empty")),
    };
    // Set the current scope's variables. These are always returned in the end.
    // Because the outer scope needs to be able to read the objects data.
    let curr_bkpt = bkpt.clone();
    let curr_name = name.clone();
    let curr_cyccnt = cyccnt.clone();
    match &curr_bkpt {
        Breakpoint::Entry(e) => {
            // Push this entry to the internal stack. Used to check
            // that the corresponding Entry, Exit are correct.
            stack.push(e.clone());
            // Build a new trace
            let name = curr_name.clone();
            let ttype = TraceType::from(e.clone());
            let start = curr_cyccnt.clone();
            let mut inner = Vec::<Trace>::new();
            // Inner loop
            let mut prev: Breakpoint;
            let mut end;
            loop {
                let (mut i, (last, _, e)) = wcet_rec(bkpts, stack).with_context(|| {
                    format!("Could not proceed with analysis after breakpoint {:?}", &e)
                })?;
                inner.append(&mut i);
                prev = last.clone();
                end = e;
                // If we get two Exits in a row, it means that we're exiting
                // the inner loop. It should also break if there are no more
                // objects in the bkpts vector
                if last.is_exit() && prev.is_exit() || bkpts.is_empty() {
                    break;
                }
            }
            let trace = Trace::new(name, ttype, start, inner, end);
            traces.push(trace);
        }
        Breakpoint::Exit(exit) => {
            // The stack should not be empty if we're exiting the analysis.
            // All corresponding Entry/Exit should add up to 255 if correct order.
            let entry = stack.pop().unwrap() as u32;
            let exit = exit.clone() as u32;
            if entry + exit != 255 {
                return Err(anyhow!(
                    "Breakpoint scope not matching! Got entry: {} and exit: {}",
                    entry,
                    exit
                ));
            }
        }
        // Should ignore the Default breakpoint instead of returning an error
        Breakpoint::Other(o) => {
            return Err(anyhow!("Unsupported breakpoint inside analysis: {:?}", o));
        }
    }
    Ok((traces, (curr_bkpt, curr_name, curr_cyccnt)))
}
fn wcet_rec ( bkpts : & mut Vec < ( Breakpoint , String , u32 ) > , stack : & mut Vec < EntryBreakpoint > , ) -> Result < ( Vec < Trace > , ( Breakpoint , String , u32 ) ) > { // This is the main result of this function let mut traces : Vec < Trace > = Vec :: new ( ) ; let ( bkpt , name , cyccnt ) = match bkpts . pop ( ) { Some ( ( b , n , c ) ) => ( b , n , c ) , None => return Err ( anyhow ! ( " " ) ) , } ; // Set the current scope's variables. These are always returned in the end. // Because the outer scope needs to be able to read the objects data. let curr_bkpt = bkpt . clone ( ) ; let curr_name = name . clone ( ) ; let curr_cyccnt = cyccnt . clone ( ) ; match & curr_bkpt { Breakpoint :: Entry ( e ) => { // Push this entry to the internal stack. Used to check // that the corresponding Entry, Exit are correct. stack . push ( e . clone ( ) ) ; // Build a new trace let name = curr_name . clone ( ) ; let ttype = TraceType :: from ( e . clone ( ) ) ; let start = curr_cyccnt . clone ( ) ; let mut inner = Vec :: < Trace > :: new ( ) ; // Inner loop let mut prev : Breakpoint ; let mut end ; loop { let ( mut i , ( last , _ , e ) ) = wcet_rec ( bkpts , stack ) . with_context ( | | { format ! ( " " e ) } ) ? ; inner . append ( & mut i ) ; prev = last . clone ( ) ; end = e ; // If we get two Exits in a row, it means that we're exiting // the inner loop. It should also break if there are no more // objects in the bkpts vector if last . is_exit ( ) && prev . is_exit ( ) || bkpts . is_empty ( ) { break ; } } let trace = Trace :: new ( name , ttype , start , inner , end ) ; traces . push ( trace ) ; } Breakpoint :: Exit ( exit ) => { // The stack should not be empty if we're exiting the analysis. // All corresponding Entry/Exit should add up to 255 if correct order. let entry = stack . pop ( ) . unwrap ( ) as u32 ; let exit = exit . clone ( ) as u32 ; if entry + exit != 255 { return Err ( anyhow ! ( " " entry exit ) ) ; } } // Should ignore the Default breakpoint instead of returning an error Breakpoint :: Other ( o ) => { return Err ( anyhow ! ( " " o ) ) ; } } Ok ( ( traces , ( curr_bkpt , curr_name , curr_cyccnt ) ) ) }
This function is not the most beautiful code ever written and quite unintuitive!
This function is not the most beautiful code ever written and quite unintuitive!
bkpts
&mut Vec<(Breakpoint, String, u32)>
stack
&mut Vec<EntryBreakpoint>
bkpts
&mut Vec<(Breakpoint, String, u32)>
stack
&mut Vec<EntryBreakpoint>