Project 5
Due Dec. 5, 2014 at 11:59:59pm no late submissions will be accepted
20 Points, you may work in groups of two on this project
Turn in this assignment as a zip file using the eCompanion Dropbox.
Graduate students must complete both MPI and multi-threaded versions of this assignment and provide full I/O statistics during runtime using an interactive visualization with D3.js for an additional 30 points.

Starter code is provided at the following link
Sample input data is provided at the following link

Introduction

Write a multi-threaded or MPI C program that uses a thread/process to represent a memory manager that will provide paged data management to worker threads/processes. Note that each worker thread/process may perform different operations.  Before worker threads/processes may start processing, they must request memory from the memory manager.  Such memory must be requested for all local variables within each thread/process except for those used to allocate memory from the memory manager.  Input data for each thread must be provided through the memory manager thread/process.

Workers will perform one of three kinds of tasks: Decryption, Matrix Addition, or Dot Product. 

Your programs must take as file input the following information:

You may assume that data will be loaded from a virtual hard drive. You may also assume that the virtual hard drive will be large enough to hold all files provided as input.

You must also provide as input within the same file:

Both threaded and MPI programs should make use of the following data structures (or similar data structures of your own creation) within the memory manager.

struct Page
{
    int pageSize;
    Frame * frame;
    struct Page * next;
};

struct Segment
{
    int threadOwner;
    Page * pageList;
    struct Segment * next;
};

struct PhysicalRam
{
    Frame * frames;
};

struct VirtualHDD
{
    int * threadOwner;
    char ** files;
};

struct Frame
{
    char * frameData;
};

Matrix Addition Input

Assume data for matrices will be stored in files. Matrices will be stored one matrix per file. Each of the files will contain header information denoting the number of rows and columns in the matrix on the first line. Thereafter, each file will contain the data for a matrix. For example, the following matrix:

[ 1 2 3
  4 5 6
  7 8 9 ]

Would be stored as:

3 3
1
2
3
4
5
6
7
8
9

Dot Product Input

Assume data for dot products will be stored in files.  A dot product is the sum of the point to point products of values within a pair of vectors.  Vectors will be stored one matrix per file. Each of the files will contain header information denoting the number of elements in the vector on the first line. For example, the following vector:

[ 1 2 3 4 5 6 7 8 9 ]

Would be stored as:

9
1
2
3
4
5
6
7
8
9

The dot product of two vectors [ 1 2 3 ] and [ 4 5 6 ] is 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32

Decryption Input (i.e. an encrypted file)

The encrypted file is a flat file that contains information encrypted via xor.  You may assume that the key will be provided in the first line of the file.  Notice that if we take 37 xor 23, we get the encrypted result 50.  We can decrypt the result by taking 50 xor 23 = 37.  For example, the following text:

This file will be encrypted!

If encrypted using 23 as the key, would be stored as:

23
C~d7q~{r7`~{{7ur7rytengcrs6


You can use the following code to help with your encryption and decryption:

#include <stdio.h>
#include <string.h>

int main(int argc, char ** argv)
{
  printf("%d\n", 37 ^ 23);
  printf("%d\n", 50 ^ 23);

  char * str = "This file will be encrypted!";

  int i = 0;
  for(i = 0; i < strlen(str); i++)
    printf("%c", str[i] ^ 23);
  printf("\n");
  return 0;
}


Processing

Assume each thread/process may cache (store with in its own data structures), all of its data received from the memory manager. You may also assume each thread can keep track of the size of the matrices, vectors, or file data belonging to it. Before a thread/process may add matrices a row and a column, decrypt data, or perform a a dot product, it must acquire data from the memory manager. To obtain data, you must make a function call or send a request to the memory manager requesting the data for that thread/process.  When this call is made, the memory manager must first simulate virtual memory by finding the correct segment number. Next, the memory manager must simulate the segment table by finding the appropriate page number in the segment table, and using the page number to access the corresponding frame from simulated physical memory (an array). You will need to keep track of segment sizes and frame sizes to make the appropriate conversions between offsets in virtual memory and physical memory. You may allow the memory manager to keep track of the files and matrices belonging to each worker thread.

Note that you may encounter memory page faults while performing processing (when loading a new thread/process). When a process/thread completes, you must swap matrix data out of memory and replace it with the needed memory from the virtual hard drive to continue processing and provide worker processes/threads with the data (files) they need. You may assume that all threads/processes arrive for processing at the approximately same time and are processed in a first come first serve manner. Note that you have a limited amount of main memory. If there is not enough memory for each thread/process to perform its processing, you must force those threads/processes to wait until memory is available. Provided memory is available, the memory manager should allocate enough space for all files for every active worker thread. Hint: you may wish to use a mutex and a condition variable to help with your implementation of the memory manager.

Output

Provide as output, the average worker thread runtime in milliseconds, the average number of frames used per worker thread, the total runtime, the total number of frames used, and the total number of pages used. Store the results of each matrix multiplication and decryption in an output file. Provide dot product results as output to standard out (the screen).  Note that this data must pass through main memory before it can be written to a file.

Submission

Submit your source code this program to the eCompanion dropbox for Project 5. Additionally, you must submit a README file explaining how to run and compile your program and denoting any issues with the program.