scheduler, mutator changes

This commit is contained in:
Alwin Berger 2024-05-22 21:54:07 +02:00
parent c533b7e184
commit bde16f8297
6 changed files with 253 additions and 130 deletions

View File

@ -5,7 +5,7 @@ authors = ["Alwin Berger <alwin.berger@tu-dortmund.de>"]
edition = "2021" edition = "2021"
[features] [features]
default = ["std", "snapshot_restore", "singlecore", "restarting", "do_hash_notify_state", "config_stg" ] default = ["std", "snapshot_restore", "singlecore", "restarting", "do_hash_notify_state", "config_stg", "fuzz_int" ]
std = [] std = []
# Exec environemnt basics # Exec environemnt basics
snapshot_restore = [] snapshot_restore = []
@ -26,6 +26,7 @@ feed_stg = [ "trace_stg", "observe_systemstate" ]
feed_stg_pathhash = [ "feed_stg"] feed_stg_pathhash = [ "feed_stg"]
feed_stg_abbhash = [ "feed_stg"] feed_stg_abbhash = [ "feed_stg"]
feed_stg_aggregatehash = [ "feed_stg"] feed_stg_aggregatehash = [ "feed_stg"]
mutate_stg = [ "observe_systemstate" ]
feed_longest = [ ] feed_longest = [ ]
feed_afl = [ "observe_edges" ] feed_afl = [ "observe_edges" ]
feed_genetic = [] feed_genetic = []
@ -44,7 +45,7 @@ sched_stg_aggregatehash = ['sched_stg'] # every aggregated path (order independe
config_genetic = ["gensize_100","feed_genetic","sched_genetic"] config_genetic = ["gensize_100","feed_genetic","sched_genetic"]
config_afl = ["feed_afl","sched_afl","observe_hitcounts"] config_afl = ["feed_afl","sched_afl","observe_hitcounts"]
config_frafl = ["feed_afl","sched_afl","feed_longest"] config_frafl = ["feed_afl","sched_afl","feed_longest"]
config_stg = ["feed_stg","sched_stg"] config_stg = ["feed_stg_aggregatehash","sched_stg_aggregatehash","mutate_stg"]
[profile.release] [profile.release]
lto = true lto = true

View File

@ -4,6 +4,7 @@
use core::marker::PhantomData; use core::marker::PhantomData;
use std::cmp::{max, min}; use std::cmp::{max, min};
use hashbrown::HashMap;
use libafl_bolts::rands::{ use libafl_bolts::rands::{
StdRand, RandomSeed, StdRand, RandomSeed,
Rand Rand
@ -12,7 +13,7 @@ use libafl::{
corpus::{self, Corpus}, fuzzer::Evaluator, mark_feature_time, prelude::{new_hash_feedback, CorpusId, HasBytesVec, MutationResult, Mutator, UsesInput}, stages::Stage, start_timer, state::{HasCorpus, HasMetadata, HasNamedMetadata, HasRand, MaybeHasClientPerfMonitor, UsesState}, Error corpus::{self, Corpus}, fuzzer::Evaluator, mark_feature_time, prelude::{new_hash_feedback, CorpusId, HasBytesVec, MutationResult, Mutator, UsesInput}, stages::Stage, start_timer, state::{HasCorpus, HasMetadata, HasNamedMetadata, HasRand, MaybeHasClientPerfMonitor, UsesState}, Error
}; };
use libafl::prelude::State; use libafl::prelude::State;
use crate::{clock::IcHist, fuzzer::{DO_NUM_INTERRUPT, FIRST_INT}, systemstate::{stg::{STGFeedbackState, STGNodeMetadata}, ExecInterval, FreeRTOSSystemStateMetadata, ReducedFreeRTOSSystemState}}; use crate::{clock::IcHist, fuzzer::{DO_NUM_INTERRUPT, FIRST_INT}, systemstate::{stg::{STGFeedbackState, STGNodeMetadata}, CaptureEvent, ExecInterval, FreeRTOSSystemStateMetadata, ReducedFreeRTOSSystemState}};
pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*ms*/ * 62500; pub static mut MINIMUM_INTER_ARRIVAL_TIME : u32 = 1000 /*ms*/ * 62500;
// one isn per 2**4 ns // one isn per 2**4 ns
@ -89,9 +90,8 @@ where
.get(corpus_idx)? .get(corpus_idx)?
.borrow_mut().clone(); .borrow_mut().clone();
let mut newinput = _input.input_mut().as_mut().unwrap().clone(); let mut newinput = _input.input_mut().as_mut().unwrap().clone();
// let mut tmpinput = _input.input_mut().as_mut().unwrap().clone();
let mut do_rerun = false; let mut do_rerun = false;
if state.rand_mut().between(1, 100) <= 50 // only attempt the mutation half of the time // if state.rand_mut().between(1, 100) <= 50 // only attempt the mutation half of the time
{ {
// need our own random generator, because borrowing rules // need our own random generator, because borrowing rules
let mut myrand = StdRand::new(); let mut myrand = StdRand::new();
@ -120,127 +120,188 @@ where
let mut suffix = target_bytes.split_off(4 * num_interrupts); let mut suffix = target_bytes.split_off(4 * num_interrupts);
let mut prefix : Vec<[u8; 4]> = vec![]; let mut prefix : Vec<[u8; 4]> = vec![];
// let mut suffix : Vec<u8> = vec![]; // let mut suffix : Vec<u8> = vec![];
#[cfg(feature = "trace_stg")] #[cfg(feature = "mutate_stg")]
{ {
if myrand.between(1,100) <= 25 { // 0.5*0.25 = 12.5% of the time fully randomize all interrupts let metadata = state.metadata_map();
let hist = metadata.get::<IcHist>().unwrap();
let maxtick : u64 = hist.1.0;
drop(hist);
if interrupt_offsets[0] as u64 > maxtick {
do_rerun = true; do_rerun = true;
let metadata = state.metadata_map(); for _ in 0..num_interrupts {
let hist = metadata.get::<IcHist>().unwrap();
let maxtick : u64 = hist.1.0;
// let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap();
let mut numbers : Vec<u32> = vec![];
for i in 0..num_interrupts {
prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick, u32::MAX as u64)).try_into().expect("ticks > u32"))); prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick, u32::MAX as u64)).try_into().expect("ticks > u32")));
} }
} else { } else {
let feedbackstate = match state let choice = myrand.between(1,100);
.named_metadata_map_mut() if choice <= 25 { // 0.5*0.25 = 12.5% of the time fully randomize all interrupts
.get_mut::<STGFeedbackState>("stgfeedbackstate") { do_rerun = true;
Some(s) => s, // let metadata = state.metadata_map();
None => { let hist = metadata.get::<IcHist>().unwrap();
panic!("STGfeedbackstate not visible") let maxtick : u64 = hist.1.0;
} // let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap();
}; let mut numbers : Vec<u32> = vec![];
for i in 0..num_interrupts {
let tmp = _input.metadata_map().get::<STGNodeMetadata>(); prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick, u32::MAX as u64)).try_into().expect("ticks > u32")));
if tmp.is_some() {
let trace = tmp.expect("STGNodeMetadata not found");
// calculate hits and identify snippets
let mut last_m = false;
let mut marks : Vec<(&ExecInterval, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler
for i in 0..trace.intervals.len() {
let curr = &trace.intervals[i];
let m = interrupt_offsets[0..num_interrupts].iter().any(|x| (curr.start_tick..curr.end_tick).contains(&(*x as u64)));
if m {
marks.push((curr, i, 1));
// println!("1: {}",curr.current_task.0.task_name);
} else if last_m {
marks.push((curr, i, 2));
// println!("2: {}",curr.current_task.0.task_name);
} else {
marks.push((curr, i, 0));
} }
last_m = m;
} }
for i in 0..num_interrupts { else if choice <= 75 { // 0.5 * 0.25 = 12.5% of cases
// bounds based on minimum inter-arrival time let feedbackstate = match state
let mut lb = 0; .named_metadata_map_mut()
let mut ub : u32 = marks[marks.len()-1].0.end_tick.try_into().expect("ticks > u32"); .get_mut::<STGFeedbackState>("stgfeedbackstate") {
if i > 0 { Some(s) => s,
lb = u32::saturating_add(interrupt_offsets[i-1],unsafe{MINIMUM_INTER_ARRIVAL_TIME}); None => {
} panic!("STGfeedbackstate not visible")
if i < num_interrupts-1 {
ub = u32::saturating_sub(interrupt_offsets[i+1],unsafe{MINIMUM_INTER_ARRIVAL_TIME});
}
// get old hit and handler
let old_hit = marks.iter().filter(
|x| x.0.start_tick < (interrupt_offsets[i] as u64) && (interrupt_offsets[i] as u64) < x.0.end_tick
).next();
let old_handler = match old_hit {
Some(s) => if s.1 < num_interrupts-1 && s.1 < marks.len()-1 {
Some(marks[s.1+1])
} else {None},
None => None
};
// find reachable alternatives
let alternatives : Vec<_> = marks.iter().filter(|x|
x.2 != 2 &&
(
x.0.start_tick < (lb as u64) && (lb as u64) < x.0.end_tick
|| x.0.start_tick < (ub as u64) && (ub as u64) < x.0.end_tick )
).collect();
// in cases there are no alternatives
if alternatives.len() == 0 {
if old_hit.is_none() {
// choose something random
let untouched : Vec<_> = marks.iter().filter(
|x| x.2 == 0
).collect();
if untouched.len() > 0 {
let tmp = interrupt_offsets[i];
let choice = myrand.choose(untouched);
interrupt_offsets[i] = myrand.between(choice.0.start_tick, choice.0.end_tick)
.try_into().expect("tick > u32");
do_rerun = true;
} }
// println!("no alternatives, choose random i: {} {} -> {}",i,tmp,interrupt_offsets[i]); };
let tmp = _input.metadata_map().get::<STGNodeMetadata>();
if tmp.is_some() {
let trace = tmp.expect("STGNodeMetadata not found");
let mut node_indices = vec![];
for i in (0..trace.intervals.len()).into_iter() {
if let Some(abb) = &trace.intervals[i].abb {
if let Some(idx) = feedbackstate.state_abb_hash_index.get(&(abb.get_hash(), trace.intervals[i].start_state)) {
node_indices.push(Some(idx));
continue;
}
}
node_indices.push(None);
}
// let mut marks : HashMap<u32, usize>= HashMap::new(); // interrupt -> block hit
// for i in 0..trace.intervals.len() {
// let curr = &trace.intervals[i];
// let m = interrupt_offsets[0..num_interrupts].iter().filter(|x| (curr.start_tick..curr.end_tick).contains(&((**x) as u64)));
// for k in m {
// marks.insert(*k,i);
// }
// }
// walk backwards trough the trace and try moving the interrupt to a block that does not have an outgoing interrupt edge or ist already hit by a predecessor
for i in (0..num_interrupts).rev() {
let mut lb = FIRST_INT;
let mut ub : u32 = trace.intervals[trace.intervals.len()-1].end_tick.try_into().expect("ticks > u32");
if i > 0 {
lb = u32::saturating_add(interrupt_offsets[i-1],unsafe{MINIMUM_INTER_ARRIVAL_TIME});
}
if i < num_interrupts-1 {
ub = u32::saturating_sub(interrupt_offsets[i+1],unsafe{MINIMUM_INTER_ARRIVAL_TIME});
}
let alternatives : Vec<_> = (0..trace.intervals.len()).filter(|x|
trace.intervals[*x].start_tick < (lb as u64) && (lb as u64) < trace.intervals[*x].end_tick
|| trace.intervals[*x].start_tick > (lb as u64) && trace.intervals[*x].start_tick < (ub as u64)
).collect();
let not_yet_hit : Vec<_> = alternatives.iter().filter(
|x| feedbackstate.graph.edges_directed(*node_indices[**x].unwrap(), petgraph::Direction::Outgoing).any(|y| y.weight().event != CaptureEvent::ISRStart)).collect();
if not_yet_hit.len() > 0 {
let replacement = &trace.intervals[*myrand.choose(not_yet_hit)];
interrupt_offsets[i] = (myrand.between(replacement.start_tick,
replacement.end_tick)).try_into().expect("ticks > u32");
// println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]);
do_rerun = true;
break;
}
}
}
}
else { // old version of the alternative search
let tmp = _input.metadata_map().get::<STGNodeMetadata>();
if tmp.is_some() {
let trace = tmp.expect("STGNodeMetadata not found");
// calculate hits and identify snippets
let mut last_m = false;
let mut marks : Vec<(&ExecInterval, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler
for i in 0..trace.intervals.len() {
let curr = &trace.intervals[i];
let m = interrupt_offsets[0..num_interrupts].iter().any(|x| (curr.start_tick..curr.end_tick).contains(&(*x as u64)));
if m {
marks.push((curr, i, 1));
// println!("1: {}",curr.current_task.0.task_name);
} else if last_m {
marks.push((curr, i, 2));
// println!("2: {}",curr.current_task.0.task_name);
} else {
marks.push((curr, i, 0));
}
last_m = m;
}
for i in 0..num_interrupts {
// bounds based on minimum inter-arrival time
let mut lb = FIRST_INT;
let mut ub : u32 = marks[marks.len()-1].0.end_tick.try_into().expect("ticks > u32");
if i > 0 {
lb = u32::saturating_add(interrupt_offsets[i-1],unsafe{MINIMUM_INTER_ARRIVAL_TIME});
}
if i < num_interrupts-1 {
ub = u32::saturating_sub(interrupt_offsets[i+1],unsafe{MINIMUM_INTER_ARRIVAL_TIME});
}
// get old hit and handler
let old_hit = marks.iter().filter(
|x| x.0.start_tick < (interrupt_offsets[i] as u64) && (interrupt_offsets[i] as u64) < x.0.end_tick
).next();
let old_handler = match old_hit {
Some(s) => if s.1 < num_interrupts-1 && s.1 < marks.len()-1 {
Some(marks[s.1+1])
} else {None},
None => None
};
// find reachable alternatives
let alternatives : Vec<_> = marks.iter().filter(|x|
x.2 != 2 &&
(
x.0.start_tick < (lb as u64) && (lb as u64) < x.0.end_tick
|| x.0.start_tick > (lb as u64) && x.0.start_tick < (ub as u64))
).collect();
// in cases there are no alternatives
if alternatives.len() == 0 {
if old_hit.is_none() {
// choose something random
let untouched : Vec<_> = marks.iter().filter(
|x| x.2 == 0
).collect();
if untouched.len() > 0 {
let tmp = interrupt_offsets[i];
let choice = myrand.choose(untouched);
interrupt_offsets[i] = myrand.between(choice.0.start_tick, choice.0.end_tick)
.try_into().expect("tick > u32");
do_rerun = true;
}
// println!("no alternatives, choose random i: {} {} -> {}",i,tmp,interrupt_offsets[i]);
continue;
} else {
// do nothing
// println!("no alternatives, do nothing i: {} {}",i,interrupt_offsets[i]);
continue;
}
}
let replacement = myrand.choose(alternatives);
if (old_hit.map_or(false, |x| x == replacement)) {
// use the old value
// println!("chose old value, do nothing i: {} {}",i,interrupt_offsets[i]);
continue; continue;
} else { } else {
// do nothing let extra = if (old_hit.map_or(false, |x| x.1 < replacement.1)) {
// println!("no alternatives, do nothing i: {} {}",i,interrupt_offsets[i]); // move futher back, respect old_handler
continue; old_handler.map_or(0, |x| x.0.end_tick - x.0.start_tick)
} else { 0 };
let tmp = interrupt_offsets[i];
interrupt_offsets[i] = (myrand.between(replacement.0.start_tick,
replacement.0.end_tick) + extra).try_into().expect("ticks > u32");
// println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]);
do_rerun = true;
} }
} }
let replacement = myrand.choose(alternatives); let mut numbers : Vec<u32> = interrupt_offsets[0..num_interrupts].to_vec();
if (old_hit.map_or(false, |x| x == replacement)) { numbers.sort();
// use the old value // println!("Mutator: {:?}", numbers);
// println!("chose old value, do nothing i: {} {}",i,interrupt_offsets[i]); // let mut start : u32 = 0;
continue; // for i in 0..numbers.len() {
} else { // let tmp = numbers[i];
let extra = if (old_hit.map_or(false, |x| x.1 < replacement.1)) { // numbers[i] = numbers[i]-start;
// move futher back, respect old_handler // start = tmp;
old_handler.map_or(0, |x| x.0.end_tick - x.0.start_tick) // }
} else { 0 }; for i in 0..numbers.len() {
let tmp = interrupt_offsets[i]; prefix.push(u32::to_le_bytes(numbers[i]));
interrupt_offsets[i] = (myrand.between(replacement.0.start_tick, }
replacement.0.end_tick) + extra).try_into().expect("ticks > u32");
// println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]);
do_rerun = true;
} }
}
let mut numbers : Vec<u32> = interrupt_offsets[0..num_interrupts].to_vec();
numbers.sort();
// println!("Mutator: {:?}", numbers);
// let mut start : u32 = 0;
// for i in 0..numbers.len() {
// let tmp = numbers[i];
// numbers[i] = numbers[i]-start;
// start = tmp;
// }
for i in 0..numbers.len() {
prefix.push(u32::to_le_bytes(numbers[i]));
}
} }
} }
} }

View File

@ -336,7 +336,7 @@ impl Ord for AtomicBasicBlock {
} }
impl AtomicBasicBlock { impl AtomicBasicBlock {
fn get_hash(&self) -> u64 { pub fn get_hash(&self) -> u64 {
let mut s = DefaultHasher::new(); let mut s = DefaultHasher::new();
self.hash(&mut s); self.hash(&mut s);
s.finish() s.finish()

View File

@ -344,7 +344,7 @@ fn add_abb_info(trace: &mut Vec<ExecInterval>, table: &HashMap<u64, ReducedFreeR
/// restore the isr/api begin/end invariant /// restore the isr/api begin/end invariant
fn fix_broken_trace(meta: &mut Vec<(u64, CaptureEvent, String, (Option<u32>, Option<u32>))>) { fn fix_broken_trace(meta: &mut Vec<(u64, CaptureEvent, String, (Option<u32>, Option<u32>))>) {
for i in meta.iter_mut() { for i in meta.iter_mut() {
if i.1 == CaptureEvent::APIStart && i.2 == "vTaskGenericNotifyGiveFromISR" { if i.1 == CaptureEvent::APIStart && i.2.ends_with("FromISR") {
i.1 = CaptureEvent::ISREnd; i.1 = CaptureEvent::ISREnd;
i.2 = "isr_starter".to_string(); i.2 = "isr_starter".to_string();
} }

View File

@ -1,4 +1,5 @@
use hashbrown::HashSet;
use libafl::SerdeAny; use libafl::SerdeAny;
/// Feedbacks organizing SystemStates as a graph /// Feedbacks organizing SystemStates as a graph
use libafl::inputs::HasBytesVec; use libafl::inputs::HasBytesVec;
@ -108,8 +109,8 @@ impl PartialEq for STGNode {
pub struct STGEdge pub struct STGEdge
{ {
// is_interrupt: bool, // is_interrupt: bool,
event: CaptureEvent, pub event: CaptureEvent,
name: String pub name: String
} }
impl STGEdge { impl STGEdge {
@ -146,14 +147,15 @@ pub struct STGFeedbackState
// aggregated traces as a graph // aggregated traces as a graph
pub graph: DiGraph<STGNode, STGEdge>, pub graph: DiGraph<STGNode, STGEdge>,
systemstate_index: HashMap<u64, ReducedFreeRTOSSystemState>, systemstate_index: HashMap<u64, ReducedFreeRTOSSystemState>,
state_abb_hash_index: HashMap<(u64, u64), NodeIndex>, pub state_abb_hash_index: HashMap<(u64, u64), NodeIndex>,
stgnode_index: HashMap<u64, NodeIndex>, stgnode_index: HashMap<u64, NodeIndex>,
entrypoint: NodeIndex, entrypoint: NodeIndex,
exitpoint: NodeIndex, exitpoint: NodeIndex,
// Metadata about aggregated traces. aggegated meaning, order has been removed // Metadata about aggregated traces. aggegated meaning, order has been removed
worst_observed_per_aggegated_path: HashMap<Vec<AtomicBasicBlock>,u64>, worst_observed_per_aggegated_path: HashMap<Vec<AtomicBasicBlock>,u64>,
worst_observed_per_abb_path: HashMap<u64,u64>, worst_observed_per_abb_path: HashMap<u64,u64>,
worst_observed_per_stg_path: HashMap<u64,u64> worst_observed_per_stg_path: HashMap<u64,u64>,
worst_abb_exec_count: HashMap<AtomicBasicBlock, usize>
} }
impl Default for STGFeedbackState { impl Default for STGFeedbackState {
@ -184,6 +186,7 @@ impl Default for STGFeedbackState {
worst_observed_per_aggegated_path: HashMap::new(), worst_observed_per_aggegated_path: HashMap::new(),
worst_observed_per_abb_path: HashMap::new(), worst_observed_per_abb_path: HashMap::new(),
worst_observed_per_stg_path: HashMap::new(), worst_observed_per_stg_path: HashMap::new(),
worst_abb_exec_count: HashMap::new(),
systemstate_index, systemstate_index,
state_abb_hash_index state_abb_hash_index
} }
@ -203,13 +206,15 @@ impl Named for STGFeedbackState
pub struct STGNodeMetadata { pub struct STGNodeMetadata {
pub nodes: Vec<NodeIndex>, pub nodes: Vec<NodeIndex>,
pub edges: Vec<EdgeIndex>, pub edges: Vec<EdgeIndex>,
pub abbs: Vec<AtomicBasicBlock>, pub abbs: u64,
pub aggregate: u64,
pub top_abb_counts: Vec<u64>,
pub intervals: Vec<ExecInterval>, pub intervals: Vec<ExecInterval>,
indices: Vec<usize>, indices: Vec<usize>,
tcref: isize, tcref: isize,
} }
impl STGNodeMetadata { impl STGNodeMetadata {
pub fn new(nodes: Vec<NodeIndex>, edges: Vec<EdgeIndex>, abbs: Vec<AtomicBasicBlock>, intervals: Vec<ExecInterval>) -> Self{ pub fn new(nodes: Vec<NodeIndex>, edges: Vec<EdgeIndex>, abbs: u64, aggregate: u64, top_abb_counts: Vec<u64>, intervals: Vec<ExecInterval>) -> Self{
let mut indices : Vec<_> = vec![]; let mut indices : Vec<_> = vec![];
#[cfg(all(feature = "sched_stg",not(any(feature = "sched_stg_pathhash",feature = "sched_stg_abbhash",feature = "sched_stg_aggregatehash"))))] #[cfg(all(feature = "sched_stg",not(any(feature = "sched_stg_pathhash",feature = "sched_stg_abbhash",feature = "sched_stg_aggregatehash"))))]
{ {
@ -223,15 +228,14 @@ impl STGNodeMetadata {
} }
#[cfg(feature = "sched_stg_abbhash")] #[cfg(feature = "sched_stg_abbhash")]
{ {
indices.push(get_generic_hash(&abbs) as usize); indices.push(abbs as usize);
} }
#[cfg(feature = "sched_stg_aggregatehash")] #[cfg(feature = "sched_stg_aggregatehash")]
{ {
let mut _abbs = abbs.clone(); // indices.push(aggregate as usize);
_abbs.sort_unstable(); indices = top_abb_counts.iter().map(|x| (*x) as usize).collect();
indices.push(get_generic_hash(&_abbs) as usize);
} }
Self {indices, intervals, nodes, abbs, edges, tcref: 0} Self {indices, intervals, nodes, abbs, aggregate, top_abb_counts, edges, tcref: 0}
} }
} }
impl AsSlice for STGNodeMetadata { impl AsSlice for STGNodeMetadata {
@ -258,6 +262,36 @@ libafl_bolts::impl_serdeany!(STGNodeMetadata);
pub type GraphMaximizerCorpusScheduler<CS> = pub type GraphMaximizerCorpusScheduler<CS> =
MinimizerScheduler<CS, MaxTimeFavFactor<<CS as UsesState>::State>,STGNodeMetadata>; MinimizerScheduler<CS, MaxTimeFavFactor<<CS as UsesState>::State>,STGNodeMetadata>;
// AI generated, human verified
fn count_occurrences<T>(vec: &Vec<T>) -> HashMap<&T, usize>
where
T: PartialEq + Eq + Hash + Clone,
{
let mut counts = HashMap::new();
if vec.is_empty() {
return counts;
}
let mut current_obj = &vec[0];
let mut current_count = 1;
for obj in vec.iter().skip(1) {
if obj == current_obj {
current_count += 1;
} else {
counts.insert(current_obj, current_count);
current_obj = obj;
current_count = 1;
}
}
// Insert the count of the last object
counts.insert(current_obj, current_count);
counts
}
//============================= Graph Feedback //============================= Graph Feedback
pub static mut STG_MAP: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE]; pub static mut STG_MAP: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE];
@ -274,7 +308,9 @@ pub struct StgFeedback
last_node_trace: Option<Vec<NodeIndex>>, last_node_trace: Option<Vec<NodeIndex>>,
last_edge_trace: Option<Vec<EdgeIndex>>, last_edge_trace: Option<Vec<EdgeIndex>>,
last_intervals: Option<Vec<ExecInterval>>, last_intervals: Option<Vec<ExecInterval>>,
last_abbs: Option<Vec<AtomicBasicBlock>>, last_abbs_hash: Option<u64>, // only set, if it was interesting
last_aggregate_hash: Option<u64>, // only set, if it was interesting
last_top_abb_hashes: Option<Vec<u64>>, // only set, if it was interesting
dump_path: Option<PathBuf> dump_path: Option<PathBuf>
} }
#[cfg(feature = "feed_stg")] #[cfg(feature = "feed_stg")]
@ -458,6 +494,7 @@ where
if INTEREST_AGGREGATE || INTEREST_ABBPATH { if INTEREST_AGGREGATE || INTEREST_ABBPATH {
if INTEREST_ABBPATH { if INTEREST_ABBPATH {
let h = get_generic_hash(&tmp); let h = get_generic_hash(&tmp);
self.last_abbs_hash = Some(h);
// order of execution is relevant // order of execution is relevant
if let Some(x) = feedbackstate.worst_observed_per_abb_path.get_mut(&h) { if let Some(x) = feedbackstate.worst_observed_per_abb_path.get_mut(&h) {
let t = clock_observer.last_runtime(); let t = clock_observer.last_runtime();
@ -474,6 +511,22 @@ where
// aggegation by sorting, order of states is not relevant // aggegation by sorting, order of states is not relevant
let mut _tmp = tmp.clone(); let mut _tmp = tmp.clone();
_tmp.sort(); _tmp.sort();
let counts = count_occurrences(&_tmp);
let mut top_indices = Vec::new();
for (k,c) in counts {
if let Some(reference) = feedbackstate.worst_abb_exec_count.get_mut(k) {
if *reference < c {
*reference = c;
top_indices.push(get_generic_hash(k));
}
} else {
top_indices.push(get_generic_hash(k));
feedbackstate.worst_abb_exec_count.insert(k.clone(), c);
}
}
self.last_top_abb_hashes = Some(top_indices);
self.last_aggregate_hash = Some(get_generic_hash(&_tmp));
if let Some(x) = feedbackstate.worst_observed_per_aggegated_path.get_mut(&_tmp) { if let Some(x) = feedbackstate.worst_observed_per_aggegated_path.get_mut(&_tmp) {
let t = clock_observer.last_runtime(); let t = clock_observer.last_runtime();
if t > *x { if t > *x {
@ -494,7 +547,6 @@ where
self.last_node_trace = Some(nodetrace); self.last_node_trace = Some(nodetrace);
self.last_edge_trace = Some(edgetrace); self.last_edge_trace = Some(edgetrace);
self.last_intervals = Some(observer.last_trace.clone()); self.last_intervals = Some(observer.last_trace.clone());
self.last_abbs = Some(tmp);
if let Some(dp) = &self.dump_path { if let Some(dp) = &self.dump_path {
if updated { if updated {
@ -516,9 +568,8 @@ where
fn append_metadata<OT>(&mut self, _state: &mut S, _observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> { fn append_metadata<OT>(&mut self, _state: &mut S, _observers: &OT, testcase: &mut Testcase<S::Input>) -> Result<(), Error> {
let nodes = self.last_node_trace.take(); let nodes = self.last_node_trace.take();
let edges = self.last_edge_trace.take(); let edges = self.last_edge_trace.take();
let abbs = self.last_abbs.take();
match nodes { match nodes {
Some(s) => testcase.metadata_map_mut().insert(STGNodeMetadata::new(s, edges.unwrap(), abbs.unwrap(), self.last_intervals.take().unwrap())), Some(s) => testcase.metadata_map_mut().insert(STGNodeMetadata::new(s, edges.unwrap(), self.last_abbs_hash.take().unwrap_or_default(), self.last_aggregate_hash.take().unwrap_or_default(), self.last_top_abb_hashes.take().unwrap_or_default(), self.last_intervals.take().unwrap())),
None => (), None => (),
} }
Ok(()) Ok(())

View File

@ -58,6 +58,15 @@ impl TopRatedsMetadata {
pub fn map(&self) -> &HashMap<usize, CorpusId> { pub fn map(&self) -> &HashMap<usize, CorpusId> {
&self.map &self.map
} }
/// Retruns the number of inices that are considered interesting
pub fn get_number(&self) -> usize {
let mut tmp = HashSet::new();
for i in self.map.values() {
tmp.insert(*i);
}
tmp.len()
}
} }
impl Default for TopRatedsMetadata { impl Default for TopRatedsMetadata {
@ -325,6 +334,7 @@ where
.map .map
.insert(elem, idx); .insert(elem, idx);
} }
println!("Number of interesting corpus elements: {}", state.metadata_map_mut().get::<TopRatedsMetadata>().unwrap().get_number());
Ok(()) Ok(())
} }