/* Starter MPI Mandelbrot program. This program computes and displays the Mandelbrot set. Usage: mandelbrot maxiter width height where "maxiter" denotes the maximum number of iterations at each point (default MAX_ITER) "width" denotes the width of the display window, in pixels (default X_RESN) "height" denotes the height of the display window, in pixels (default Y_RESN) and all three arguments are optional. Input: none, except the optional command-line arguments Output: a graphical display as described in Wilkinson & Allen, displayed using the X Window system, plus text output to standard output showing the above parameters, plus number of processes and execution time in seconds Original code obtained from Web site for Wilkinson and Allen's text on parallel programming: http://www.cs.uncc.edu/~abw/parallel/par_prog/ Reformatted and revised by B. Massingill, Jan 2001 to produce revised sequential version. Additional changes made for MPI. */ #include #include #include #include #include #include #include #include "mpi.h" #define X_RESN 800 /* default window width */ #define Y_RESN 800 /* default window height */ #define MAX_ITER 100 /* default max iterations */ /* region to display */ #define REAL_MIN -2 #define IMAG_MIN -2 #define REAL_MAX 2 #define IMAG_MAX 2 typedef struct complextype { float real, imag; } Compl; /* ---- Program for master process ----------------------------------- */ /* Contains most code from original main program, slightly modified for MPI To be called in process 0 only */ int master_process (int nprocs, int argc, char *argv[]) { /* Variables for graphical display */ Window win; /* initialization for a window */ unsigned int width = 0, height = 0, /* window size */ x, y, /* window position */ border_width, /* border width in pixels */ disp_width, disp_height, /* size of screen */ screen; /* which screen */ char *window_name = "Mandelbrot Set", *disp_name = NULL; GC gc; unsigned long valuemask = 0; XGCValues values; Display *display; XSizeHints size_hints; /* variable from original code, apparently unused */ /* Pixmap bitmap; */ /* XPoint points[800]; */ /* FILE *fp, *fopen (); */ /* char str[100]; */ XSetWindowAttributes attr[1]; unsigned long white, black, /* white, black pixel values */ min_color, max_color, /* min, max values for color */ color; float scale_real, scale_imag; /* scaling factors to map region to window */ /* Mandelbrot variables */ int maxiter = 0; /* maximum iterations */ int i, j, k; Compl z, c; float lengthsq, temp; /* Miscellaneous variables */ char dummy; /* do a scanf into this variable at end as a way to pause before exit */ double start_time, end_time; /* for computing execution time */ /* Process command-line arguments, if any */ /* Usage is: mandelbrot [maxiter] [width] [height] or mandelbrot -h to show usage message */ if ((argc > 1) && (strcmp(argv[1], "-h") == 0)) { fprintf (stderr, "Usage: mandelbrot [maxiter] [width] [height]\n"); exit (EXIT_FAILURE); } if (argc > 1) maxiter = atoi(argv[1]); if (argc > 2) width = atoi(argv[2]); if (argc > 3) height = atoi(argv[3]); maxiter = (maxiter > 0) ? maxiter : MAX_ITER; width = (width > 0) ? width : X_RESN; height = (height > 0) ? height : Y_RESN; /* Connect to Xserver */ if ( (display = XOpenDisplay (disp_name)) == NULL ) { fprintf (stderr, "drawon: cannot connect to X server %s\n", XDisplayName (disp_name) ); exit (EXIT_FAILURE); } /* Initialize for graphical display */ screen = DefaultScreen (display); disp_width = DisplayWidth (display, screen); disp_height = DisplayHeight (display, screen); x = 0; y = 0; /* window position */ border_width = 4; win = XCreateSimpleWindow (display, RootWindow (display, screen), x, y, width, height, border_width, BlackPixel (display, screen), WhitePixel (display, screen)); size_hints.flags = USPosition|USSize; size_hints.x = x; size_hints.y = y; size_hints.width = width; size_hints.height = height; size_hints.min_width = 300; size_hints.min_height = 300; XSetNormalHints (display, win, &size_hints); XStoreName(display, win, window_name); /* graphics context */ gc = XCreateGC (display, win, valuemask, &values); /* color values for white, black */ white = WhitePixel (display, screen); black = BlackPixel (display, screen); XSetBackground (display, gc, white); XSetForeground (display, gc, black); XSetLineAttributes (display, gc, 1, LineSolid, CapRound, JoinRound); attr[0].backing_store = Always; attr[0].backing_planes = 1; attr[0].backing_pixel = black; XChangeWindowAttributes(display, win, CWBackingStore | CWBackingPlanes | CWBackingPixel, attr); XMapWindow (display, win); XSync(display, 0); /* Get min and max for range of color values -- assumed to be defined by "white", "black" */ min_color = (white > black) ? black : white; max_color = (white > black) ? white : black; /* Compute scaling factors (to scale computational region to window */ scale_real = (float) (REAL_MAX - REAL_MIN) / (float) width; scale_imag = (float) (IMAG_MAX - IMAG_MIN) / (float) height; /* Start timing */ start_time = MPI_Wtime(); /* Calculate and draw points */ /* START OF SECTION TO CHANGE */ for(i=0; i < width; i++) for(j=0; j < height; j++) { z.real = z.imag = 0.0; /* scale display coordinates to actual region */ c.real = REAL_MIN + ((float) i * scale_real); c.imag = IMAG_MIN + ((float) j * scale_imag); k = 0; /* Calculate z0, z1, .... until divergence or max. iters */ do { temp = z.real*z.real - z.imag*z.imag + c.real; z.imag = 2.0*z.real*z.imag + c.imag; z.real = temp; lengthsq = z.real*z.real + z.imag*z.imag; k++; } while (lengthsq < 4.0 && k < maxiter); /* Scale color and display point */ color = ((k-1)*(max_color - min_color))/maxiter; XSetForeground (display, gc, color); XDrawPoint (display, win, gc, i, j); } /* END OF SECTION TO CHANGE */ /* End timing */ end_time = MPI_Wtime(); XFlush (display); /* Produce text output */ fprintf (stdout, "nprocs = %d, maxiter = %d, width = %d, height = %d\n", nprocs, maxiter, width, height); fprintf (stdout, "execution time in seconds = %g\n", end_time - start_time); /* Wait for user response, then return to main program */ fprintf (stderr, "Press enter to end program\n"); fscanf (stdin, "%c", &dummy); return EXIT_SUCCESS; } /* ---- Program for slave process ----------------------------------- */ /* To be called in each process other than process 0 */ int slave_process (int nprocs, int myID) { /* START OF SECTION TO CHANGE */ /* (put your code here) */ /* END OF SECTION TO CHANGE */ return EXIT_SUCCESS; } /* ---- Main program ------------------------------------------------ */ int main(int argc, char *argv[]) { int nprocs; int myid; int returnval; if (MPI_Init(&argc, &argv) != MPI_SUCCESS) { printf("MPI initialization error\n"); exit(EXIT_FAILURE); } (void) MPI_Comm_size(MPI_COMM_WORLD, &nprocs); (void) MPI_Comm_rank(MPI_COMM_WORLD, &myid); if (myid == 0) { printf("master process started\n"); returnval = master_process(nprocs, argc, argv); } else { printf("slave process started, id = %d\n", myid); returnval = slave_process(nprocs, myid); } (void) MPI_Finalize(); return returnval; }