Contents:
Project Details
Starting Point Code and Tips for Getting Started
Useful Functions and Links to more Resources
Designing and Running Experiments
Written Report
Submission and Demo
Your world is represented by a 2-D array of values (0 or 1). If a grid cell's value is 1, it represents a live object, if it is 0 a dead object. At each discrete time step, every cell in the 2-D grid gets a new value based on the current value of its eight neighbors:
Your 2-D world should be a TORUS; every cell in the grid has exactly eight neighbors. In the torus world, cells on the edge of the grid have neighbors that wrap around to the opposite edge. For example, the grid locations marked with an 'x' are the eight neighbors of the grid cell whose value is shown as 1.
x 1 x 0 0 0 0 x x x 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 x x x 0 0 0 0Conway's Game of Life description from Wikipedia, shows some example patterns you can use to test the correctness of your solution (like Blinker, Toad or Beacon).
You should implement two different solutions to the game of life based on how threads are assigned to grid cells:
row column --- ------ 1 1 1 1 1 1 1 1 1 1 2 2 3 3 4 4 1 1 1 1 1 1 1 1 1 1 2 2 3 3 4 4 2 2 2 2 2 2 2 2 1 1 2 2 3 3 4 4 2 2 2 2 2 2 2 2 1 1 2 2 3 3 4 4 3 3 3 3 3 3 3 3 1 1 2 2 3 3 4 4 3 3 3 3 3 3 3 3 1 1 2 2 3 3 4 4 4 4 4 4 4 4 4 4 1 1 2 2 3 3 4 4 4 4 4 4 4 4 4 4 1 1 2 2 3 3 4 4
You should be careful to stick with the fork-join, fork-join, fork-join model of OpenMP; don't do things in the parallel parts that are really not parallel or you will get some weird/unexpected behavior. Do not try to "optimize" your code by reducing fork-join blocks. You should, however, think about minimizing other parallel overheads as you design a solution; your solution should be designed so that there is a performance improvement from parallelization. If your 1 thread execution wins out over the multi-thread ones, think about how you can remove some parallel overhead (think of space/time trade-offs, think about synchronization costs, ...).
cp ~newhall/public/cs87/lab4/* .Take a look at at the code and try running it with different command line argument values for the number of threads:
./gameoflife # this will use default # tids based on num cpus ./gameoflife 2 # run with 2 threadsOnce you understand what this code is doing, I'd recommend first trying modify the program to get a program that "assigns" threads row-wise to the the 2-D grid of values by having each thread set its part of the grid to its tid, and then test assigning tids column-wise:
./gameoflife 4 row-wise: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 column-wise: 0 0 1 1 2 2 3 3 0 0 1 1 2 2 3 3 0 0 1 1 2 2 3 3 0 0 1 1 2 2 3 3 0 0 1 1 2 2 3 3 0 0 1 1 2 2 3 3 0 0 1 1 2 2 3 3 0 0 1 1 2 2 3 3Remember: in C, function prototypes that have 2-D array parameters, must specify the column dimension to use array[i][j] syntax for accessing bucket values in the passed array:
void printarray(int array[][GRID_DIM]);Once you have verified that you know how to assign grid cells to threads, implement the game of life program and test it out on a small grid (16x16) for some of the test patterns shown on the Wikipedia page.
Once you have verified correctness of your solution, comment out all debug output, and add some sequential code to initialize your the grid to some random pattern of 1's and 0's (don't do a 50-50 assignment, use maybe ~20% 1's).
Add timing code to only the discrete event simulation part (not the initialization of the grid or printfs), and start running experiements.
You should run experiments of your two solutions varying:
You should run multiple runs of each experiement (e.g. don't just do a single times run of a 64x64 grid, with 4 threads, and 10000 time steps).
You should be careful to control the experimental runs as much as possible. If other people using the machine you are running experiements on, their programs can interfere with your results. You can see what is running on a machine:
Also, make sure that your grid size is not too large to cause swapping. When you first try some sample runs with different grid sizes, run:
watch -n 1 cat /proc/swaps Filename Type Size Used Priority /dev/sda5 partition 2072344 0 -1If you notice the Used value going above 0, your grid size is too big to fit into RAM (or there are too many people running on this machine, and you need to find an idle machine).
Pick a quad-core machine to run most of your experiements. As much as possible, it is good to run all your experiements on the same machine, or at least identical machines.
In addition, the department has two 8-core machines, carrot and mushroom. You should run a limited number of experiments on these machines, as you will have to share access to them. note: mushroom is running a 64-bit version of Linux, so you will need to re-compile your program on mushroom before running it.
8-core machine reservations: I've added a lab 4, 8-core machine reservation page to the wiki. Please use this to reserve times to use these machines. If you want to run during a time someone else reserved, you can try logging in and running who to see if the machine is really in use. If it is, you will have to wait. The idea is to use this to notify each other of times you would like to use one of these machines for experiements, and to monitor your own usage by having a record of who has had access to these machines, so that we can implement some type of "fair access policy".
I suggest that you run a large round of experiements on quad-core, and then pick a few experiements from those to re-run on the 8-core, along with some additional runs with 8 threads.