save stats per abb

This commit is contained in:
Alwin Berger 2024-10-21 17:13:38 +02:00
parent 926ad96b8e
commit 8417613cb2
5 changed files with 73 additions and 11 deletions

View File

@ -25,4 +25,4 @@ do
done < <(find ./remote/timedump -maxdepth 2 -type 'f' -iregex '.*\.case')
# echo "${PLOTS[@]}"
snakemake -c 6 "${PLOTS[@]}"
snakemake -c 6 --keep-incomplete "${PLOTS[@]}"

View File

@ -192,7 +192,30 @@ where
let names : Vec<String> = observer.last_run.iter().map(|x| x.current_task.task_name.clone()).collect();
match &self.dumpfile {
Some(s) => {
std::fs::write(s,ron::to_string(&(&observer.last_trace,&observer.last_states,&observer.job_instances)).expect("Error serializing hashmap")).expect("Can not dump to file");
let per_task_metadata = if let Some(worst_instance) = observer.job_instances.iter().filter(|x| Some(x.2.clone()) == observer.select_task).max_by(|a,b| (a.1-a.0).cmp(&(b.1-b.0))) {
// extract computation time spent in each task and abb
let t : Vec<_> = observer.last_trace.iter().filter(|x| x.start_tick < worst_instance.1 && x.end_tick > worst_instance.0 ).cloned().collect();
// task_name -> addr -> (count, time)
let mut ret : HashMap<String, HashMap<u32, (usize, usize, u64)>> = HashMap::new();
let mut t2 = t.clone();
t2.sort_by_key(|x| x.get_task_name_unchecked());
t2.chunk_by_mut(|x,y| x.get_task_name_unchecked() == y.get_task_name_unchecked()).for_each(|x| {
x.sort_by_key(|y| y.abb.as_ref().unwrap().start);
x.chunk_by(|y,z| y.abb.as_ref().unwrap().start == z.abb.as_ref().unwrap().start).for_each(|y| {
match ret.get_mut(&y[0].get_task_name_unchecked()) {
Option::None => {
ret.insert(y[0].get_task_name_unchecked(), HashMap::from([(y[0].abb.as_ref().unwrap().start, (y.len(), y.iter().filter(|x| x.is_abb_end()).count(), y.iter().map(|z| z.get_exec_time()).sum::<_>()))]));
}
Some(x) => {
x.insert(y[0].abb.as_ref().unwrap().start, (y.len(), y.iter().filter(|x| x.is_abb_end()).count(), y.iter().map(|z| z.get_exec_time()).sum()));
}
}
});
});
dbg!(&ret);
ret
} else {HashMap::new()};
std::fs::write(s,ron::to_string(&(&observer.last_trace,&observer.last_states,&observer.job_instances,per_task_metadata)).expect("Error serializing hashmap")).expect("Can not dump to file");
self.dumpfile = None
},
Option::None => if self.dump_metadata {println!("{:?}\n{:?}",observer.last_run,names);}

View File

@ -194,6 +194,7 @@ pub struct ExecInterval {
pub end_state: u64,
pub start_capture: (CaptureEvent, String),
pub end_capture: (CaptureEvent, String),
pub interval_name: String,
pub level: u8,
tick_spend_preempted: u64,
pub abb: Option<AtomicBasicBlock>
@ -228,6 +229,20 @@ impl ExecInterval {
pub fn get_hash_index(&self) -> (u64, u64) {
return (self.start_state, self.abb.as_ref().expect("ABB not set").get_hash())
}
pub fn get_task_name(&self) -> Option<String> {
self.abb.as_ref().map(|x| x.instance_name.clone()).flatten()
}
pub fn get_task_name_unchecked(&self) -> String {
self.get_task_name().unwrap_or_else(|| "unknown".to_string())
}
pub fn is_abb_end(&self) -> bool {
match self.end_capture.0 {
CaptureEvent::APIStart | CaptureEvent::APIEnd | CaptureEvent::ISREnd | CaptureEvent::End => true,
_ => false
}
}
}
// Wrapper around Vec<RefinedFreeRTOSSystemState> to attach as Metadata
@ -280,7 +295,8 @@ pub struct AtomicBasicBlock {
start: GuestAddr,
ends: HashSet<GuestAddr>,
level: u8,
instance_id: usize
instance_id: usize,
instance_name: Option<String>,
}
impl PartialEq for AtomicBasicBlock {
@ -308,7 +324,7 @@ impl fmt::Display for AtomicBasicBlock {
for end in &self.ends {
ends_str.push_str(&format!("0x{:#x}, ", end));
}
write!(f, "ABB {{ level: {}, start: 0x{:#x}, ends: [{}]}}", self.level, self.start, ends_str.trim().trim_matches(','))
write!(f, "ABB {} {{ level: {}, start: 0x{:#x}, ends: [{}]}}", &self.instance_name.as_ref().unwrap_or(&"".to_string()), self.level, self.start, ends_str.trim().trim_matches(','))
}
}
impl fmt::Debug for AtomicBasicBlock {
@ -317,7 +333,7 @@ impl fmt::Debug for AtomicBasicBlock {
for end in &self.ends {
ends_str.push_str(&format!("{:#x}, ", end));
}
write!(f, "ABB {{ level: {}, start: {:#x}, ends: [{}]}}", self.level, self.start, ends_str.trim().trim_matches(','))
write!(f, "ABB {} {{ level: {}, start: 0x{:#x}, ends: [{}]}}", &self.instance_name.as_ref().unwrap_or(&"".to_string()), self.level, self.start, ends_str.trim().trim_matches(','))
}
}

View File

@ -83,7 +83,7 @@ where
let observer = &self;
let mut worst_case_per_task = HashMap::new();
observer.job_instances.iter().for_each(|x| {
let time = (x.1-x.0);
let time = x.1-x.0;
if worst_case_per_task.get(&x.2).is_some() {
let old = worst_case_per_task.get_mut(&x.2).unwrap();
if time > *old {
@ -191,7 +191,11 @@ fn tcb_list_to_vec_cached(list: List_t, dump: &mut HashMap<u32,rtos_struct>) ->
ret.push(last_tcb);
ret
}
/// Drains a List of raw SystemStates to produce a refined trace
/// returns:
/// - a Vec of ReducedFreeRTOSSystemStates
/// - a Vec of metadata tuples (qemu_tick, capture_event, capture_name, edge, mem_reads)
fn refine_system_states(mut input: Vec<RawFreeRTOSSystemState>) -> (Vec<ReducedFreeRTOSSystemState>, Vec<(u64, CaptureEvent, String, (u32, u32), HashSet<u32>)>) {
let mut ret = (Vec::<_>::new(), Vec::<_>::new());
for mut i in input.drain(..) {
@ -412,6 +416,11 @@ fn get_release_response_pairs(rel: &Vec<(u64, String)>, resp: &Vec<(u64, String)
}
/// Transform the states and metadata into a list of ExecIntervals, along with a HashMap of states, a list of HashSets marking memory reads and a bool indicating success
/// returns:
/// - a Vec of ExecIntervals
/// - a Vec of HashSets marking memory reads during these intervals
/// - a HashMap of ReducedFreeRTOSSystemStates by hash
/// - a bool indicating success
fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, CaptureEvent, String, (u32, u32), HashSet<u32>)>) -> (Vec<ExecInterval>, Vec<HashSet<u32>>, HashMap<u64, ReducedFreeRTOSSystemState>, bool) {
if trace.len() == 0 {return (Vec::new(), Vec::new(), HashMap::new(), true);}
let mut isr_stack : VecDeque<u8> = VecDeque::from([]); // 2+ = ISR, 1 = systemcall, 0 = APP. Trace starts with an ISREnd and executes the app
@ -427,6 +436,7 @@ fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, Capt
table.insert(last_hash, trace[0].clone());
for i in 0..trace.len()-1 {
let curr_name = trace[i].current_task.task_name.as_str();
// let mut interval_name = curr_name; // Name of the interval, either the task name or the isr/api funtion name
let level = match meta[i].1 {
CaptureEvent::APIEnd => { // API end always exits towards the app
if !level_of_task.contains_key(curr_name) {
@ -440,6 +450,7 @@ fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, Capt
level_of_task.insert(curr_name, 0);
}
*level_of_task.get_mut(curr_name).unwrap()=1;
// interval_name = &meta[i].2;
1
},
CaptureEvent::ISREnd => {
@ -449,11 +460,15 @@ fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, Capt
}
// nested isr, TODO: Test level > 2
if isr_stack.len() > 1 {
// interval_name = ""; // We can't know which isr is running
isr_stack.pop_back().unwrap();
*isr_stack.back().unwrap()
} else {
isr_stack.pop_back();
// possibly go back to an api call that is still running for this task
if level_of_task.get(curr_name).unwrap() == &1 {
// interval_name = ""; // We can't know which api is running
}
*level_of_task.get(curr_name).unwrap()
}
},
@ -463,6 +478,7 @@ fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, Capt
// &2
// } else {
// regular case
// interval_name = &meta[i].2;
if isr_stack.len() > 0 {
let l = *isr_stack.back().unwrap();
isr_stack.push_back(l+1);
@ -488,6 +504,7 @@ fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, Capt
start_capture: (meta[i].1, meta[i].2.clone()),
end_capture: (meta[i+1].1, meta[i+1].2.clone()),
level: level,
interval_name: String::new(),
tick_spend_preempted: 0,
abb: None
});
@ -499,6 +516,7 @@ fn states2intervals(trace: Vec<ReducedFreeRTOSSystemState>, meta: Vec<(u64, Capt
(ret, reads, table, t)
}
/// Marks which abbs were executed at each interval
fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeRTOSSystemState>, edges: &Vec<(u32, u32)>) -> bool {
let mut id_count = 0;
let mut ret = true;
@ -522,7 +540,7 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
// assert_eq!(open_abb, None);
ret &= open_abb.is_none();
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), i);
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count})));
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count, instance_name: Some(trace[i].start_capture.1.clone())})));
id_count+=1;
},
// generic isr abb start
@ -530,7 +548,7 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
// assert_eq!(open_abb, None);
ret &= open_abb.is_none();
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), i);
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count})));
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count, instance_name: Some(trace[i].start_capture.1.clone())})));
id_count+=1;
},
// generic app abb start
@ -538,7 +556,7 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
// assert_eq!(open_abb, None);
ret &= open_abb.is_none();
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), i);
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count})));
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count, instance_name: if trace[i].level<2 {Some(curr_name.clone())} else {None}})));
id_count+=1;
},
// generic continued blocks
@ -547,7 +565,7 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
if trace[i].start_capture.1=="xPortPendSVHandler" && !task_has_started.contains(curr_name) {
// assert_eq!(open_abb, None);
ret &= open_abb.is_none();
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: 0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count})));
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: 0, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count, instance_name: Some(curr_name.clone())})));
id_count+=1;
open_abb_at_this_ret_addr_and_task.insert((edges[i].1, if trace[i].level<2 {&curr_name} else {""}), i);
task_has_started.insert(curr_name.clone());
@ -563,7 +581,7 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
// println!("Continued block with no start {} {} {:?} {:?} {:x}-{:x} {} {}", curr_name, trace[i].start_tick, trace[i].start_capture, trace[i].end_capture, edges[i].0, edges[i].1, task_has_started.contains(curr_name),trace[i].level);
// println!("{:x?}", open_abb_at_this_ret_addr_and_task);
ret = false;
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].1, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count})));
wip_abb_trace.push(Rc::new(RefCell::new(AtomicBasicBlock{start: edges[i].1, ends: HashSet::new(), level: if trace[i].level<2 {trace[i].level} else {2}, instance_id: id_count, instance_name: if trace[i].level<1 {Some(curr_name.clone())} else {None}})));
id_count+=1;
}
}
@ -602,6 +620,7 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
for i in 0..trace.len() {
trace[i].abb = Some((*wip_abb_trace[i]).borrow().clone());
trace[i].interval_name = (*wip_abb_trace[i]).borrow().instance_name.clone().unwrap_or(String::from(""));
}
return ret;
}

View File

@ -40,6 +40,10 @@ pub fn tick_to_time(ticks: u64) -> Duration {
Duration::from_nanos((ticks << QEMU_ICOUNT_SHIFT) as u64)
}
pub fn tick_to_ms(ticks: u64) -> f32 {
(Duration::from_nanos(ticks << QEMU_ICOUNT_SHIFT).as_micros() as f32/10.0).round()/100.0
}
//========== Metadata
#[derive(Debug, SerdeAny, Serialize, Deserialize)]
pub struct QemuIcountMetadata {