Repository navigation
Expand file tree
/
Copy pathmemSim.py
More file actions
executable file
·324 lines (259 loc) · 11.8 KB
/
Copy pathmemSim.py
File metadata and controls
executable file
·324 lines (259 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
#!/usr/bin/env python3
import sys
import struct
from collections import deque, OrderedDict
TLB_SIZE = 16 # Change this for different TLB tests
class TLB:
"""Translation Lookaside Buffer with 16 entries using FIFO replacement"""
def __init__(self):
self.entries = OrderedDict() # page_num -> frame_num
self.max_size = TLB_SIZE
def lookup(self, page_num):
"""Returns frame number if found, None otherwise"""
return self.entries.get(page_num)
def insert(self, page_num, frame_num):
"""Insert or update TLB entry"""
if page_num in self.entries:
# Remove and re-add to maintain FIFO order
del self.entries[page_num]
elif len(self.entries) >= self.max_size:
# Remove oldest entry (FIFO)
self.entries.popitem(last=False)
self.entries[page_num] = frame_num
class PageTableEntry:
"""Entry in the page table"""
def __init__(self):
self.present = False
self.frame_num = None
class PageTable:
"""Page table with 256 entries"""
def __init__(self):
self.entries = [PageTableEntry() for _ in range(256)]
def lookup(self, page_num):
"""Returns PageTableEntry for the given page number"""
return self.entries[page_num]
def set_entry(self, page_num, frame_num):
"""Set page table entry as present and assign frame"""
entry = self.entries[page_num]
entry.present = True
entry.frame_num = frame_num
class PhysicalMemory:
"""Physical memory management"""
def __init__(self, num_frames):
self.num_frames = num_frames
self.frames = [bytearray(256) for _ in range(num_frames)]
self.frame_to_page = {} # frame_num -> page_num mapping
self.free_frames = deque(range(num_frames))
def allocate_frame(self):
"""Allocate a free frame, returns frame number or None if full"""
if self.free_frames:
return self.free_frames.popleft()
return None
def load_page(self, frame_num, page_data, page_num):
"""Load page data into specified frame"""
self.frames[frame_num] = bytearray(page_data)
self.frame_to_page[frame_num] = page_num
def get_frame_content(self, frame_num):
"""Get the content of a frame as hex string"""
return self.frames[frame_num].hex()
def get_byte(self, frame_num, offset):
"""Get a specific byte from a frame"""
return struct.unpack('b', self.frames[frame_num][offset:offset+1])[0]
def deallocate_frame(self, frame_num):
"""Mark frame as free"""
if frame_num in self.frame_to_page:
del self.frame_to_page[frame_num]
self.free_frames.append(frame_num)
class PageReplacementAlgorithm:
"""Base class for page replacement algorithms"""
def __init__(self, physical_memory, page_table):
self.physical_memory = physical_memory
self.page_table = page_table
def select_victim(self, reference_sequence=None, current_index=None):
"""Select a frame to evict. To be implemented by subclasses"""
raise NotImplementedError
class FIFOAlgorithm(PageReplacementAlgorithm):
"""First-In-First-Out page replacement"""
def __init__(self, physical_memory, page_table):
super().__init__(physical_memory, page_table)
self.insertion_order = deque()
def add_page(self, frame_num):
"""Record that a page was loaded into this frame"""
self.insertion_order.append(frame_num)
def select_victim(self, reference_sequence=None, current_index=None):
"""Select the oldest frame"""
return self.insertion_order.popleft()
class LRUAlgorithm(PageReplacementAlgorithm):
"""Least Recently Used page replacement"""
def __init__(self, physical_memory, page_table):
super().__init__(physical_memory, page_table)
self.usage_order = [] # Most recent at the end
def access_page(self, frame_num):
"""Record that a page in this frame was accessed"""
if frame_num in self.usage_order:
self.usage_order.remove(frame_num)
self.usage_order.append(frame_num)
def add_page(self, frame_num):
"""Record that a page was loaded into this frame"""
self.access_page(frame_num)
def select_victim(self, reference_sequence=None, current_index=None):
"""Select the least recently used frame"""
return self.usage_order.pop(0)
class OPTAlgorithm(PageReplacementAlgorithm):
"""Optimal page replacement (Belady's algorithm)"""
def __init__(self, physical_memory, page_table):
super().__init__(physical_memory, page_table)
def add_page(self, frame_num):
"""No special tracking needed for OPT"""
pass
def access_page(self, frame_num):
"""No special tracking needed for OPT"""
pass
def select_victim(self, reference_sequence, current_index):
"""Select the frame that will be used farthest in the future"""
frame_to_page = self.physical_memory.frame_to_page
farthest_frame = None
farthest_distance = -1
for frame_num in frame_to_page:
page_num = frame_to_page[frame_num]
# Find next use of this page
next_use = float('inf')
for i in range(current_index + 1, len(reference_sequence)):
addr = reference_sequence[i]
future_page = (addr >> 8) & 0xFF
if future_page == page_num:
next_use = i
break
if next_use > farthest_distance:
farthest_distance = next_use
farthest_frame = frame_num
return farthest_frame
class VirtualMemorySimulator:
"""Main virtual memory simulator"""
def __init__(self, num_frames, replacement_algorithm, backing_store_file):
self.num_frames = num_frames
self.tlb = TLB()
self.page_table = PageTable()
self.physical_memory = PhysicalMemory(num_frames)
self.backing_store_file = backing_store_file
# Initialize page replacement algorithm
if replacement_algorithm == "FIFO":
self.replacement_algo = FIFOAlgorithm(self.physical_memory, self.page_table)
elif replacement_algorithm == "LRU":
self.replacement_algo = LRUAlgorithm(self.physical_memory, self.page_table)
elif replacement_algorithm == "OPT":
self.replacement_algo = OPTAlgorithm(self.physical_memory, self.page_table)
else:
raise ValueError(f"Unknown replacement algorithm: {replacement_algorithm}")
# Statistics
self.page_faults = 0
self.tlb_hits = 0
self.tlb_misses = 0
self.total_accesses = 0
def load_page_from_backing_store(self, page_num):
"""Load a page from backing store"""
try:
with open(self.backing_store_file, 'rb') as f:
f.seek(page_num * 256)
return f.read(256)
except IOError:
# If backing store doesn't exist or is too small, return zeros
return bytes(256)
def handle_page_fault(self, page_num, reference_sequence=None, current_index=None):
"""Handle a page fault by loading page from backing store"""
self.page_faults += 1
# Get page data from backing store
page_data = self.load_page_from_backing_store(page_num)
# Try to allocate a free frame
frame_num = self.physical_memory.allocate_frame()
if frame_num is None:
# No free frames, need to evict a page
victim_frame = self.replacement_algo.select_victim(reference_sequence, current_index)
# Invalidate the victim page in page table
victim_page = self.physical_memory.frame_to_page[victim_frame]
self.page_table.entries[victim_page].present = False
# Remove from TLB if present
if victim_page in self.tlb.entries:
del self.tlb.entries[victim_page]
frame_num = victim_frame
# Load the new page
self.physical_memory.load_page(frame_num, page_data, page_num)
self.page_table.set_entry(page_num, frame_num)
# Update replacement algorithm
self.replacement_algo.add_page(frame_num)
return frame_num
def translate_address(self, virtual_address, reference_sequence=None, current_index=None):
"""Translate virtual address to physical address"""
# Extract page number and offset
page_num = (virtual_address >> 8) & 0xFF
offset = virtual_address & 0xFF
self.total_accesses += 1
# Check TLB first
frame_num = self.tlb.lookup(page_num)
if frame_num is not None:
self.tlb_hits += 1
# Update LRU if needed
if isinstance(self.replacement_algo, LRUAlgorithm):
self.replacement_algo.access_page(frame_num)
else:
self.tlb_misses += 1
# Check page table
page_entry = self.page_table.lookup(page_num)
if page_entry.present:
frame_num = page_entry.frame_num
# Update LRU if needed
if isinstance(self.replacement_algo, LRUAlgorithm):
self.replacement_algo.access_page(frame_num)
else:
# Page fault
frame_num = self.handle_page_fault(page_num, reference_sequence, current_index)
# Update TLB
self.tlb.insert(page_num, frame_num)
# Get the byte value and frame content
byte_value = self.physical_memory.get_byte(frame_num, offset)
frame_content = self.physical_memory.get_frame_content(frame_num)
return frame_num, byte_value, frame_content
def print_statistics(self):
"""Print simulation statistics"""
page_fault_rate = (self.page_faults / self.total_accesses) * 100 if self.total_accesses > 0 else 0
tlb_hit_rate = (self.tlb_hits / self.total_accesses) * 100 if self.total_accesses > 0 else 0
print(f"Page Faults = {self.page_faults}")
print(f"Page Fault Rate = {page_fault_rate:.2f}%")
print(f"TLB Hits = {self.tlb_hits}")
print(f"TLB Misses = {self.tlb_misses}")
print(f"TLB Hit Rate = {tlb_hit_rate:.2f}%")
def main():
if len(sys.argv) < 2:
print("Usage: memSim <reference-sequence-file.txt> [FRAMES] [PRA]")
print("Defaults: FRAMES=256, PRA=FIFO")
sys.exit(1)
reference_file = sys.argv[1]
frames = int(sys.argv[2]) if len(sys.argv) > 2 else 256
algorithm = sys.argv[3] if len(sys.argv) > 3 else "FIFO"
# Validate inputs
if frames <= 0 or frames > 256:
print("Error: FRAMES must be between 1 and 256")
sys.exit(1)
if algorithm not in ["FIFO", "LRU", "OPT"]:
print("Error: PRA must be FIFO, LRU, or OPT")
sys.exit(1)
# Read reference sequence
try:
with open(reference_file, 'r') as f:
addresses = [int(line.strip()) & 0xFFFF for line in f if line.strip()]
except IOError:
print(f"Error: Cannot read reference file {reference_file}")
sys.exit(1)
# Initialize simulator
backing_store = "BACKING_STORE.bin"
simulator = VirtualMemorySimulator(frames, algorithm, backing_store)
# Process each address
for i, address in enumerate(addresses):
frame_num, byte_value, frame_content = simulator.translate_address(
address, addresses, i
)
print(f"{address},{byte_value},{frame_num},{frame_content}")
# Print statistics
simulator.print_statistics()
if __name__ == "__main__":
main()