swage_core/memory/
pfn_offset_resolver.rs1use super::keyed_cache::KeyedCache;
2use std::cmp::min;
3
4use super::DRAMAddr;
5use super::{BytePointer, MemoryTupleTimer, pfn_offset::CachedPfnOffset};
6use crate::memory::mem_configuration::MemConfiguration;
7use crate::util::NamedProgress;
8use crate::util::ROW_SIZE;
9use indicatif::MultiProgress;
10use indicatif::ProgressBar;
11use indicatif::ProgressStyle;
12use itertools::Itertools;
13use log::{debug, info};
14
15pub trait PfnOffsetResolver {
19 fn pfn_offset(
32 &self,
33 mem_config: &MemConfiguration,
34 conflict_threshold: u64,
35 timer: &dyn MemoryTupleTimer,
36 progress: Option<&MultiProgress>,
37 ) -> Option<usize>;
38}
39
40impl<T> PfnOffsetResolver for T
41where
42 T: BytePointer + CachedPfnOffset,
43{
44 fn pfn_offset(
52 &self,
53 mem_config: &MemConfiguration,
54 conflict_threshold: u64,
55 timer: &dyn MemoryTupleTimer,
56 progress: Option<&MultiProgress>,
57 ) -> Option<usize> {
58 if let Some(offset) = self.get_cached((*mem_config, conflict_threshold)) {
60 return Some(offset);
61 }
62 let num_rows = self.len() / ROW_SIZE;
64 let max_rows = mem_config.bank_function_period() as usize / 2; let num_rows = min(num_rows, max_rows);
66 let offset = progress.map(|progress| {
67 progress.add(
68 ProgressBar::new(num_rows as u64).with_style(ProgressStyle::named_bar("Offset")),
69 )
70 });
71 let pairs = progress.map(|progress| {
72 progress.add(
73 ProgressBar::new((num_rows * (num_rows - 1) / 2) as u64)
74 .with_style(ProgressStyle::named_bar("Pairs")),
75 )
76 });
77
78 if self.len() >= num_rows * ROW_SIZE {
80 let addr1 = self.ptr();
81 let addr2 = self.addr(num_rows * ROW_SIZE);
82 let time = unsafe { timer.time_subsequent_access_from_ram(addr1, addr2, 1000) };
83 if time > conflict_threshold {
84 info!("Pre-check failed. Block is not consecutive");
85 return self.put(None, (*mem_config, conflict_threshold));
86 }
87 } else {
88 debug!("Skip pre-check, block is too small");
89 }
90
91 'next_offset: for row_offset in 0..num_rows {
92 let addr_offset = (row_offset * ROW_SIZE) as isize;
93 debug!(
94 "Checking row offset {} (effective offset: 0x{:x})",
95 row_offset, addr_offset
96 );
97 if let (Some(offset), Some(pairs)) = (&offset, &pairs) {
99 offset.inc(1);
100 pairs.reset();
101 }
102 for row_pair in (0..num_rows).combinations(2) {
104 if let Some(pairs) = &pairs {
105 pairs.inc(1);
106 }
107 let offset1 = row_pair[0] * ROW_SIZE;
108 let offset2 = row_pair[1] * ROW_SIZE;
109 let addr1 = self.addr(offset1);
110 let addr2 = self.addr(offset2);
111 let dram1 = unsafe { DRAMAddr::from_virt_offset(addr1, addr_offset, mem_config) };
112 let dram2 = unsafe { DRAMAddr::from_virt_offset(addr2, addr_offset, mem_config) };
113 let same_bank = dram1.bank == dram2.bank;
114 let time = unsafe { timer.time_subsequent_access_from_ram(addr1, addr2, 1000) };
115 if (same_bank && time < conflict_threshold)
116 || (!same_bank && time > conflict_threshold)
117 {
118 debug!(
119 "Expected {} banks for ({:?}, {:?}), but timed {} {} {}",
120 if same_bank { "same" } else { "differing" },
121 offset1 / ROW_SIZE,
122 offset2 / ROW_SIZE,
123 time,
124 if same_bank { "<" } else { ">" },
125 conflict_threshold
126 );
127 debug!(
128 "rows: ({}, {}); addrs: (0x{:x}, 0x{:x}); DRAM: {:?}, {:?}",
129 offset1 / ROW_SIZE,
130 offset2 / ROW_SIZE,
131 addr1 as u64,
132 addr2 as u64,
133 dram1,
134 dram2
135 );
136 continue 'next_offset;
137 }
138 }
139 return self.put(Some(row_offset), (*mem_config, conflict_threshold));
140 }
141 self.put(None, (*mem_config, conflict_threshold))
142 }
143}