ECET iLab 6
Thus lab needs to simulate virtual memory. It should show a fixed value of pages and faults while also being able to translate a virtual address to physical. Here is the source code I have so far:
#include <ctime>
#include <iomanip>
#include <iostream>
#include <fstream>
#include <pthread.h>
#include <sched.h>
#include <cstdlib>
using namespace std;
#define NUM_ADDRESSES_TO_GENERATE 10000
#define IN_BUFFER_SIZE 10
#define PAGE_SIZE 2048
#define MAIN_MEMORY_SIZE 16384
#define VIRTUAL_MEMORY_SIZE 65536
#define NUM_PAGES MAIN_MEMORY_SIZE / PAGE_SIZE
// Shared buffer to write/read virtual addresses.
int inBuffer[IN_BUFFER_SIZE];
// Number of virtual addresses in the shared buffer.
int inBufferCount;
// Mutex used to synchronize access to the inBuffer.
pthread_mutex_t inBufferMutex;
// Counter for the number of page faults.
int numberOfPageFaults;
// Flag used to indicate the address generation is done.
bool addressGenerationDone;
// TODO: You’ll probably need some structures and variables to store information
// needed for page replacement and address translation.
int getNextVirtualAddress(int addr)
{
// TODO: Replace below with your own method of generating virtual addresses.
// You can just generate a random address if you want, which is probably the
// easiest thing to do.
srand(time(NULL));
addr = rand() % VIRTUAL_MEMORY_SIZE +1;
return 0;
}
void* doAddressGeneration(void* pArg)
{
int addr = -1;
int addressCount = NUM_ADDRESSES_TO_GENERATE;
while (addressCount != 0) {
if (inBufferCount < IN_BUFFER_SIZE) {
addr = getNextVirtualAddress(addr);
// Write the next virtual address. Be careful to synchronize
// appropriately with the address translation thread.
pthread_mutex_lock(&inBufferMutex);
inBuffer[inBufferCount] = addr;
inBufferCount++;
pthread_mutex_unlock(&inBufferMutex);
addressCount–;
} else {
// The buffer is full. Yield to wait for it to empty.
sched_yield();
}
}
// Mark that address generation is done.
addressGenerationDone = true;
pthread_exit(NULL);
}
int translateAddress(int addr)
{
int pageNumber = VIRTUAL_MEMORY_SIZE / PAGE_SIZE;
int baseVirtualAddress = pageNumber * PAGE_SIZE;
int pageOffset = VIRTUAL_MEMORY_SIZE % PAGE_SIZE;
int physAddr = MAIN_MEMORY_SIZE / PAGE_SIZE;
int basePhysicalAddress = physAddr * PAGE_SIZE;
int finalPhysicalAddress = basePhysicalAddress + 4;
// TODO: See page 189 in the text for info about paging. You will need a page
// table. I found Figure 3-10 useful. This figure shows how to translate a
// virtual address to a physical address.
// TODO: If the page table does not contain a mapping for to a page frame, a
// page fault occurs. In this case, you will have to choose a page frame
// (and possibly evict an old page if all page frames are in use). I would
// recommend FIFO as the easiest to implement (see page 204). FIFO would
// require a queue of page frames.
return 0;
}
void* doAddressTranslation(void* pArg)
{
int addr;
int physAddr;
ofstream outputFile;
ostream* pOutput;
outputFile.open(“ilab6_output.txt”);
if (outputFile.is_open()) {
pOutput = &outputFile;
} else {
cout << “Error opening ilab6_output.txt, using standard output”
<< endl;
outputFile.close();
pOutput = &cout;
}
cout << “Virtual: ” << VIRTUAL_MEMORY_SIZE << “Physical: ” << MAIN_MEMORY_SIZE << endl
<< “——————–” << endl;
// Keep translating addresses until none are left.
while (!addressGenerationDone) {
if (inBufferCount <= 0) {
// There are no addresses to read. Yield to wait for more.
sched_yield();
}
while (inBufferCount > 0) {
// Read the next virtual address. Be careful to synchronize
// appropriately with the address generation thread.
pthread_mutex_lock(&inBufferMutex);
inBufferCount–;
addr = inBuffer[inBufferCount];
pthread_mutex_unlock(&inBufferMutex);
// Translate the virtual address.
physAddr = translateAddress(addr);
*pOutput << “0x” << hex << setfill(‘0’) << setw(4) << addr
<< ” -> 0x” << hex << setfill(‘0’) << setw(4) << physAddr
<< endl;
}
}
if (outputFile.is_open()) {
outputFile.close();
}
pthread_exit(NULL);
}
void* doStatistics(void* pArg)
{
pthread_t* pAddrTranThread = (pthread_t*)pArg;
// Wait until address translation thread exits.
pthread_join(*pAddrTranThread, NULL);
cout << “Total Number of Page Faults = ” << numberOfPageFaults << endl;
pthread_exit(NULL);
}
int main(int argc, char* argv[])
{
pthread_attr_t attrs;
pthread_t addrGenThread;
pthread_t addrTranThread;
pthread_t statsThread;
// TODO: Seed random number generator. If your getNextVirtualAddress
// function does not generate random numbers, the following line can be
// removed.
srand(time(NULL));
pthread_mutex_init(&inBufferMutex, NULL);
pthread_attr_init(&attrs);
pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_JOINABLE);
// Create three joinable threads, one for each component of the iLab.
pthread_create(&addrGenThread, &attrs, doAddressGeneration, NULL);
pthread_create(&addrTranThread, &attrs, doAddressTranslation, NULL);
pthread_create(&statsThread, &attrs, doStatistics, &addrTranThread);
pthread_attr_destroy(&attrs);
pthread_join(addrGenThread, NULL);
pthread_join(addrTranThread, NULL);
pthread_mutex_destroy(&inBufferMutex);
pthread_join(statsThread, NULL);
// Once all the component threads have exited, the program can exit.
return 0;
}