diff --git a/src/main.rs b/src/main.rs index b179fe1..ccd45f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ mod util; // Imports use { - self::{args::Args, pin_trace::PinTrace}, + self::{args::Args, pin_trace::PinTraceReader}, crate::{classifiers::hemem, sim::Simulator, util::FemtoDuration}, anyhow::Context, clap::Parser, @@ -29,11 +29,9 @@ fn main() -> Result<(), anyhow::Error> { logger::init(args.log_file.as_deref(), args.log_file_append); // Read the trace file - let pin_trace = { - let mut pin_trace_file = fs::File::open(&args.trace_file).context("Unable to open trace file")?; - PinTrace::from_reader(&mut pin_trace_file).context("Unable to parse pin trace")? - }; - tracing::trace!(target: "ftmemsim::parse_pin_trace", ?pin_trace, "Parsed pin trace"); + let mut pin_trace_file = fs::File::open(&args.trace_file).context("Unable to open trace file")?; + let mut pin_trace_reader = PinTraceReader::from_reader(&mut pin_trace_file).context("Unable to parse pin trace")?; + tracing::trace!(target: "ftmemsim::parse_pin_trace", ?pin_trace_reader, "Parsed pin trace"); // Run the simulator let mut sim = Simulator::new(0, Duration::from_secs_f64(0.1)); @@ -44,12 +42,12 @@ fn main() -> Result<(), anyhow::Error> { global_cooling_threshold: 18, }, vec![ - hemem::Memory::new("ram", 100, hemem::memories::AccessLatencies { + hemem::Memory::new("ram", 100 * 100, hemem::memories::AccessLatencies { read: FemtoDuration::from_nanos_f64(1.5), write: FemtoDuration::from_nanos_f64(1.0), fault: FemtoDuration::from_nanos_f64(10.0), }), - hemem::Memory::new("optane", 800, hemem::memories::AccessLatencies { + hemem::Memory::new("optane", 800 * 100, hemem::memories::AccessLatencies { read: FemtoDuration::from_nanos_f64(5.0), write: FemtoDuration::from_nanos_f64(4.0), fault: FemtoDuration::from_nanos_f64(50.0), @@ -57,7 +55,7 @@ fn main() -> Result<(), anyhow::Error> { ], ); - sim.run(pin_trace.records.iter().copied(), &mut hemem) + sim.run(&mut pin_trace_reader, &mut hemem) .context("Unable to run simulator")?; Ok(()) diff --git a/src/pin_trace.rs b/src/pin_trace.rs index 33f093e..60313b0 100644 --- a/src/pin_trace.rs +++ b/src/pin_trace.rs @@ -8,22 +8,25 @@ use { std::io, }; -/// Pin trace +/// Pin trace reader #[derive(Clone, Debug)] -pub struct PinTrace { +pub struct PinTraceReader { /// Header - pub header: Header, + _header: Header, - /// All records - pub records: Vec, + /// Records remaining + records_remaining: u64, + + /// Reader + reader: R, } -impl PinTrace { +impl PinTraceReader { /// Magic pub const MAGIC: [u8; 8] = *b"PINT v0\0"; /// Parses a pin trace from a reader - pub fn from_reader(reader: &mut R) -> Result { + pub fn from_reader(mut reader: R) -> Result { // Read the magic let magic = reader.read_byte_array().context("Unable to read magic")?; anyhow::ensure!( @@ -34,10 +37,11 @@ impl PinTrace { ); // Read the header - let header = Header::from_reader(reader).context("Unable to read header")?; + let header = Header::from_reader(&mut reader).context("Unable to read header")?; tracing::trace!(?header, "Parsed header"); // Get the total number of records + // TODO: Not have this hack here? let total_records = { let magic_size = Self::MAGIC.len() as u64; let header_size = Header::BYTE_SIZE as u64; @@ -55,14 +59,30 @@ impl PinTrace { (total_actual_size - magic_size - header_size) / record_size }; - let mut records = - Vec::with_capacity(usize::try_from(total_records).context("Total records didn't fit into a `usize`")?); - for record_idx in 0..total_records { - let record = Record::from_reader(reader).with_context(|| format!("Unable to read record {record_idx}"))?; - records.push(record); + Ok(Self { + _header: header, + records_remaining: total_records, + reader, + }) + } + + /// Reads the next record + pub fn read_next(&mut self) -> Result, anyhow::Error> { + // If we're done, return `None` + if self.records_remaining == 0 { + return Ok(None); } - Ok(Self { header, records }) + // Else parse the next record and reduce the remaining records + let record = Record::from_reader(&mut self.reader).context("Unable to read record")?; + self.records_remaining -= 1; + + Ok(Some(record)) + } + + /// Returns the remaining records + pub fn records_remaining(&self) -> u64 { + self.records_remaining } } diff --git a/src/sim.rs b/src/sim.rs index 1b74449..e495aa3 100644 --- a/src/sim.rs +++ b/src/sim.rs @@ -2,10 +2,11 @@ // Imports use { - crate::{pin_trace, util}, + crate::{pin_trace, pin_trace::PinTraceReader, util}, anyhow::Context, std::{ fmt, + io, time::{Duration, Instant}, }, }; @@ -35,17 +36,23 @@ impl Simulator { } } - /// Runs the simulator on records `records` with classifier `classifier` + /// Runs the simulator on all traces from `pin_trace_reader` with classifier `classifier` pub fn run( &mut self, - records: impl IntoIterator, + pin_trace_reader: &mut PinTraceReader, classifier: &mut C, ) -> Result<(), anyhow::Error> { // Note: We start in the past so that we output right away at the start let mut last_debug_time = Instant::now() - self.debug_output_freq; + // Create the record iterator + let total_records = pin_trace_reader.records_remaining(); + let record_it = std::iter::from_fn(|| pin_trace_reader.read_next().transpose()); + // Go through all records - for record in records.into_iter().step_by(self.trace_skip + 1) { + for (record_idx, record_res) in record_it.enumerate().step_by(self.trace_skip + 1) { + let record = record_res.context("Unable to read next record")?; + // Handle each trace let trace = Trace { record }; classifier @@ -55,7 +62,11 @@ impl Simulator { // Then show debug output, if it's been long enough let cur_time = Instant::now(); if cur_time.duration_since(last_debug_time) >= self.debug_output_freq { - tracing::info!("Debug: {}", util::DisplayWrapper::new(|f| classifier.fmt_debug(f))); + let records_processed_percentage = 100.0 * (record_idx as f64 / total_records as f64); + tracing::info!( + "[{records_processed_percentage:.2}%] Debug: {}", + util::DisplayWrapper::new(|f| classifier.fmt_debug(f)) + ); last_debug_time = cur_time } }