profile woets

This commit is contained in:
Alwin Berger 2025-02-18 16:27:53 +01:00
parent 64d1151e96
commit bbf99eca8b
4 changed files with 83 additions and 35 deletions

View File

@ -141,8 +141,8 @@ rule run_bench:
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1
mkdir -p $(dirname {output[0]}) mkdir -p $(dirname {output[0]})
set +e set +e
echo $(pwd)/{input[1]}/release/fret -n $(pwd)/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num} -s {select_task} -t -a -g -k {input[0]} -c ./target_symbols.csv fuzz --random -t {RUNTIME} -s {wildcards.num} echo $(pwd)/{input[1]}/release/fret -n $(pwd)/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num} -s {select_task} -t -a -r -g -k {input[0]} -c ./target_symbols.csv fuzz --random -t {RUNTIME} -s {wildcards.num}
$(pwd)/{input[1]}/release/fret -n $(pwd)/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num} -s {select_task} -t -a -g -k {input[0]} -c ./target_symbols.csv fuzz --random -t {RUNTIME} -s {wildcards.num} > {output[1]} 2>&1 $(pwd)/{input[1]}/release/fret -n $(pwd)/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num} -s {select_task} -t -a -r -g -k {input[0]} -c ./target_symbols.csv fuzz --random -t {RUNTIME} -s {wildcards.num} > {output[1]} 2>&1
exit 0 exit 0
""" """
else: else:
@ -150,8 +150,8 @@ rule run_bench:
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1
mkdir -p $(dirname {output[0]}) mkdir -p $(dirname {output[0]})
set +e set +e
echo $(pwd)/{input[1]}/release/fret -n $(pwd)/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num} -s {select_task} -t -a -g -k {input[0]} -c ./target_symbols.csv fuzz -t {RUNTIME} -s {wildcards.num} echo $(pwd)/{input[1]}/release/fret -n $(pwd)/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num} -s {select_task} -t -a -r -g -k {input[0]} -c ./target_symbols.csv fuzz -t {RUNTIME} -s {wildcards.num}
$(pwd)/{input[1]}/release/fret -n $(pwd)/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num} -s {select_task} -t -a -g -k {input[0]} -c ./target_symbols.csv fuzz -t {RUNTIME} -s {wildcards.num} > {output[1]} 2>&1 $(pwd)/{input[1]}/release/fret -n $(pwd)/timedump/{wildcards.fuzzer}/{wildcards.target}#{wildcards.num} -s {select_task} -t -a -r -g -k {input[0]} -c ./target_symbols.csv fuzz -t {RUNTIME} -s {wildcards.num} > {output[1]} 2>&1
exit 0 exit 0
""" """
shell(script) shell(script)

View File

@ -56,11 +56,11 @@ where
where { where {
match &self.dumpfile { match &self.dumpfile {
Some(s) => { Some(s) => {
let time_has_come = self.last_dump.map(|t| Instant::now()-t > Duration::from_secs(60)).unwrap_or(true); let time_has_come = self.last_dump.map(|t| Instant::now()-t > Duration::from_secs(1200)).unwrap_or(true);
if time_has_come { if time_has_come {
self.last_dump = Some(Instant::now()); self.last_dump = Some(Instant::now());
// Try dumping the worst case // Try dumping the worst case
let casename = s.with_extension(format!("at_{}h.case", (Instant::now()-self.init_time).as_secs()/60)); let casename = s.with_extension(format!("at_{}h.case", (Instant::now()-self.init_time).as_secs()/3600));
let corpus = state.corpus(); let corpus = state.corpus();
let mut worst = Duration::new(0,0); let mut worst = Duration::new(0,0);
let mut worst_input = None; let mut worst_input = None;

View File

@ -1,10 +1,13 @@
use hashbrown::HashMap; use hashbrown::HashMap;
use libafl_bolts::prelude::{SerdeAny, SerdeAnyMap}; use libafl_bolts::prelude::{SerdeAny, SerdeAnyMap};
use libafl_qemu::{elf::EasyElf, read_user_reg_unchecked, GuestAddr, GuestPhysAddr}; use libafl_qemu::{elf::EasyElf, read_user_reg_unchecked, GuestAddr, GuestPhysAddr};
use std::ops::Range;
use std::cmp::min; use std::cmp::min;
use std::ops::Range;
use crate::{fuzzer::{DO_NUM_INTERRUPT, FIRST_INT}, time::clock::QEMU_ISNS_PER_USEC}; use crate::{
fuzzer::{DO_NUM_INTERRUPT, FIRST_INT},
time::clock::QEMU_ISNS_PER_USEC,
};
use super::ExecInterval; use super::ExecInterval;
@ -99,39 +102,47 @@ pub fn get_icount(emulator: &libafl_qemu::Qemu) -> u64 {
} }
} }
pub fn input_bytes_to_interrupt_times(buf: &[u8], config: (usize,u32)) -> Vec<u32> { pub fn input_bytes_to_interrupt_times(buf: &[u8], config: (usize, u32)) -> Vec<u32> {
let len = buf.len(); let len = buf.len();
let mut start_tick; let mut start_tick;
let mut ret = Vec::with_capacity(min(DO_NUM_INTERRUPT, len/4)); let mut ret = Vec::with_capacity(min(DO_NUM_INTERRUPT, len / 4));
for i in 0..DO_NUM_INTERRUPT { for i in 0..DO_NUM_INTERRUPT {
let mut buf4b : [u8; 4] = [0,0,0,0]; let mut buf4b: [u8; 4] = [0, 0, 0, 0];
if len >= (i+1)*4 { if len >= (i + 1) * 4 {
for j in 0usize..4usize { for j in 0usize..4usize {
buf4b[j]=buf[i*4+j]; buf4b[j] = buf[i * 4 + j];
} }
start_tick = u32::from_le_bytes(buf4b); start_tick = u32::from_le_bytes(buf4b);
if start_tick < FIRST_INT {start_tick=0;} if start_tick < FIRST_INT {
start_tick = 0;
}
ret.push(start_tick); ret.push(start_tick);
} else {break;} } else {
break;
}
} }
ret.sort_unstable(); ret.sort_unstable();
// obey the minimum inter arrival time while maintaining the sort // obey the minimum inter arrival time while maintaining the sort
for i in 0..ret.len() { for i in 0..ret.len() {
if ret[i]==0 {continue;} if ret[i] == 0 {
for j in i+1..ret.len() { continue;
if ret[j]-ret[i] < config.1 * QEMU_ISNS_PER_USEC { }
for j in i + 1..ret.len() {
if ret[j] - ret[i] < config.1 * QEMU_ISNS_PER_USEC {
// ret[j] = u32::saturating_add(ret[i],config.1 * QEMU_ISNS_PER_USEC); // ret[j] = u32::saturating_add(ret[i],config.1 * QEMU_ISNS_PER_USEC);
ret[j] = 0; // remove the interrupt ret[j] = 0; // remove the interrupt
ret.sort_unstable(); ret.sort_unstable();
break; break;
} else {break;} } else {
break;
}
} }
} }
ret ret
} }
pub fn interrupt_times_to_input_bytes(interrupt_times: &[u32]) -> Vec<u8> { pub fn interrupt_times_to_input_bytes(interrupt_times: &[u32]) -> Vec<u8> {
let mut ret = Vec::with_capacity(interrupt_times.len()*4); let mut ret = Vec::with_capacity(interrupt_times.len() * 4);
for i in interrupt_times { for i in interrupt_times {
ret.extend(u32::to_le_bytes(*i)); ret.extend(u32::to_le_bytes(*i));
} }
@ -178,21 +189,57 @@ where
} }
} }
/// Build an ABB-profile from a stretch of intervals /// Build an ABB-profile from a stretch of intervals
/// returns mapping: task_name -> (abb_addr -> (interval_count, exec_count, exec_time)) /// returns mapping: task_name -> (abb_addr -> (interval_count, exec_count, exec_time, woet))
#[allow(unused)] #[allow(unused)]
pub fn abb_profile( pub fn abb_profile(
mut intervals: Vec<ExecInterval>, mut intervals: Vec<ExecInterval>,
) -> HashMap<String, HashMap<u32, (usize, usize, u64)>> { ) -> HashMap<String, HashMap<u32, (usize, usize, u64, u64)>> {
let mut ret: HashMap<String, HashMap<u32, (usize, usize, u64)>> = HashMap::new(); let mut ret: HashMap<String, HashMap<u32, (usize, usize, u64, u64)>> = HashMap::new();
intervals.sort_by_key(|x| x.get_task_name_unchecked()); intervals.sort_by_key(|x| x.get_task_name_unchecked());
intervals intervals
.chunk_by_mut(|x, y| x.get_task_name_unchecked() == y.get_task_name_unchecked()) .chunk_by_mut(|x, y| x.get_task_name_unchecked() == y.get_task_name_unchecked())
.for_each(|x| { // Iterate over all tasks
x.sort_by_key(|y| y.abb.as_ref().unwrap().start); .for_each(|intv_of_task| {
x.chunk_by(|y, z| y.abb.as_ref().unwrap().start == z.abb.as_ref().unwrap().start) // Iterate over all intervals of this task
.for_each(|y| match ret.get_mut(&y[0].get_task_name_unchecked()) { intv_of_task.sort_by_key(|y| y.abb.as_ref().unwrap().start);
// Iterate over each abb of this task
let mut inter_per_abb_of_task: Vec<&mut [ExecInterval]> = intv_of_task
.chunk_by_mut(|y, z| y.abb.as_ref().unwrap().start == z.abb.as_ref().unwrap().start)
.collect();
// arrange the abbs by their start address
inter_per_abb_of_task
.iter_mut()
.for_each(|ivs_of_abb_of_task| {
ivs_of_abb_of_task.sort_by_key(|y| y.abb.as_ref().unwrap().instance_id)
});
// find the woet for this abb
let abb_woet: HashMap<GuestAddr, u64> = inter_per_abb_of_task
.iter()
.map(|ivs_of_abb_of_task| {
// group intervals by id, sum up the exec time of the abb instance
ivs_of_abb_of_task
.chunk_by(
|y, z| {
y.abb.as_ref().unwrap().instance_id
== z.abb.as_ref().unwrap().instance_id
},
)
.map(|intv_of_abb_with_id| {
(
intv_of_abb_with_id[0].abb.as_ref().unwrap().start,
intv_of_abb_with_id
.iter()
.map(|z| z.get_exec_time())
.sum::<_>(),
)
})
.max_by_key(|x| x.1)
.unwrap()
})
.collect();
inter_per_abb_of_task.into_iter().for_each(|y| {
match ret.get_mut(&y[0].get_task_name_unchecked()) {
Option::None => { Option::None => {
ret.insert( ret.insert(
y[0].get_task_name_unchecked(), y[0].get_task_name_unchecked(),
@ -202,6 +249,7 @@ pub fn abb_profile(
y.len(), y.len(),
y.iter().filter(|x| x.is_abb_end()).count(), y.iter().filter(|x| x.is_abb_end()).count(),
y.iter().map(|z| z.get_exec_time()).sum::<_>(), y.iter().map(|z| z.get_exec_time()).sum::<_>(),
abb_woet[&y[0].abb.as_ref().unwrap().start],
), ),
)]), )]),
); );
@ -213,15 +261,16 @@ pub fn abb_profile(
y.len(), y.len(),
y.iter().filter(|x| x.is_abb_end()).count(), y.iter().filter(|x| x.is_abb_end()).count(),
y.iter().map(|z| z.get_exec_time()).sum(), y.iter().map(|z| z.get_exec_time()).sum(),
abb_woet[&y[0].abb.as_ref().unwrap().start],
), ),
); );
} }
}); }
});
}); });
ret ret
} }
pub fn unmut<T>(x: &mut T) -> &T { pub fn unmut<T>(x: &mut T) -> &T {
&(*x) &(*x)
} }

View File

@ -77,16 +77,15 @@ pub trait SystemTraceData: Serialize + Sized + for<'a> Deserialize<'a> + Default
#[inline] #[inline]
/// extract computation time spent in each task and abb /// extract computation time spent in each task and abb
/// task_name -> (abb_addr -> (interval_count, exec_count, exec_time)) /// task_name -> (abb_addr -> (interval_count, exec_count, exec_time, woet))
fn select_abb_profile( fn select_abb_profile(
&self, &self,
select_task: Option<String>, select_task: Option<String>,
) -> HashMap<String, HashMap<u32, (usize, usize, u64)>> { ) -> HashMap<String, HashMap<u32, (usize, usize, u64, u64)>> {
if let Some(select_task) = select_task.as_ref() { if let Some(select_task) = select_task.as_ref() {
// Task selected, only profile this task // Task selected, only profile this task
if let Some(worst_instance) = self let wjptybrt = self.worst_jobs_per_task_by_response_time();
.worst_jobs_per_task_by_response_time() if let Some(worst_instance) = wjptybrt.get(select_task)
.get(select_task)
{ {
let t: Vec<_> = self let t: Vec<_> = self
.intervals() .intervals()