Below is the file 'aca319/lab9q1.c' from this revision. You can also download the file.


#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <math.h>

#include "mpi.h"
#include "mpe.h"

#define		TRACK_SIZE		50

#define		ACCELERATION_RATE	10
#define		BREAK_RATE		10

#define		SPEED_LIMIT		30

#define		BREAK_DISTANCE		2
#define		ACCELERATE_DISTANCE	5

#define		INSPECT_RANK		255

struct car {
	int track_pos;
	int speed;
	int next_car_pos;
};

void
drive(struct car *c, int rank, int size)
{
	MPI_Status status;
	int distance;
	int send_to;

	/* firstly, we determine what our speed for this time
	 * interval will be, based on our distance to the next
	 * car on the track
	 */
	if (c->next_car_pos > c->track_pos) {
		distance = c->next_car_pos - c->track_pos;
	} else {
		distance = (TRACK_SIZE - c->track_pos - 1) + c->next_car_pos;
	}

	if (rank == INSPECT_RANK)
		printf("[%d] (before) position=%d, speed=%d, distance=%d\n", rank, c->track_pos, c->speed, distance);
	if (distance <= BREAK_DISTANCE) {
		c->speed -= BREAK_RATE;
	} else if (distance >= ACCELERATE_DISTANCE) {
		c->speed += ACCELERATION_RATE;
	}

	/* no speeding! */
	if (c->speed > SPEED_LIMIT)
		c->speed = SPEED_LIMIT;
	/* no going backwards, either */
	if (c->speed < 0)
		c->speed = 0;
	/* ensure we don't overtake */
	if (c->speed > distance - 1)
		c->speed = distance - 1;

	/* then we move
	 */
	c->track_pos = (c->track_pos + c->speed) % TRACK_SIZE;

	if (rank == INSPECT_RANK)
		printf("[%d] (after) position=%d, speed=%d\n", rank, c->track_pos, c->speed);

	/* then we send our position to the car behind us, and
	 * receive the car in front's position
	 */
	send_to = rank - 1;
	if (send_to < 0)
		send_to = size - 1;
	MPI_Sendrecv(&c->track_pos, 1, MPI_INT, send_to, 50,
			&c->next_car_pos, 1, MPI_INT, (rank + 1) % size, 50, MPI_COMM_WORLD, &status);
	//printf("%d: at %d, next car at %d\n", rank, c->track_pos, c->next_car_pos);
}

int
main(int argc, char *argv[])
{
	int rank, size;
	struct car this_car;
	char *track;

	MPI_Init(&argc, &argv);

	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
	MPI_Comm_size(MPI_COMM_WORLD, &size);

	/* we're going to start 'size' cars.
	 * they are evenly spaced around the track.
	 */
	this_car.track_pos = rank * (TRACK_SIZE / size);
	this_car.next_car_pos = (rank + 1 % size) * (TRACK_SIZE / size);
	this_car.speed = 0;

	if (rank == 0) {
		track = malloc(sizeof(char) * TRACK_SIZE);
		if (!track) {
			fprintf(stderr, "Unable to allocate track array.\n");
			return -1;
		}
	}

	for (;;) {
		/* every processor element updates, and exchanges information
		 * to satisfy data dependency
		 */
		drive(&this_car, rank, size);
		/* processor 0 outputs the track state, all other processors
		 * send their state to 0
		 */
		if (rank == 0) {
			int i, position;
			MPI_Status status;

			memset(track, 0, TRACK_SIZE * sizeof(char));
			track[this_car.track_pos] = '0';
			for (i=1;i<size;i++) {
				MPI_Recv(&position, 1, MPI_INT, i, 60, MPI_COMM_WORLD, &status);
				if (i < 10) {
					track[position] = 0x30 + i;
				} else {
					track[position] = 'A' + (i-10);
				}
			}
			for (i=0;i<TRACK_SIZE;i++) {
				if (track[i] != 0) {
					printf("%c", track[i]);
				} else {
					printf("-");
				}
			}
			fflush(stdout);
			printf("\n\n");
		} else {
			MPI_Send(&this_car.track_pos, 1, MPI_INT, 0, 60, MPI_COMM_WORLD);
		}
		sleep(1);
	}

	if (rank == 0) {
		free(track);
	}

	MPI_Finalize();

	return 0;
}