From c632e5d570d4763e8e18d764e95b7a9e515ebf99 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Wed, 4 Feb 2026 15:20:13 -0800 Subject: [PATCH] speed up simulation by optimizing SimulationImpl::read_traces this makes cpu/crates/cpu/tests/next_pc.rs take 56s instead of 168s --- crates/fayalite/src/sim.rs | 13 ++++------- crates/fayalite/src/util.rs | 2 +- crates/fayalite/src/util/misc.rs | 40 ++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index a59a4c7..002161e 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -40,7 +40,7 @@ use crate::{ OpaqueSimValue, OpaqueSimValueSize, OpaqueSimValueSizeRange, OpaqueSimValueSlice, OpaqueSimValueWriter, }, - util::{BitSliceWriteWithBase, DebugAsDisplay, HashMap, HashSet}, + util::{BitSliceWriteWithBase, DebugAsDisplay, HashMap, HashSet, copy_le_bytes_to_bitslice}, }; use bitvec::{bits, order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView}; use num_bigint::BigInt; @@ -2198,14 +2198,11 @@ impl SimulationImpl { SimTraceKind::BigUInt { index, ty: _ } | SimTraceKind::BigSInt { index, ty: _ } => { let state = state.unwrap_bits_mut(); let bigint = &self.state.big_slots[index]; - let mut bytes = bigint.to_signed_bytes_le(); - bytes.resize( - state.len().div_ceil(8), - if bigint.is_negative() { 0xFF } else { 0 }, + copy_le_bytes_to_bitslice( + state, + &bigint.to_signed_bytes_le(), + bigint.is_negative(), ); - let bitslice = BitSlice::::from_slice(&bytes); - let bitslice = &bitslice[..state.len()]; - state.clone_from_bitslice(bitslice); } SimTraceKind::BigBool { index } | SimTraceKind::BigAsyncReset { index } diff --git a/crates/fayalite/src/util.rs b/crates/fayalite/src/util.rs index 9796488..f1457de 100644 --- a/crates/fayalite/src/util.rs +++ b/crates/fayalite/src/util.rs @@ -41,7 +41,7 @@ pub use misc::{ os_str_strip_suffix, serialize_to_json_ascii, serialize_to_json_ascii_pretty, serialize_to_json_ascii_pretty_with_indent, slice_range, try_slice_range, }; -pub(crate) use misc::{InternedStrCompareAsStr, chain}; +pub(crate) use misc::{InternedStrCompareAsStr, chain, copy_le_bytes_to_bitslice}; pub mod job_server; pub mod prefix_sum; diff --git a/crates/fayalite/src/util/misc.rs b/crates/fayalite/src/util/misc.rs index 165ab3a..8879a8d 100644 --- a/crates/fayalite/src/util/misc.rs +++ b/crates/fayalite/src/util/misc.rs @@ -612,3 +612,43 @@ impl std::borrow::Borrow for InternedStrCompareAsStr { &self.0 } } + +pub(crate) fn copy_le_bytes_to_bitslice( + dest: &mut BitSlice, + bytes: &[u8], + msb_fill: bool, +) { + let (chunks, remainder) = bytes.as_chunks(); + let mut filled_to = 0; + for (i, chunk) in chunks.iter().enumerate() { + if let Some(start_bit_index) = i.checked_mul(usize::BITS as usize) + && start_bit_index < dest.len() + { + let end_bit_index = start_bit_index + .saturating_add(usize::BITS as usize) + .min(dest.len()); + let bit_len = end_bit_index - start_bit_index; + let chunk = usize::from_le_bytes(*chunk); + dest[start_bit_index..end_bit_index].copy_from_bitslice(&chunk.view_bits()[..bit_len]); + filled_to = end_bit_index; + } else { + break; + } + } + if !remainder.is_empty() { + if let Some(start_bit_index) = chunks.len().checked_mul(usize::BITS as usize) + && start_bit_index < dest.len() + { + let end_bit_index = start_bit_index + .saturating_add(usize::BITS as usize) + .min(dest.len()); + let bit_len = end_bit_index - start_bit_index; + let mut chunk = [if msb_fill { !0 } else { 0 }; _]; + chunk[..remainder.len()].copy_from_slice(remainder); + let chunk = usize::from_le_bytes(chunk); + dest[start_bit_index..end_bit_index].copy_from_bitslice(&chunk.view_bits()[..bit_len]); + filled_to = end_bit_index; + } + } + dest[filled_to..].fill(msb_fill); +}