use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::{marker::PhantomData, time::Duration};
use serde::{Deserialize, Serialize};
use crate::{
corpus::{Corpus, CorpusId, SchedulerTestcaseMetaData},
inputs::UsesInput,
schedulers::Scheduler,
state::{HasCorpus, HasMetadata, UsesState},
Error,
};
pub const N_FUZZ_SIZE: usize = 1 << 21;
crate::impl_serdeany!(SchedulerMetadata);
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SchedulerMetadata {
strat: Option<PowerSchedule>,
exec_time: Duration,
cycles: u64,
bitmap_size: u64,
bitmap_size_log: f64,
bitmap_entries: u64,
queue_cycles: u64,
n_fuzz: Vec<u32>,
}
impl SchedulerMetadata {
#[must_use]
pub fn new(strat: Option<PowerSchedule>) -> Self {
Self {
strat,
exec_time: Duration::from_millis(0),
cycles: 0,
bitmap_size: 0,
bitmap_size_log: 0.0,
bitmap_entries: 0,
queue_cycles: 0,
n_fuzz: vec![0; N_FUZZ_SIZE],
}
}
#[must_use]
pub fn strat(&self) -> Option<PowerSchedule> {
self.strat
}
#[must_use]
pub fn exec_time(&self) -> Duration {
self.exec_time
}
pub fn set_exec_time(&mut self, time: Duration) {
self.exec_time = time;
}
#[must_use]
pub fn cycles(&self) -> u64 {
self.cycles
}
pub fn set_cycles(&mut self, val: u64) {
self.cycles = val;
}
#[must_use]
pub fn bitmap_size(&self) -> u64 {
self.bitmap_size
}
pub fn set_bitmap_size(&mut self, val: u64) {
self.bitmap_size = val;
}
#[must_use]
pub fn bitmap_size_log(&self) -> f64 {
self.bitmap_size_log
}
pub fn set_bitmap_size_log(&mut self, val: f64) {
self.bitmap_size_log = val;
}
#[must_use]
pub fn bitmap_entries(&self) -> u64 {
self.bitmap_entries
}
pub fn set_bitmap_entries(&mut self, val: u64) {
self.bitmap_entries = val;
}
#[must_use]
pub fn queue_cycles(&self) -> u64 {
self.queue_cycles
}
pub fn set_queue_cycles(&mut self, val: u64) {
self.queue_cycles = val;
}
#[must_use]
pub fn n_fuzz(&self) -> &[u32] {
&self.n_fuzz
}
#[must_use]
pub fn n_fuzz_mut(&mut self) -> &mut [u32] {
&mut self.n_fuzz
}
}
#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
pub enum PowerSchedule {
EXPLORE,
EXPLOIT,
FAST,
COE,
LIN,
QUAD,
}
#[derive(Clone, Debug)]
pub struct PowerQueueScheduler<S> {
strat: PowerSchedule,
phantom: PhantomData<S>,
}
impl<S> UsesState for PowerQueueScheduler<S>
where
S: UsesInput,
{
type State = S;
}
impl<S> Scheduler for PowerQueueScheduler<S>
where
S: HasCorpus + HasMetadata,
{
fn on_add(&self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
if !state.has_metadata::<SchedulerMetadata>() {
state.add_metadata::<SchedulerMetadata>(SchedulerMetadata::new(Some(self.strat)));
}
let current_idx = *state.corpus().current();
let mut depth = match current_idx {
Some(parent_idx) => state
.corpus()
.get(parent_idx)?
.borrow_mut()
.metadata_mut()
.get_mut::<SchedulerTestcaseMetaData>()
.ok_or_else(|| {
Error::key_not_found("SchedulerTestcaseMetaData not found".to_string())
})?
.depth(),
None => 0,
};
depth += 1;
state
.corpus()
.get(idx)?
.borrow_mut()
.add_metadata(SchedulerTestcaseMetaData::new(depth));
Ok(())
}
fn next(&self, state: &mut Self::State) -> Result<CorpusId, Error> {
if state.corpus().count() == 0 {
Err(Error::empty(String::from("No entries in corpus")))
} else {
let id = match state.corpus().current() {
Some(cur) => {
if let Some(next) = state.corpus().next(*cur) {
next
} else {
let psmeta = state
.metadata_mut()
.get_mut::<SchedulerMetadata>()
.ok_or_else(|| {
Error::key_not_found("SchedulerMetadata not found".to_string())
})?;
psmeta.set_queue_cycles(psmeta.queue_cycles() + 1);
state.corpus().first().unwrap()
}
}
None => state.corpus().first().unwrap(),
};
*state.corpus_mut().current_mut() = Some(id);
let mut testcase = state.corpus().get(id)?.borrow_mut();
let tcmeta = testcase
.metadata_mut()
.get_mut::<SchedulerTestcaseMetaData>()
.ok_or_else(|| {
Error::key_not_found("SchedulerTestcaseMetaData not found".to_string())
})?;
if tcmeta.handicap() >= 4 {
tcmeta.set_handicap(tcmeta.handicap() - 4);
} else if tcmeta.handicap() > 0 {
tcmeta.set_handicap(tcmeta.handicap() - 1);
}
Ok(id)
}
}
}
impl<S> PowerQueueScheduler<S> {
#[must_use]
pub fn new(strat: PowerSchedule) -> Self {
PowerQueueScheduler {
strat,
phantom: PhantomData,
}
}
}