replacement_cpp_TITLE
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <stdexcept>
#include <utility>
#include "replacement.h"
using std::string;
void Ref::print(ostream &strm) const
{
// Print strings for the reference types.
static const char *tmap[] = { "null", "ifet", "stor", "fetc", "upda" };
strm << tmap[type]
<< " @ 0x" << std::setw(8) << std::setfill('0') << std::hex
<< addr << std::dec << "+" << size;
}
void ReplacementAlg::init_memory()
{
m_memory = new page_table_t::iterator[m_num_frame];
for(int i = 0; i < m_num_frame; ++i)
m_memory[i] = m_page_table.end();
}
int ReplacementAlg::read(string filename)
{
// Set up the reading stream, either an open file or cin.
std::ifstream fin; // Open if filename is not -
std::istream *inpoint; // Point to input stream in use.
if(filename == "-")
inpoint = &std::cin;
else {
fin.open(filename.c_str());
if(!fin)
throw std::runtime_error
("Open " + filename + " failed: " +
strerror(errno));
inpoint = &fin;
}
// Read all the lines, and interpret any which will as references.
int count = 0;
string line;
while(std::getline(*inpoint, line)) {
Ref r; // Fill this in.
// Read the fields from the line. If the format doesn't
// match, discard the line.
if(sscanf(line.c_str()+2, "%x,%ld", &r.addr, &r.size) != 2)
continue;
// Set the line type, and discard the line if the type
// mark is not recognized.
if(line[0] == 'I') {
r.type = Ref::instr_fetch;
} else if(line[1] == 'S') {
r.type = Ref::store;
} else if(line[1] == 'L') {
r.type = Ref::fetch;
} else if(line[1] == 'M') {
r.type = Ref::update;
} else
continue;
// Process the item.
++count;
ref(r);
}
return count;
}
// Simulate the occurance of a memory reference.
void ReplacementAlg::ref(const Ref &r)
{
// Handle the reference count and maintenance call.
if(m_maint_freq && ++m_maint_count >= m_maint_freq) {
maint();
m_maint_count = 0;
}
// Analyze the reference.
unsigned pno = pageno(r);
int np = npage(r);
for(; np--; ++pno) {
++m_refcount;
// Check the frame.
page_table_t::iterator i = m_page_table.find(pno);
if(i == m_page_table.end() || !i->second.is_valid()) {
// Page fault.
++m_faultct;
// Get the frame to use.
unsigned long target = fault(r);
if(target >= m_num_frame) {
std::ostringstream msg;
msg << "fault() returned out-of-bounds frame "
<< target << " for fault on " << r;
throw std::runtime_error(msg.str());
}
// Remove the existing page if present.
page_table_t::iterator oldPTE = m_memory[target];
if(oldPTE != m_page_table.end() &&
oldPTE->second.is_valid()) {
// Remove current occupant.
++m_removect;
if(oldPTE->second.get_mod()) ++m_rewrite;
m_page_table.erase(oldPTE);
}
// Insert the the pte for the faulting page.
if(i == m_page_table.end())
i = m_page_table.insert
(std::make_pair(pno, PTE(target))).first;
else
i->second.validate(target);
// Adjust the frame.
m_memory[target] = i;
// Retry the reference.
}
// Update PTE flags.
i->second.set_ref();
if(r.is_write()) i->second.set_mod();
}
}
// Look up a PTE by page number
const PTE *ReplacementAlg::get_PTE_by_page(unsigned long page)
{
static PTE invalid;
page_table_t::iterator loc = m_page_table.find(page);
if(loc == m_page_table.end()) return &invalid;
return &loc->second;
}
// Look up a PTE by frame number
PTE *ReplacementAlg::get_PTE_by_frame(unsigned long frame)
{
if(frame >= m_num_frame) {
std::ostringstream msg;
msg << "get_PTE_by_frame() sent frame number "
<< frame << " out of range";
throw std::runtime_error(msg.str());
}
page_table_t::iterator loc = m_memory[frame];
if(loc == m_page_table.end()) return NULL;
return &loc->second;
}
void ReplacementAlg::print_stats(std::ostream &strm)
{
strm << "Algorithm: " << name();
if(m_maint_freq) strm << ", maint freq " << m_maint_freq;
strm << std::endl;
strm << "Memory: " << m_num_frame << " frames of "
<< (1 << m_page_bits) << " bytes each for "
<< (1 << m_page_bits)*m_num_frame << " total." << std::endl;
strm << "Performance: " << get_refcount() << " references produced "
<< get_faultcount() << " faults, rate: " << get_faultrate()
<< std::endl;
}