ModSim: Finished code for assignment 4 part 1.

parent c19decc2
CFLAGS +=-std=c99 -Wall -Wextra -g -O2
LDFLAGS+=-lmpi
MAIN = main
OFILES = interval.o slave.o master.o main.o
$(MAIN): $(OFILES)
clean:
rm -vf $(MAIN) $(OFILES)
/*
* Created by Sander van Veen (UvA ID: 6167969)
*/
/* interval is a pointer to a struct used by the functions
* in the file interval.c. As such it constitutes an opaque data type
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/times.h>
#include <limits.h>
#include "interval.h"
#include <math.h>
/*
* Over the years the number of clock ticks per second has been called by many
* names. The code give here appears to work on most machines. Use MY_CLK_TCK
* to convert the output of times() to seconds.
*/
static clock_t MY_CLK_TCK = 0;
typedef struct interval_t {
struct timeval last_wct; /* Used for wall-clock time */
struct tms last_cput; /* Used for CPU time */
} interval_t;
/*
* The function new_interval creates and initialises a new interval_t structure
* and returns a pointer to this structure.
*/
interval interval_init(void) {
interval nw = calloc(1, sizeof(interval_t));
if( !nw )
return NULL;
gettimeofday(&(nw->last_wct), NULL);
times(&(nw->last_cput));
if( !MY_CLK_TCK )
MY_CLK_TCK = sysconf(_SC_CLK_TCK);
return nw;
}
/*
* Free the memory used by the interval pointer and set the pointer to NULL. If
* the pointer is valid, zero is returned, or 1 otherwise.
*/
int interval_destroy(interval *intervalPtr) {
if( intervalPtr == NULL )
return 1;
free(*intervalPtr);
*intervalPtr = NULL;
return 0;
}
/*
* Returns the wall clock time, user CPU time and system CPU time for the
* calling process and its children consumed since the previous call for the
* specified interval. Returns zero on success, -1 when an invalid pointer is
* passed as argument.
*/
int interval_time(interval id, double *wct, double *ust, double *syt) {
if( !id || wct == NULL || ust == NULL || syt == NULL )
return -1;
struct timeval last_wct = id->last_wct;
struct tms last_cput = id->last_cput;
if( interval_destroy(&id) )
return -1;
id = interval_init();
*wct = (id->last_wct.tv_sec + id->last_wct.tv_usec / 1e6)
- (last_wct.tv_sec + last_wct.tv_usec / 1e6);
*ust = difftime(id->last_cput.tms_utime, last_cput.tms_utime) / MY_CLK_TCK;
*syt = difftime(id->last_cput.tms_stime, last_cput.tms_stime) / MY_CLK_TCK;
return 0;
}
/* interval is a pointer to a struct used by the functions
in the file interval.c. As such it constitutes an opaque data type */
typedef struct interval_t *interval;
/* the function interval_init creates and initialises a new
interval_t struct and returns its address */
interval interval_init(void);
/* The function interval_destroy frees the memory for an interval
variable and NULLs its value to prevent accidental reuse.
It returns zero on success, -1 when an invalid pointer
is passed as an argument. */
int interval_destroy(interval *intervalPtr);
/* the function interval_time returns the wall clock time,
user CPU time and system CPU time for the calling process
and its children consumed since the previous call for the
specified interval.
It returns zero on success, -1 when an invalid pointer
is passed as an argument. */
int interval_time(interval id, double *wct, double *ust, double *syt);
#include <stdlib.h>
#include <stdio.h>
#include <mpi.h>
#include "main.h"
#include "interval.h"
#include "master.h"
#include "slave.h"
#define LIST_SIZE 1000000 // Total items for all tasks (million)
int test_stride = 1; // Items per task
int test_current_item = 0; // Position in item list
double test_list[LIST_SIZE]; // List containing all test items
int main(int argc, char **argv)
{
int role;
// Create list of zero values.
for(int i = 0; i < LIST_SIZE; i++)
test_list[i] = .0;
// Perhaps the user wants a different stride?
if( argc == 2 )
test_stride = atoi(argv[1]);
// Initialize MPI.
argc = 1; // Reset argc to hide our arguments.
MPI_Init(&argc, &argv);
// Find out my identity in the default communicator.
MPI_Comm_rank(MPI_COMM_WORLD, &role);
if(role == 0) {
int ntasks = master_init();
// Benchmark
double wct, ust, syt;
interval start_time = interval_init();
master_run(ntasks, test_stride);
(void) interval_time(start_time, &wct, &ust, &syt);
printf("test list has size: %d\n", LIST_SIZE);
printf("real: %.12e\nuser: %.12e\nsys: %.12e\n", wct, ust, syt);
// Memory clean up
interval_destroy(&start_time);
master_destroy(ntasks);
} else {
slave(test_stride);
}
// Shut down MPI.
MPI_Finalize();
return 0;
}
unit_work_t *get_next_work_item(void) {
if( test_current_item + (test_stride-1) < LIST_SIZE )
return NULL;
return &test_list[test_current_item+test_stride];
}
void process_results(unit_result_t result) {
// Fill in with whatever is relevant to process the results returned by the
// slave.
}
#define WORK_TAG 1
#define DIE_TAG 2
typedef double unit_work_t;
typedef double unit_result_t;
unit_work_t *get_next_work_item(void);
void process_results(unit_result_t result);
#include <mpi.h>
#include "main.h"
#include "master.h"
int master_init(void) {
// Find out how many processes there are in the default communicator
int ntasks;
MPI_Comm_size(MPI_COMM_WORLD, &ntasks);
return ntasks;
}
void master_run(int ntasks, int items_per_task) {
int rank;
unit_work_t *work;
unit_result_t result;
MPI_Status status;
// Seed the slaves; send one unit of work to each slave.
for(rank = 1; rank < ntasks; ++rank) {
// Get the next items of work to do
work = get_next_work_item();
// Send it to each rank
MPI_Send(work, // message buffer
items_per_task, // size of data array
MPI_INT, // data item is an integer
rank, // destination process rank
WORK_TAG, // user chosen message tag
MPI_COMM_WORLD); // default communicator
}
// Loop over getting new work requests until there is no work to be done.
while((work = get_next_work_item()) != NULL) {
// Receive results from a slave
MPI_Recv(&result, // message buffer
1, // one data item
MPI_DOUBLE, // of type double real
MPI_ANY_SOURCE, // receive from any sender
MPI_ANY_TAG, // any type of message
MPI_COMM_WORLD, // default communicator
&status); // info about the received message
// Send the slave a new work unit
MPI_Send(work, // message buffer
items_per_task, // size of data array
MPI_INT, // data item is an integer
status.MPI_SOURCE, // to who we just received from
WORK_TAG, // user chosen message tag
MPI_COMM_WORLD); // default communicator
}
// There's no more work to be done, so receive all the outstanding results
// from the slaves.
for (rank = 1; rank < ntasks; ++rank) {
MPI_Recv(&result, 1, MPI_DOUBLE, MPI_ANY_SOURCE, MPI_ANY_TAG,
MPI_COMM_WORLD, &status);
}
}
void master_destroy(int ntasks) {
// Tell all slaves to exit by sending an empty message with the DIE_TAG.
for (int rank = 1; rank < ntasks; ++rank) {
MPI_Send(0, 0, MPI_INT, rank, DIE_TAG, MPI_COMM_WORLD);
}
}
int master_init(void);
void master_run(int ntasks, int items_per_task);
void master_destroy(int ntasks);
#include <mpi.h>
#include "main.h"
#include "slave.h"
void slave(int items_per_task) {
for(;;) {
unit_work_t work;
MPI_Status status;
/* Receive a message from the master */
MPI_Recv(&work, items_per_task, MPI_INT, 0, MPI_ANY_TAG,
MPI_COMM_WORLD, &status);
/* Check the tag of the received message. */
if(status.MPI_TAG == DIE_TAG)
return;
/* Do the work */
unit_result_t result = do_work(&work, items_per_task);
/* Send the result back */
MPI_Send(&result, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
}
}
unit_result_t do_work(unit_work_t *work, int items_per_task) {
// Fill in with whatever is necessary to process the work and generate a
// result.
return .0;
}
void slave(int items_per_task);
unit_result_t do_work(unit_work_t *work, int items_per_task);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment