MinimizerCorpusScheduler skeleton
This commit is contained in:
parent
58841ed82e
commit
705196fe32
@ -1,225 +1,127 @@
|
|||||||
use alloc::{borrow::ToOwned, vec::Vec};
|
use core::marker::PhantomData;
|
||||||
use core::{cell::RefCell, iter::Iterator, marker::PhantomData};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
corpus::Corpus, corpus::HasTestcaseVec, corpus::Testcase, inputs::{HasLen, Input}, utils::Rand, Error,
|
corpus::{Corpus, CorpusScheduler, Testcase},
|
||||||
|
inputs::{HasLen, Input},
|
||||||
|
state::HasCorpus,
|
||||||
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait FavFactor: Serialize + serde::de::DeserializeOwned + 'static
|
pub trait FavFactor<I>
|
||||||
{
|
|
||||||
fn compute<I>(testcase: &Testcase<I>) -> Result<u64, Error>
|
|
||||||
where
|
|
||||||
I: Input;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LenTimeMulFavFactor {}
|
|
||||||
|
|
||||||
// TODO time as Duration and put len into Testcase
|
|
||||||
impl FavFactor for LenTimeMulFavFactor {
|
|
||||||
fn compute<I>(entry: &Testcase<I>) -> Result<u64, Error>
|
|
||||||
where
|
|
||||||
I: Input + HasLen
|
|
||||||
{
|
|
||||||
entry.exec_time().as_usec() * (entry.cached_len()? as u64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CorpusMinimizer {
|
|
||||||
fn update_score<C, I, R>(corpus: &mut C, idx: usize) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand;
|
|
||||||
|
|
||||||
fn cull<C, I, R>(corpus: &mut C) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FavCorpusMinimizer<F>
|
|
||||||
where
|
where
|
||||||
F: FavFactor
|
|
||||||
{
|
|
||||||
phantom: PhantomData<F>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<F> CorpusMinimizer for FavCorpusMinimizer<F>
|
|
||||||
where
|
|
||||||
F: FavFactor
|
|
||||||
{
|
|
||||||
fn update_score<C, I, R>(corpus: &mut C, idx: usize) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cull<C, I, R>(corpus: &mut C) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct NoveltiesMeta {
|
|
||||||
novelties: Vec<usize>,
|
|
||||||
}
|
|
||||||
// impl Iterator<Item = usize>
|
|
||||||
|
|
||||||
/// A Queue-like corpus, wrapping an existing Corpus instance
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
||||||
#[serde(bound = "I: serde::de::DeserializeOwned")]
|
|
||||||
pub struct MinSetCorpus<C, F, I, IT, R, T>
|
|
||||||
where
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
F: FavFactor,
|
|
||||||
I: Input,
|
I: Input,
|
||||||
IT: Iterator<Item = T>,
|
|
||||||
R: Rand,
|
|
||||||
{
|
{
|
||||||
corpus: C,
|
fn compute(testcase: &mut Testcase<I>) -> Result<u64, Error>;
|
||||||
pos: usize,
|
|
||||||
// TODO rebase minset on remove()
|
|
||||||
minset: HashSet<usize>,
|
|
||||||
top_rated: HashMap<T, usize>,
|
|
||||||
phantom: PhantomData<(F, I, IT, R)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, I, R> HasTestcaseVec<I> for MinSetCorpus<C, I, R>
|
pub struct LenTimeMulFavFactor<I>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
I: Input + HasLen,
|
||||||
I: Input,
|
|
||||||
R: Rand,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
phantom: PhantomData<I>,
|
||||||
fn entries(&self) -> &[RefCell<Testcase<I>>] {
|
}
|
||||||
self.corpus.entries()
|
|
||||||
}
|
impl<I> FavFactor<I> for LenTimeMulFavFactor<I>
|
||||||
#[inline]
|
where
|
||||||
fn entries_mut(&mut self) -> &mut Vec<RefCell<Testcase<I>>> {
|
I: Input + HasLen,
|
||||||
self.corpus.entries_mut()
|
{
|
||||||
|
fn compute(entry: &mut Testcase<I>) -> Result<u64, Error> {
|
||||||
|
Ok(entry.exec_time().map_or(1, |d| d.as_millis()) as u64 * entry.cached_len()? as u64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, I, R> Corpus<I, R> for MinSetCorpus<C, I, R>
|
pub struct MinimizerCorpusScheduler<C, CS, F, I, S>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
CS: CorpusScheduler<I, S>,
|
||||||
I: Input,
|
F: FavFactor<I>,
|
||||||
R: Rand,
|
I: Input,
|
||||||
|
S: HasCorpus<C, I>,
|
||||||
|
C: Corpus<I>
|
||||||
{
|
{
|
||||||
/// Returns the number of elements
|
base: CS,
|
||||||
#[inline]
|
phantom: PhantomData<(C, F, I, S)>,
|
||||||
fn count(&self) -> usize {
|
}
|
||||||
self.corpus.count()
|
|
||||||
|
impl<C, CS, F, I, S> CorpusScheduler<I, S> for MinimizerCorpusScheduler<C, CS, F, I, S>
|
||||||
|
where
|
||||||
|
CS: CorpusScheduler<I, S>,
|
||||||
|
F: FavFactor<I>,
|
||||||
|
I: Input,
|
||||||
|
S: HasCorpus<C, I>,
|
||||||
|
C: Corpus<I>
|
||||||
|
{
|
||||||
|
/// Add an entry to the corpus and return its index
|
||||||
|
fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> {
|
||||||
|
self.base.on_add(state, idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO change add to return Result
|
/// Replaces the testcase at the given idx
|
||||||
#[inline]
|
fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error> {
|
||||||
fn add(&mut self, entry: Testcase<I>) -> usize {
|
self.base.on_replace(state, idx, testcase)
|
||||||
let idx = self.corpus.add(entry);
|
|
||||||
self.update_score(idx).unwrap();
|
|
||||||
idx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes an entry from the corpus, returning it if it was present.
|
/// Removes an entry from the corpus, returning it if it was present.
|
||||||
#[inline]
|
fn on_remove(
|
||||||
fn remove(&mut self, entry: &Testcase<I>) -> Option<Testcase<I>> {
|
&self,
|
||||||
self.corpus.remove(entry)
|
state: &mut S,
|
||||||
}
|
idx: usize,
|
||||||
|
testcase: &Option<Testcase<I>>,
|
||||||
/// Gets a random entry
|
) -> Result<(), Error> {
|
||||||
#[inline]
|
self.base.on_remove(state, idx, testcase)
|
||||||
fn random_entry(&self, rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), Error> {
|
|
||||||
self.corpus.random_entry(rand)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the testacase we currently use
|
|
||||||
#[inline]
|
|
||||||
fn current_testcase(&self) -> (&RefCell<Testcase<I>>, usize) {
|
|
||||||
(self.get(self.pos - 1), self.pos - 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: IntoIter
|
||||||
/// Gets the next entry
|
/// Gets the next entry
|
||||||
#[inline]
|
fn next(&self, state: &mut S) -> Result<usize, Error> {
|
||||||
fn next(&mut self, _rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), Error> {
|
self.base.next(state)
|
||||||
self.cull();
|
|
||||||
self.pos += 1;
|
|
||||||
if self.corpus.count() == 0 {
|
|
||||||
return Err(Error::Empty("Corpus".to_owned()));
|
|
||||||
}
|
|
||||||
if self.pos > self.corpus.count() {
|
|
||||||
// TODO: Always loop or return informational error?
|
|
||||||
self.pos = 1;
|
|
||||||
self.cycles += 1;
|
|
||||||
}
|
|
||||||
Ok((&self.corpus.entries()[self.pos - 1], self.pos - 1))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, I, R> MinSetCorpus<C, I, R>
|
impl<C, CS, F, I, S> MinimizerCorpusScheduler<C, CS, F, I, S>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
CS: CorpusScheduler<I, S>,
|
||||||
|
F: FavFactor<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
R: Rand,
|
S: HasCorpus<C, I>,
|
||||||
|
C: Corpus<I>
|
||||||
{
|
{
|
||||||
pub fn new(corpus: C) -> Self {
|
/*pub fn update_score(&self, state: &mut S, idx: usize) -> Result<(), Error> {
|
||||||
Self {
|
let entry = state.corpus().get(idx)?.borrow_mut();
|
||||||
corpus: corpus,
|
let factor = F::compute(&mut *entry)?;
|
||||||
phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn corpus(&self) -> &C {
|
|
||||||
&self.corpus
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn corpus_mut(&mut self) -> &mut C {
|
|
||||||
&mut self.corpus
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO move this functions and top rated to another struct
|
|
||||||
// create something like MinSetCorpus<.., FavMinimizer<LenTimeMulFavFactor>>
|
|
||||||
|
|
||||||
pub fn update_score(&mut self, idx: usize) -> Result<(), Error> {
|
|
||||||
let factor = F::compute(self.entries()[idx].borrow())?;
|
|
||||||
for elem in entry.get::<IT>() {
|
for elem in entry.get::<IT>() {
|
||||||
if let val = self.top_rated.get_mut(elem) {
|
if let val = self.top_rated.get_mut(elem) {
|
||||||
if factor > F::compute(self.entries()[val].borrow())? {
|
if factor > F::compute(self.entries()[val].borrow())? {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = self.top_rated.insert(elem, idx);
|
let _ = self.top_rated.insert(elem, idx);
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
pub fn cull(&mut self) {
|
|
||||||
let mut acc = HashSet::new();
|
|
||||||
self.minset.clear();
|
|
||||||
|
|
||||||
for key in self.top_rated.keys() {
|
pub fn new(base: CS) -> Self {
|
||||||
if !acc.contains(key) {
|
Self {
|
||||||
let idx = self.top_rated.get(key).unwrap();
|
base: base,
|
||||||
let entry = self.entries()[idx].borrow();
|
phantom: PhantomData,
|
||||||
for elem in entry.get::<IT>() {
|
|
||||||
acc.insert(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.minset.insert(idx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub fn cull(&mut self) {
|
||||||
|
let mut acc = HashSet::new();
|
||||||
|
self.minset.clear();
|
||||||
|
|
||||||
|
for key in self.top_rated.keys() {
|
||||||
|
if !acc.contains(key) {
|
||||||
|
let idx = self.top_rated.get(key).unwrap();
|
||||||
|
let entry = self.entries()[idx].borrow();
|
||||||
|
for elem in entry.get::<IT>() {
|
||||||
|
acc.insert(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.minset.insert(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
@ -14,6 +14,7 @@ pub use ondisk::OnDiskCorpus;
|
|||||||
pub mod queue;
|
pub mod queue;
|
||||||
pub use queue::QueueCorpusScheduler;
|
pub use queue::QueueCorpusScheduler;
|
||||||
|
|
||||||
|
pub mod minset;
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
@ -56,7 +57,7 @@ where
|
|||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
/// Add an entry to the corpus and return its index
|
/// Add an entry to the corpus and return its index
|
||||||
fn on_add(&self, _state: &mut S, _idx: usize, _testcase: &Testcase<I>) -> Result<(), Error> {
|
fn on_add(&self, _state: &mut S, _idx: usize) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ where
|
|||||||
/// Time needed to execute the input
|
/// Time needed to execute the input
|
||||||
exec_time: Option<Duration>,
|
exec_time: Option<Duration>,
|
||||||
/// Cached len of the input, if any
|
/// Cached len of the input, if any
|
||||||
cached_len: Option<usize>
|
cached_len: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Impl of a testcase
|
/// Impl of a testcase
|
||||||
@ -135,6 +135,16 @@ where
|
|||||||
self.metadatas.insert(meta);
|
self.metadatas.insert(meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the execution time of the testcase
|
||||||
|
pub fn exec_time(&self) -> &Option<Duration> {
|
||||||
|
&self.exec_time
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the execution time of the testcase (mut)
|
||||||
|
pub fn exec_time_mut(&mut self) -> &mut Option<Duration> {
|
||||||
|
&mut self.exec_time
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new Testcase instace given an input
|
/// Create a new Testcase instace given an input
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new<T>(input: T) -> Self
|
pub fn new<T>(input: T) -> Self
|
||||||
@ -147,7 +157,7 @@ where
|
|||||||
fitness: 0,
|
fitness: 0,
|
||||||
metadatas: SerdeAnyMap::new(),
|
metadatas: SerdeAnyMap::new(),
|
||||||
exec_time: None,
|
exec_time: None,
|
||||||
cached_len: None
|
cached_len: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +170,7 @@ where
|
|||||||
fitness: 0,
|
fitness: 0,
|
||||||
metadatas: SerdeAnyMap::new(),
|
metadatas: SerdeAnyMap::new(),
|
||||||
exec_time: None,
|
exec_time: None,
|
||||||
cached_len: None
|
cached_len: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,7 +183,7 @@ where
|
|||||||
fitness: fitness,
|
fitness: fitness,
|
||||||
metadatas: SerdeAnyMap::new(),
|
metadatas: SerdeAnyMap::new(),
|
||||||
exec_time: None,
|
exec_time: None,
|
||||||
cached_len: None
|
cached_len: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +195,7 @@ where
|
|||||||
fitness: 0,
|
fitness: 0,
|
||||||
metadatas: SerdeAnyMap::new(),
|
metadatas: SerdeAnyMap::new(),
|
||||||
exec_time: None,
|
exec_time: None,
|
||||||
cached_len: None
|
cached_len: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,17 +213,15 @@ where
|
|||||||
let l = i.len();
|
let l = i.len();
|
||||||
self.cached_len = Some(l);
|
self.cached_len = Some(l);
|
||||||
l
|
l
|
||||||
},
|
|
||||||
None => {
|
|
||||||
match self.cached_len {
|
|
||||||
Some(l) => l,
|
|
||||||
None => {
|
|
||||||
let l = self.load_input()?.len();
|
|
||||||
self.cached_len = Some(l);
|
|
||||||
l
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
None => match self.cached_len {
|
||||||
|
Some(l) => l,
|
||||||
|
None => {
|
||||||
|
let l = self.load_input()?.len();
|
||||||
|
self.cached_len = Some(l);
|
||||||
|
l
|
||||||
|
}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user