use serde::{Deserialize, Serialize};
use serde::{Deserializer, Serializer};
use std::sync::{Arc, RwLock};
use std::thread::{sleep, spawn};
use std::time::{Duration, Instant};
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct Stats {
pub title: String,
pub total_executions: u64,
pub started: Option<SerializableInstant>,
pub executions_per_second: ExecsPerSecond,
pub last_healt_check: Option<SerializableInstant>,
pub running: bool,
pub cylcles_done: usize,
pub last_new_path: Option<SerializableInstant>,
pub last_unique_crash: Option<SerializableInstant>,
pub total_crashes: usize,
pub total_unique_responses: usize,
pub corpus_count: usize,
pub total_timeouts: usize,
pub backoff_time: u64,
}
const BUCKET_SIZE: usize = 10;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ExecsPerSecond {
time_started: SerializableInstant,
counter: [usize; BUCKET_SIZE],
last_bucket_id: usize,
}
impl Default for ExecsPerSecond {
fn default() -> Self {
Self {
time_started: SerializableInstant::now(),
counter: Default::default(),
last_bucket_id: 0,
}
}
}
impl ExecsPerSecond {
pub(crate) fn get(&self) -> usize {
self.counter.iter().sum()
}
pub(crate) fn clear(&mut self) {
self.counter = Default::default();
}
pub(crate) fn start(stats: Arc<RwLock<Stats>>) {
spawn(move || {
loop {
if let Ok(mut stats) = stats.write() {
if !stats.running {
break;
}
stats.executions_per_second.reseter();
}
sleep(Duration::from_millis((1000 / BUCKET_SIZE / 2) as u64));
}
});
}
fn reseter(&mut self) {
let bucked_id =
self.time_started.elapsed().as_millis() as usize % 1000 / (1000 / BUCKET_SIZE);
if self.last_bucket_id == bucked_id {
} else {
self.counter[bucked_id] = 0;
self.last_bucket_id = bucked_id;
}
}
pub(crate) fn add(&mut self) {
let bucked_id =
self.time_started.elapsed().as_millis() as usize % 1000 / (1000 / BUCKET_SIZE);
self.counter[bucked_id] += 1;
}
}
pub type StatsType = Arc<RwLock<Stats>>;
#[derive(Debug, Clone, Copy)]
pub struct SerializableInstant(Instant);
impl Default for SerializableInstant {
fn default() -> Self {
Self(Instant::now())
}
}
impl SerializableInstant {
fn new(instant: Instant) -> Self {
Self(instant)
}
#[must_use]
pub fn now() -> Self {
Self(Instant::now())
}
#[must_use]
pub fn into_inner(self) -> Instant {
self.0
}
}
impl Serialize for SerializableInstant {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u128(self.0.elapsed().as_nanos())
}
}
impl<'de> Deserialize<'de> for SerializableInstant {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let nanos = u128::deserialize(deserializer)?;
#[allow(clippy::cast_possible_truncation)]
if let Some(ok) = Instant::now().checked_sub(std::time::Duration::from_nanos(nanos as u64))
{
Ok(SerializableInstant::new(ok))
} else {
Ok(SerializableInstant::now())
}
}
}
impl std::ops::Deref for SerializableInstant {
type Target = Instant;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for SerializableInstant {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl From<Instant> for SerializableInstant {
fn from(instant: Instant) -> Self {
SerializableInstant(instant)
}
}
impl From<SerializableInstant> for Instant {
fn from(serializable: SerializableInstant) -> Self {
serializable.0
}
}