mod chunk_collector_store;
mod instance_set;
pub use chunk_collector_store::*;
pub use instance_set::*;
use arc_swap::ArcSwap;
use proofman_fields::PrimeField64;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex, PoisonError, RwLock,
};
use zisk_common::{
io::ZiskStdin, BusDevice, EmuTrace, ExecutorStatsHandle, InstanceType, Stats,
ZiskExecutorSummary,
};
use zisk_core::ZiskRom;
use crate::error::{ExecutorError, ExecutorResult, RwLockExt};
pub type ChunkCollector = (usize, Box<dyn BusDevice<u64>>);
pub struct ExecutionState<F: PrimeField64> {
pub zisk_rom: RwLock<Option<Arc<ZiskRom>>>,
pub stdin: ArcSwap<ZiskStdin>,
pub min_traces: Arc<RwLock<Option<Vec<Arc<EmuTrace>>>>>,
pub instance_set: Arc<InstanceSet<F>>,
pub collector_store: Arc<ChunkCollectorStore>,
pub execution_result: Mutex<ZiskExecutorSummary>,
pub stats: ExecutorStatsHandle,
pub use_hints: AtomicBool,
}
impl<F: PrimeField64> ExecutionState<F> {
pub fn new() -> Self {
Self {
zisk_rom: RwLock::new(None),
stdin: ArcSwap::from_pointee(ZiskStdin::new()),
min_traces: Arc::new(RwLock::new(None)),
instance_set: Arc::new(InstanceSet::new()),
collector_store: Arc::new(ChunkCollectorStore::new()),
execution_result: Mutex::new(ZiskExecutorSummary::default()),
stats: ExecutorStatsHandle::new(),
use_hints: AtomicBool::new(false),
}
}
pub fn set_rom(&self, rom: Arc<ZiskRom>, use_hints: bool) {
*self.zisk_rom.write().unwrap() = Some(rom);
self.use_hints.store(use_hints, Ordering::SeqCst);
}
pub fn get_rom(&self) -> ExecutorResult<Arc<ZiskRom>> {
let guard = self.zisk_rom.read_or_poison("rom")?;
guard.as_ref().cloned().ok_or(ExecutorError::RomNotInitialized)
}
pub fn set_stdin(&self, stdin: ZiskStdin) {
self.stdin.store(Arc::new(stdin));
}
pub fn get_stdin(&self) -> Arc<ZiskStdin> {
self.stdin.load_full()
}
pub fn reset(&self) {
*self.execution_result.lock().unwrap_or_else(PoisonError::into_inner) =
ZiskExecutorSummary::default();
*self.min_traces.write().unwrap_or_else(PoisonError::into_inner) = None;
self.instance_set.reset();
self.collector_store.reset();
self.stats.reset();
}
pub fn get_execution_result(&self) -> ZiskExecutorSummary {
self.execution_result.lock().unwrap().clone()
}
pub fn set_execution_result(&self, result: ZiskExecutorSummary) {
*self.execution_result.lock().unwrap() = result;
}
pub fn get_stats(&self) -> ExecutorStatsHandle {
self.stats.clone()
}
#[allow(clippy::type_complexity)]
pub(super) fn take_collectors_for_instance(
&self,
global_id: usize,
instance_type: InstanceType,
) -> ExecutorResult<Vec<(usize, Box<dyn BusDevice<u64>>)>> {
match instance_type {
InstanceType::Instance => {
let mut guard = self.collector_store.inner.write_or_poison("collector_store")?;
let collectors =
guard.remove(&global_id).ok_or(ExecutorError::MissingIndexEntry {
global_id,
index: "collector_store",
})?;
collectors
.into_iter()
.enumerate()
.map(|(idx, opt)| {
opt.ok_or_else(|| {
ExecutorError::Internal(format!(
"collector at index {idx} for global_id {global_id} is None"
))
})
})
.collect::<ExecutorResult<Vec<_>>>()
}
InstanceType::Table => Ok(vec![]),
}
}
pub(crate) fn register_empty_collector(
&self,
global_id: usize,
airgroup_id: usize,
air_id: usize,
) -> ExecutorResult<()> {
let stats = Stats::new_no_collection(airgroup_id, air_id);
self.collector_store
.inner
.write_or_poison("collector_store")?
.insert(global_id, Vec::new());
self.stats.insert_witness_stats(global_id, stats);
Ok(())
}
}
impl<F: PrimeField64> Default for ExecutionState<F> {
fn default() -> Self {
Self::new()
}
}