/* tab:4 * * wator.sc - Problem 4 for Short Course. Each fish in wator moves locally. * * Author: Andrea C. Dusseau * Version: 1 * Creation Date: Thu May 27 11:17:55 1993 * Filename: wator.sc * History: */ #include /* --------------------------- Definitions ------------------------------ */ #define FISH_PER_PROC 100 /* number of fish on each processor */ #define DISPLAY_SIZE 256 /* pixel size of display window */ #define HARD_CODED_PROCS 64 #define BLOCK_HEIGHT (DISPLAY_SIZE/HARD_CODED_PROCS) /* The probability that a fish exists at a grid location -- used during initialization */ #define FISH_CHANCE (0.1) /* HAS_FISH decides randomly if a fish is present in a particular cell. */ #define HAS_FISH ((random()&65535)/65536.0 < FISH_CHANCE) /* The destination directions in which a fish may want to move */ typedef enum { DIR_NONE, DIR_NORTH, DIR_SOUTH, DIR_EAST, DIR_WEST, DIR_MOVED } dir_t; typedef struct { char fish_present; /* Whether or not a fish is present in a grid square */ dir_t dest_dir; /* The direction this fish wishes to move */ } grid_t; /* ------------------------------ Data ------------------------------- */ /* We need two buffers: one that holds the world as of the last iteration and * one that contains the world being built during this iteration. The role * of each buffer is reversed each iteration. */ grid_t watorA[PROCS]::[BLOCK_HEIGHT][DISPLAY_SIZE]; grid_t watorB[PROCS]::[BLOCK_HEIGHT][DISPLAY_SIZE]; grid_t (* spread old_w)[BLOCK_HEIGHT][DISPLAY_SIZE]; grid_t (* spread new_w)[BLOCK_HEIGHT][DISPLAY_SIZE]; /* ---------------------------- Procedures -------------------------- */ /* * all_init_fish: * Randomly assigns fish to the portions of wator which are local to this processor * The chance of each grid point having a fish is determined by FISH_CHANCE */ void all_init_fish() { int i, j; grid_t *grid; srandom(MYPROC*131); old_w = &watorA[0][0][0]; new_w = &watorB[0][0][0]; grid = (grid_t *)&old_w[MYPROC][0][0]; for (i = 0; i < BLOCK_HEIGHT; i++) for (j = 0; j < DISPLAY_SIZE; j++, grid++) grid->fish_present = HAS_FISH; } /* * all_select_dest: * Each processor loops over the portion of wator which is local and if * a fish is present in a grid, then it assigns a random destination direction * to it. */ void all_select_dest() { int i, j; grid_t *grid; float dest; grid = (grid_t *)&old_w[MYPROC][0][0]; for (i = 0; i < BLOCK_HEIGHT; i++) for (j = 0; j < DISPLAY_SIZE; j++, grid++) { if (!grid->fish_present) continue; dest = (random()&65535)/65536.0; if (dest < 0.2) grid->dest_dir = DIR_NORTH; else if (dest < 0.4) grid->dest_dir = DIR_SOUTH; else if (dest < 0.6) grid->dest_dir = DIR_EAST; else if (dest < 0.8) grid->dest_dir = DIR_WEST; else grid->dest_dir = DIR_NONE; } } /* * get_dest: * An auxiliary routine which calculates the destination grid in both the * old wator and the new wator, given the current x and y position and the * destination direction. */ void get_dest(int y, int x, dir_t d, grid_t **dest, grid_t **newdest) { switch (d) { case DIR_NORTH: if (y) { *dest = (grid_t *)&old_w[MYPROC][y-1][x]; *newdest = (grid_t *)&new_w[MYPROC][y-1][x]; } else { *dest = (grid_t *)&old_w[MYPROC ? MYPROC-1 : PROCS-1][BLOCK_HEIGHT-1][x]; *newdest = (grid_t *)&new_w[MYPROC ? MYPROC-1 : PROCS-1][BLOCK_HEIGHT-1][x]; } break; case DIR_SOUTH: if (y < BLOCK_HEIGHT-1) { *dest = (grid_t *)&old_w[MYPROC][y+1][x]; *newdest = (grid_t *)&new_w[MYPROC][y+1][x]; } else { *dest = (grid_t *)&old_w[MYPROC < PROCS-1 ? MYPROC + 1 : 0][0][x]; *newdest = (grid_t *)&new_w[MYPROC < PROCS-1 ? MYPROC + 1 : 0][0][x]; } break; case DIR_EAST: *dest = (grid_t *)&old_w[MYPROC][y][(x+1)%DISPLAY_SIZE]; *newdest = (grid_t *)&new_w[MYPROC][y][(x+1)%DISPLAY_SIZE]; break; case DIR_WEST: *dest = (grid_t *)&old_w[MYPROC][y][x? x-1 : DISPLAY_SIZE-1]; *newdest = (grid_t *)&new_w[MYPROC][y][x ? x-1 : DISPLAY_SIZE-1]; break; } } /* * all_move_fish: * Each processor loops through the portions of wator which are local and * tries to move each fish that wants to go in the currently selected * direction. In order for a fish to move, its destination grid must be * free in both the previous time step and the current time step. */ void all_move_fish(dir_t dest_dir) { int i, j; grid_t *grid, *dest, *newdest; grid = (grid_t *)&old_w[MYPROC][0][0]; for (i = 0; i < BLOCK_HEIGHT; i++) for (j = 0; j < DISPLAY_SIZE; j++, grid++) { if (!grid->fish_present || grid->dest_dir != dest_dir) continue; get_dest(i, j, dest_dir, &dest, &newdest); if (!dest->fish_present && !newdest->fish_present) { /* Move this fish to its desired destination and mark it as being moved */ newdest->fish_present = 1; grid->dest_dir = DIR_MOVED; } /* Fish can't be moved; mark it so that it will be copied over to the new world */ else grid->dest_dir = DIR_NONE; } } /* * all_copy_stay: * This procedure copies the fish that did not move from the old world into * the new world. It also clears out the old world. */ void all_copy_stay() { int i, j; grid_t *grid, *new; grid = (grid_t *)&old_w[MYPROC][0][0]; new = (grid_t *)&new_w[MYPROC][0][0]; for (i = 0; i < BLOCK_HEIGHT; i++) for (j = 0; j < DISPLAY_SIZE; j++, grid++, new++) { if (grid->fish_present && grid->dest_dir == DIR_NONE) new->fish_present = 1; grid->fish_present = 0; } } /* * all_display_fish: * Each processor loops over the local portion of the old world and sends * those points which are different than the previous display. */ void all_display_fish() { static int init = 0; static char old_map[BLOCK_HEIGHT][DISPLAY_SIZE]; char *old_fish; int i, j; grid_t *new_fish; /* If this is the first time, open a window and clear the old map. */ if (!init) { init = 1; on_one X_init(DISPLAY_SIZE); old_fish = &old_map[0][0]; for (i = 0; i < BLOCK_HEIGHT; i++) for (j = 0; j < DISPLAY_SIZE; j++, old_fish++) *old_fish = 0; } /* Send changes in map to host for display, and copy new map to old. */ old_fish = &old_map[0][0]; new_fish = (grid_t *)&old_w[MYPROC][0][0]; for (i = 0; i < BLOCK_HEIGHT; i++) for (j = 0; j < DISPLAY_SIZE; j++, old_fish++, new_fish++) { if (*old_fish != new_fish->fish_present) { X_point(j, MYPROC*BLOCK_HEIGHT + i, new_fish->fish_present); *old_fish = new_fish->fish_present; } } } /* * splitc_main: */ splitc_main() { grid_t (*spread tmp_w)[BLOCK_HEIGHT][DISPLAY_SIZE]; /* Randomly assign fish to wator */ all_init_fish(); barrier(); while (1) { /* Move fish according to their selected destination direction */ all_select_dest(); all_move_fish(DIR_NORTH); /* * Need to synchronize before moving south because we must ensure that the * processor below us has priority for moving its fish north into our space */ barrier(); all_move_fish(DIR_SOUTH); /* * Once again, need to synchronize because we must ensure that the * processor above us has priority for moving its fish south into our space */ barrier(); all_move_fish(DIR_EAST); /* Do not need to synchronize because this is all local movement */ all_move_fish(DIR_WEST); all_copy_stay(); /* Swap the new and old wator pointers */ tmp_w = new_w; new_w = old_w; old_w = tmp_w; /* Send display data to host node. */ all_display_fish(); /* Synchronize to insure that host has all of the current display data. */ barrier(); /* Display the ocean. */ on_one X_show(); } }