Pin trace reading is now done as-needed instead of up-front.

This commit is contained in:
2023-05-17 19:30:10 +01:00
parent 43c6788370
commit 94e31534bf
3 changed files with 57 additions and 28 deletions

View File

@@ -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(())

View File

@@ -8,22 +8,25 @@ use {
std::io,
};
/// Pin trace
/// Pin trace reader
#[derive(Clone, Debug)]
pub struct PinTrace {
pub struct PinTraceReader<R> {
/// Header
pub header: Header,
_header: Header,
/// All records
pub records: Vec<Record>,
/// Records remaining
records_remaining: u64,
/// Reader
reader: R,
}
impl PinTrace {
impl<R: io::Read + io::Seek> PinTraceReader<R> {
/// Magic
pub const MAGIC: [u8; 8] = *b"PINT v0\0";
/// Parses a pin trace from a reader
pub fn from_reader<R: io::Read + io::Seek>(reader: &mut R) -> Result<Self, anyhow::Error> {
pub fn from_reader(mut reader: R) -> Result<Self, anyhow::Error> {
// 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<Option<Record>, 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
}
}

View File

@@ -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<C: Classifier>(
&mut self,
records: impl IntoIterator<Item = pin_trace::Record>,
pin_trace_reader: &mut PinTraceReader<impl io::Read + io::Seek>,
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
}
}