Parallel Programming in C for the Transputer
© D. Thiébaut, 1995
We now look at the complete program implementing the Mandelbrot set. The
program makes use of several new files that are included in the Tek[1 ] graphics package offered by Computer Systems
Architects. The header filegraph.h contains the prototypes of the
graphic functions. Most Borland's Turbo C graphic functions are
supported by the Tek package, making the transfer of Turbo C graphics program
written for a PC compatible to a transputer network almost instantaneous. The
cio.exe driver which normally runs on the host is replaced by tgio.exe, which
intercepts all the standard I/O functions along with the calls to the graphic
functions. Finally the library t4graph (for T400 transputers) or t8graph (for
T800 transputers) must be provided to the linker during the final linking
process.
/* =======================================================================
mandl_tf.c
DESCRIPTION:
Mandelbrot in C with floating point.
Runs on as few as one transputer, and uses two concurrent tasks
to display the mandelbrot set. One task relays points generated by
nodes down the link which are sending them back to PC, as well as
points generated by the second task. The second tasks implement the
mandelbrot set algorithm.
The program interfaces with tgio.exe running on the PC host.
Supports TurboC-type graphics function but relies on PC to
execute them.
TO COMPILE AND RUN:
make -f mandl_tf
chainnif -# 1 -1 mandl_tf -nif mandl_tf.nif
ld-net mandl_tf
ASSOCIATED NIF-FILE
buffer_size 200;
host_server tgio.exe;
level_timeout 400;
decode_timeout 2000;
1, mandl_tf, R0, 0, , ,;
====================================================================== */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "conc.h"
#include "graph.h"
/* =========================== DEFINITIONS ============================ */
#define SIZEINT ((int) sizeof(int))
#define NO_NODES 1 /* number of transputers */
/* This macro can be set */
/* between 1 and 5 */
/* =========================== PROTOTYPES ============================= */
void DoMandelbrot(void);
void Task1(Process *Task1P, Channel *softc);
void Task2(Process *Task2P, Channel *softc);
/* -------------------------------------------------------------------- */
/* MAIN */
/* -------------------------------------------------------------------- */
int main(void)
{
if (_node_number==1)
{
/* request auto detection */
int gdriver = DETECT, gmode, errorcode;
char *msg;
/* initialize graphics mode */
initgraph(&gdriver, &gmode, "C:\\TC_V3\\BGI");
/* read result of initialization */
errorcode = graphresult();
if (errorcode!=grOk) /* an error occurred */
{
printf("Graphics error: ");
grapherrormsg(errorcode, msg);
printf("%s\n", msg);
exit(1); /* return with error code */
}
/* do mandelbrot set */
DoMandelbrot();
/* clean up */
closegraph();
exit();
}
else
DoMandelbrot();
exit();
}
/* -------------------------------------------------------------------- */
/* DOMANDELBROT */
/* Generates mandelbrot set in (-2,-1.5)-(1,1.5) rectangle of the */
/* complex plane. */
/* -------------------------------------------------------------------- */
#define WS_SIZE 8192
void DoMandelbrot(void)
{
Process *Task1P, *Task2P;
Channel *softc;
softc = ChanAlloc();
Task1P = ProcAlloc(Task1, WS_SIZE, 1, softc);
Task2P = ProcAlloc(Task2, WS_SIZE, 1, softc);
if ((Task1P==NULL) || (Task2P==NULL) || (softc==NULL))
return;
ProcPar(Task1P, Task2P, 0);
ChanFree(softc);
ProcFree(Task1P);
ProcFree(Task2P);
}
/* -------------------------------------------------------------------- */
/* TASK2 */
/* Serves as a relay. */
/* -------------------------------------------------------------------- */
void Task2(Process *Task2P, Channel *softc)
{
int Buffer[3] = {0,0,0};
int Index;
int NotDoneYet = (NO_NODES>1)? 2: 1;
switch (_node_number)
{
case 1: while (NotDoneYet)
{
Index = ProcAlt(LINK1IN, softc, 0);
if (Index==1)
ChanIn(softc, (char *) Buffer, 3*SIZEINT);
else
ChanIn(LINK1IN, (char *) Buffer, 3*SIZEINT);
if (Buffer[0]==-1)
NotDoneYet--;
else
putpixel(Buffer[0], Buffer[1], Buffer[2]);
}
break;
case 2:
case 3:
case 4: while (NotDoneYet)
{
Index = ProcAlt(LINK1IN, softc, 0);
if (Index==1)
ChanIn(softc, (char *) Buffer, 3*SIZEINT);
else
ChanIn(LINK1IN, (char *) Buffer, 3*SIZEINT);
if (Buffer[0]==-1)
NotDoneYet--;
else
ChanOut(LINK0OUT, (char *) Buffer, 3*SIZEINT);
}
Buffer[0] =-1;
ChanOut(LINK0OUT, (char *) Buffer, 3*SIZEINT);
break;
case 5: do
{
ChanIn(softc, (char *) Buffer, 3*SIZEINT);
ChanOut(LINK0OUT, (char *) Buffer, 3*SIZEINT);
}
while (Buffer[0]!=-1);
}
}
/* -------------------------------------------------------------------- */
/* TASK1 */
/* Does the computation for each point */
/* -------------------------------------------------------------------- */
void Task1(Process *Task1P, Channel *softc)
{
float localXmin, localXmax, localYmin, localYmax;
float DeltaX, DeltaY, Cx, Cy;
int i, j, color;
float xn, yn, xn_1, yn_1, distance, MaxDist;
int maxcolor, maxx, maxy, StartOffset;
int Buffer[3];
if (_node_number==1)
{
maxcolor = getmaxcolor();
maxx = getmaxx();
maxy = getmaxy();
}
else
{
ChanIn(LINK0IN, (char *) &maxcolor, SIZEINT);
ChanIn(LINK0IN, (char *) &maxx, SIZEINT);
ChanIn(LINK0IN, (char *) &maxy, SIZEINT);
}
if (_node_number<NO_NODES)
{
ChanOut(LINK1OUT, (char *) &maxcolor, SIZEINT);
ChanOut(LINK1OUT, (char *) &maxx, SIZEINT);
ChanOut(LINK1OUT, (char *) &maxy, SIZEINT);
}
StartOffset = _node_number-1;
/*--- define threshold for Zn series ---*/
MaxDist = 100.0;
/*--- define boundaries (-2,-1.5) lower-left, (1,1.5) upper right---*/
localXmin =-2.0;
localXmax = 1.0;
localYmin =-1.5;
localYmax =+1.5;
/*--- define x and y increment for each pixel ---*/
DeltaX = (localXmax-localXmin)/maxx;
DeltaY = (localYmax-localYmin)/maxy;
/*--- start the loop. ---*/
Cx = localXmin+((_node_number-1) * DeltaX);
DeltaX = (localXmax-localXmin)*NO_NODES/maxx;
for (i = StartOffset; i<=maxx; i += NO_NODES)
{
Cy = localYmin;
for (j = 0; j<=maxy; j++)
{
xn = 0;
yn = 0;
for (color = 0; color<maxcolor; color++)
{
/*--- compute xn+1 = (xn*xn) - (yn*yn) + Cx ---*/
xn_1 = xn*xn-yn*yn+Cx;
/*--- compute yn+1 = 2*xn*yn + Cy ---*/
yn = 2*xn*yn+Cy;
/*--- update ---*/
xn = xn_1;
/*--- compute distance = xn*xn + yn*yn ---*/
distance = xn*xn+yn*yn;
if (distance>=MaxDist)
break;
}
/*--- we've exited the loop. Found out color of point ---*/
/*--- if color is black then don't "putpixel" it since ---*/
/*--- the background is already black! ---*/
if ((color<maxcolor) && (color!=BLACK))
{
Buffer[2] = color;
Buffer[0] = i;
Buffer[1] = j;
ChanOut(softc, (char *) Buffer, 3*SIZEINT);
}
Cy += DeltaY;
}
Cx += DeltaX;
}
/*--- tell other task that we are done ---*/
Buffer[0] =-1;
ChanOut(softc, (char *) Buffer, 3*SIZEINT);
}
Listing
4: Listing of Mandelbrot set program. This program works in conjunction with
tgio driver on the host. T8graph library contains graphics primitives to allow
the root transputer to access the graphics screen.