Introduzione | Cap.1 | Cap.2 | Cap.3 | Cap.4 | Cap.5 | Appendice | Bibliografia
L' approccio piu' immediato per lo sviluppo di algoritmi paralleli
e' quello di partire da algoritmi sequenziali, individuare gli
eventuali passi indipendenti tra loro e arrivare a versioni parallele.
In questo stesso ambito, due sono le possibili vie da seguire.
Si puo' dividere il programma, per quanto possibile in tante attivita'
parallele (parallelismo fine-grain);oppure scomporlo nelle
sue componenti principali (parallelismo course-grain).
Per determinare quale dei due approcci sia il migliore bisogna
tener presente che l' obiettivo del calcolo parallelo e' l' incremento
delle prestazioni rispetto ai programmi scalari. Dal momento che
il parallelismo fine-grain ha bisogno di un maggiore overhead
di comunicazione, potrebbe capitare che una soluzione fine-grain
diventi piu' lenta di una soluzione sequenziale.
Per il programma si e' scelta un' implementazione course-grain. Piu' precisamente, dal momento che, ogni rettangolo della griglia e' indipendente dagli altri, si e' scelto di assegnare a processori diversi rettangoli diversi. La griglia viene quindi divisa in parti, tante quante il numero dei processori e ognuno di essi si occupa di tracciare le linee di livello nella parte assegnatagli.
La Fig.5.2 illustra una situazione tipica. La griglia rappresenta la matrice dei punti dati mentre le parti colorate rappresentano le zone assegnate ai processori. Dal momento che il numero dei rettangoli che formano la griglia non e', in generale, divisibile esattamente per il numero di processori, alcuni processori riceveranno un carico di lavoro maggiore rispetto ad altri. La figura riporta anche la percentuale di lavoro assegnato ad ogni processore. La Fig.5.3 riporta invece il caso ideale in cui il numero di rettangoli da processare e' diviso esattamente dal numero di processori. In tal caso infatti non ci sono rettangoli rimanenti e tutti i processori eseguono la stessa quantita' di lavoro.
Analizziamo adesso piu' da vicino i punti piu' importanti del
programma. Come tutti i programmi che girano sotto Express e'
necessario dapprima inizializzare alcune strutture necessarie
al sistema. Questo viene fatto dichiarando in un blocco COMMON
delle variabili opportune e chiamando la funzione KXINIT.
- - - - - - - - - - - -
COMMON /xpress/nocare,norder,nonode,ihost,ialnod,ialprc
INTEGER . . . . . ,nprocs(2)
DATA nprocs/2,2/
- - - - - - - - - - - -
EXTERNAL kxinit
CALL kxinit
- - - - - - - - - - - -
Con la chiamate alla funzione KXPARA si rendono disponibili al programma le informazioni sull' ambiente.
INTEGER env(4), . . . . . . .
- - - - - - - - - - - -
CALL kxpara(env)
- - - - - - - - - - - -
Piu' precisamente chiamando la funzione con un vettore di interi
(env) come argomento, essa restituisce, il numero di processori
con cui e' stato lanciato il programma in env(2) ed il NIP (numero
identificativo del processore) dei processori allocati in env(1).
Cio' permette una allocazione dinamica dei compiti e quindi permette
al programma di girare su un numero qualunque di processori. La
conseguenza piu' importante e' che l' applicazione girera' tanto
piu' veloce quanto piu' alto e' il numero di processori disponibili.
- - - - - - - - - - - - -
NumeroProcessori = env(2)
NumeroRetttangoli = xdim1 * ydim1
RettangoliPerProcessore =NumeroRettangoli / NumeroProcessori
RettangoliRimanenti = mod(NumeroRettangoli,NumeroProcessori)
- - - - - - - - - - - - -
C Costruzione di linee di livello per punti distribuiti regolarmente
C ai nodi di una griglia rettangolare
PROGRAM CONTOUR
INTEGER xdim,ydim,xdim1,ydim1
CHARACTER*8 cs(15)
REAL c(15)
COMMON /grid/grid(0:100,0:100)
COMMON /h/hx,hy
COMMON /origin/xx,yy
INTEGER NumProc,NumRet,RePrPr
INTEGER RetRim,process
COMMON /xpress/nocare,norder,nonode,ihost,ialnod,ialprc
INTEGER env(4),gbuffer(8192),nprocs(2)
DATA nprocs/2,2/
EXTERNAL kxinit
CALL kxinit
CALL kxpara(env)
CALL ksingl(6)
WRITE(*,*)'dominio in cui campionare la funzione:'
WRITE(*,*)'intervallo delle ascisse (a,b)'
READ(*,*) xx,xx1
WRITE(*,*)'intervallo delle ordinate (c,d)'
READ(*,*) yy,yy1
IF (xx .GE. xx1 .OR. yy .GE. yy1) STOP
WRITE(*,*)'num. punti sui lati della griglia'
READ(*,*) xdim
ydim=xdim
WRITE(*,*)'numero di linee di livello (max 14)'
READ(*,*) numlin
WRITE(*,*)'vettore delle linee di livello'
DO 5 i=1,numlin
READ(*,23) c(i),cs(i)
5 CONTINUE
23 FORMAT(f9.3,t1,a)
ydim1 = ydim - 1
xdim1 = xdim - 1
hx = (xx1 - xx) / xdim1
hy = (yy1 - yy) / ydim1
istat=kopenp(gbuffer,8192)
IF (istat .LT. 0) THEN
WRITE(*,*)'chiamata grafica fallita'
STOP
ENDIF
C chiama la sub che si occupa della definizione di un vettore per
C i colori delle linee di livello e della costruzione della legenda
CALL LEGENDA(numlin, cs)
C crea una viewport al centro dello schermo che conterra' il
C disegno e assegna ad essa il sistema di coordinate del grafico
ivp=kvport(.3,.3,.8,.8)
CALL kortho(xx,yy,xx1,yy1,0)
CALL krainb(0,15)
CALL kcolor(1)
C Costruisce una reticolazione del dominio in base ai dati forniti.
C i valori ai nodi della griglia sono forniti dalla funzione
FUNZ
DO 7 j=0,ydim1
y = yy + hy * j
DO 7 i=0,xdim1
x = xx + hx * i
grid(j, i) = funz(x,y)
7 CONTINUE
NumProc = env(2)
NumRet = xdim1 * ydim1
RePrPr =NumRet / NumProc
RetRim = mod(NumRet,NumProc)
process=env(1)
i = (process * RePrPr) / xdim1
j = mod((process * RePrPr),xdim1)
kk = 0
DO 10 k = 0,RePrPr - 1
IF ((j + kk) .ge. xdim1) THEN
i = i + 1
j = 0
kk = 0
ENDIF
CALL rettangolo(j+kk,i,c,numlin)
kk = kk + 1
10 CONTINUE
CALL kusend
IF (.NOT.(RetRim .EQ. 0)) THEN
IF (process .LT. RetRim) THEN
i = (NumProc * RePrPr + process) / xdim1
j = mod((NumProc * RePrPr + process),xdim1)
CALL rettangolo(j,i,c,numlin)
ENDIF
ENDIF
CALL kusend
DO 11 i=1,1000000
11 CONTINUE
CALL kclosp
END
C questa e' la definizione della funzione utilizzata per la
C costruzione della griglia
REAL FUNCTION funz (x, y)
C funz = x + y
C funz = 3 / 2 * (COS(3 / 5 * (y - 1)) + 5 / 4) / (1 + ((x - 4)
C * / 3) ** 2)
C funz = ABS(x + y)
funz = SIN(x ** 2) + COS(y ** 2) + SIN(x)
C funz = TAN(y - x) + 1
C funz = 8 / 3.14 * EXP(-8 * (x * x + y * y))
C funz = 9 * (3 / 4 * EXP(-(x - 3) ** 2 - (y - 3) ** 2) / 4) +
C * EXP(-(x / 7) ** 2 - (y / 10) - 1 / 5 * EXP(-(x - 5) ** 2 -
C * (y - 8) ** 2) + 1 / 2 * EXP((-(x - 8) ** 2 - (y - 4) ** 2) / 4))
END
C Calcola per interpolazione lineare l'ascissa del punto
C di ordinata c (linea di livello)
REAL FUNCTION interp(x1, z1, x2, z2, c)
IF ((z2 - z1).EQ.0) THEN
interp = 0
ELSE
interp = (c - z1) * (x2 - x1) / (z2 - z1)
END IF
END
C questa sub determina se la linea di livello specificata
C interseca questo lato e la posizione del punto.
SUBROUTINE lato (i, j, m, n, c, x, y, flag)
REAL interp
LOGICAL flag
COMMON /grid/grid(0:100,0:100)
COMMON /h/hx,hy
flag=.FALSE.
IF ((grid(i, j) .LE. c .AND. c .LE. grid(m, n)) .OR. (grid(m, n)
* .LE. c .AND. c .LE. grid(i, j))) THEN
x = j * hx + interp(j * hx, grid(i, j), n * hx, grid(m, n), c)
y = i * hy + interp(i * hy, grid(i, j), m * hy, grid(m, n), c)
flag =.TRUE.
END IF
END
C Costruisce la legenda.
C n e' il numero di linee di livello e c il vettore delle
linee
SUBROUTINE legenda (n, cs)
character*8 cs(n)
ivp1=kvport(.1,.1,.2,.8)
CALL kspace(0.,0.,50.,100.)
a = 0.
DO 22 i=1,n
CALL kbox(0.,a,10.,a+10,i,0)
CALL kdotex(cs(i),25.,a+5,0.,1,1)
a = a + 16
22 CONTINUE
CALL kusend
END
C questa sub processa il rettangolino della griglia individuato
C dagli indici i e j.
C c vettore delle linee di livello
C numlin numero delle linee di livello
SUBROUTINE rettangolo (i, j, c, numlin)
REAL x(4), y(4),c(numlin)
LOGICAL flag(1:4)
COMMON /origin/xx,yy
COMMON /h/hx,hy
CALL kcolor(1)
CALL kbox(xx+j*hx,yy+i*hy,xx+(j+1)*hx,yy+(i+1)*hy,0,1)
DO 25 k=1,numlin
CALL lato(i, j, i, j + 1, c(k), x(1), y(1), flag(1))
CALL lato(i, j, i + 1, j, c(k), x(2), y(2), flag(2))
CALL lato(i + 1, j, i + 1, j + 1, c(k), x(3), y(3), flag(3))
CALL lato(i + 1, j + 1, i, j + 1, c(k), x(4), y(4), flag(4))
DO 30 ii=1,4
IF (flag(ii)) THEN
x1 = x(ii)
y1 = y(ii)
DO 35 jj=ii+1,4
IF (flag(jj)) THEN
x2 = x(jj)
y2 = y(jj)
END IF
35 CONTINUE
CALL kcolor(k)
CALL kmove(xx+x1,yy+y1)
CALL kcont(xx+x2,yy+y2)
END IF
30 CONTINUE
flag(1) =.FALSE.
flag(2) =.FALSE.
flag(3) =.FALSE.
flag(4) =.FALSE.
25 CONTINUE
END
L' obiettivo del calcolo parallelo e' di ottenere una accellerazione degli algoritmi sfruttando al meglio le risorse dell' hardware. Affiche' l' utente sia capace di redigere algoritmi efficienti, egli deve essere capace di effettuare un' analisi accurata (profiling) dell' algoritmo per verificare la presenza di "colli di bottiglia" dovuti ad una poco razionale progettazione dell' algoritmo.
Il profiling di algoritmi paralleli e' molto piu' laborioso di quello di algoritmi sequenziali dal momento che entrano in gioco piu' fattori che influenzano le loro prestazioni. Il piu' ovvio, per un' architettura message-passing, e' la quantita' di tempo speso nello spedire e ricevere messaggi.
L' Express di Parasoft mette a disposizione dell' utente tre tool che permettono un' accurata analisi:
1) Execution Profiling;
2) Event Profiling;
3) Communication Profiling;
Per tutti e tre vengono fornite delle funzioni che ne permettono l' attivazione, la disattivazione e l' analisi. I tool descritti sono del tipo "post-mortem", cio' significa che i dati, durante l' esecuzione del programma, vengono accumulati in appositi buffers ed esaminati ad esecuzione terminata. Questo essenzialmente per due ragioni:
- la lentezza dell' I/O dei sistemi parralleli, sopratutto se paragonata alla grande potenza di calcolo di questi sistemi;
- la difficolta di analizzare la grandee mole di dati in tempo
reale durante l' esecuzione;
Il profilo dell' esecuzione riporta, per ogni nodo, il nome di tutte le funzioni o subroutine chiamate , il tempo di esecuzione di ciascuna funzione ed il numero di volte in cui questa e' stata invocata dal nodo, insieme ad una stima del tempo speso in stato "idle" (attesa).
Le funzioni che gestiscono il profilo dell' esecuzione sono:
- KXPINQ();
- KXPINI(buffer,buflen,f_start,scale);
- KXPON();
- KXPOFF();
La funzione KXPINQ() serve a controllare se il programma e' stato lanciato con lo switch -mx che attiva il profiling. Essa restituisce 1 se lo switch e' presente, zero altrimenti.
Tramite la KXPINI si specifica il buffer in cui immagazzinare i dati del profilo, la funzione da cui cominciare l' analisi, mentre il terzo parametro indica il numero di indirizzi da mappare per l' analisi statistica.
Le funzioni KXPON e KXPOFF rispettivamente attivano e disattivano il profilo inizializzato con la chiamata a KXPINI.
Un esempio del loro utilizzo e' il seguente:
C Set up dell' execution profiler
INTEGER PBUB(32768)
EXTERNAL KXINIT
- - - - - - - - - - - -
ISTX=KXPINQ()
IF (ISTX .NE. 0) THEN
CALL KXPINI(PBUF,32768,KXINIT,8192)
CALL KXPON
ENDIF
- - - - - - - - - - - -
C chiusura dell' execution profiler
IF (ISTX .NE. 0) CALL KXPOFF
Una volta ottenuti i dati questi possono essere analizzati mediante il comando xtool che apre il file "xprof.out" generato dal profiler. Questo file contiene delle tabelle, una per ogni nodo, che riportano tutte le funzioni attivate e le percentuali di tempo speso nel compiere lavoro utile e tempo speso in stato di attesa (idle).
Le comunicazioni tra processori hanno un ruolo importante nell' esecuzione di un programma, in quanto esse influenzano il tempo totale di elaborazione. Eseguire il profilo delle comunicazioni puo' aiutare a decidere la topologia del network da utilizzare.
Le funzioni che gestiscono il profilo delle comunicazioni sono:
- KCPINQ();
- KCPON();
- KCPOFF();
La funzione KCPINQ() serve a controllare se il programma e' stato lanciato con lo switch -mc che attiva il profiling. Essa restituisce 1 se lo switch e' presente, zero altrimenti.
Le funzioni KCPON e KCPOFF rispettivamente attivano e disattivano
il profilo.
Un esempio del loro utilizzo e' il seguente:
C Set up del communication profiler
ISTC=KCPINQ()
IF (ISTC .NE. 0) CALL KCPON
- - - - - - - - - - - -
C chiusura del comunication profiler
IF (ISTC .NE. 0) CALL KCPOFF
I dati vengono immagazzinati nel file "cprof.out"
generato dal profiler. Questo file contiene delle tabelle, una
per ogni nodo, che riportano il tempo speso nelle comunicazioni
tra i nodi, il tempo di I/O ed il tempo speso in calcolo.
Node 0
===========
Internode Communication : 0.00 milliseconds
I/O Communication : 3432.90 milliseconds
Calculation : 12520.45 milliseconds
Per effettuare l' analisi di singole porzioni di codice, si puo' invece utilizzare il profilo dell' evento. Tramite le routines:
- KEPINQ();
- KEPINI(buf,buflen,log_buf,lunl>);
- KEPON;
- KEPOFF;
l' utente puo' selezionare una parte del codice da analizzare. La KEPINI alloca due buffers destinati a contenere i dati del profilo. L' ampiezza di tali buffers deve essere sufficientemente ampia per evitare che alcuni dati vengano scartati, col risultato di invalidare tutta la procedura. La KEPINQ controlla lo stato dello switch -me sulla riga di comando del Cubix. Le KEPON e KEPOFF rispettivamente attivano e disattivano il profilo.
Il profilo dell' evento fornisce un meccanismo per analizzare
il codice piu' selettivamente. Per far cio' si utilizzano i "toggles",
particolari strutture con le quali si seleziona un segmento di
codice. Le routine che permettono il loro uso sono:
- KEPTGI(toggle, label);
- KEPTOG(toggle);
La prima serve ad inizializzare le strutture toggle e ad assegnare una etichetta all'evento che poi comparira' nel file di output del profilo. La seconda serve a definire la parte di codice da analizzare. Essa va infatti inserita prima e dopo l'evento.
Il comando che serve ad analizzare i dati del profilo accumulati
nei buffers e' etool. Esso apre il file "eprof.out"
generato dal profilo e riporta un' output del tipo:
Node 0
=========
| label | calls | total sec | average | variance |
|--------------------------------------------------------------------------|
| processo rett. riman | 0 | 0.000 | N/A | N/A |
| processo rettangolo | 9 | 0.016 | 0.002
| 0.001 |
La porzione di codice che segue riporta, invece, la definizione
delle strutture e dell'evento utilizzato per il profilo del programma
Contour. L' evento studiato e' il processo dei rettangoli che
formano la griglia. Le tabelle che seguono riportano, per ogni
nodo, il numero di volte in cui la subroutine e' stata chiamata
ed il tempo totale e medio impiegato.
C Variabili utilizzate per l'analisi del profilo
INTEGER LABBUF(256), LOGBUF(1024)
INTEGER TOGGLE1(20),TOGGLE2(20)
- - - - - - - - - - - - - - -
C Set up the event profiler.
CALL KEPINI(LABBUF, 4*256, LOGBUF, 4*1024)
CALL KEPTGI(TOGGLE1, 'processo rettangolo ')
CALL KEPTGI(TOGGLE2,'processo rettang. rimanenti ')
ISTE = KEPINQ()
IF(ISTE.NE.0) CALL KEPON
C
- - - - - - - - - - - - - - - - - - - -
CALL KEPTOG(toggle1)
CALL RETTANGOLO(J+KK,I,C,NUMLIN)
CALL KEPTOG(TOGGLE1)
C Se ci sono rettangoli rimanenti....
IF (.NOT.(RETRIM .EQ. 0)) THEN
CALL KEPTOG(TOGGLE2)
CALL RETTANGOLO(J,I,C,NUMLIN)
CALL KEPTOG(TOGGLE2)
- - - - - - - - - - - - - - - - -
C chiusura dell'event profiler
IF (ISTE .NE. 0) CALL KEPOFF
Ctool Version 3.1 -- Copyright (C) 1991 ParaSoft
Node 0
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3432.90 milliseconds
Calculation : 12520.45 milliseconds
Node 1
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3429.31 milliseconds
Calculation : 12516.86 milliseconds
Node 2
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3430.66 milliseconds
Calculation : 12515.46 milliseconds
Node 3
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3431.62 milliseconds
Calculation : 12514.37 milliseconds
Node 4
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3435.52 milliseconds
Calculation : 12510.40 milliseconds
Node 5
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3438.21 milliseconds
Calculation : 12508.16 milliseconds
Node 6
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3436.99 milliseconds
Calculation : 12509.38 milliseconds
Node 7
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3428.29 milliseconds
Calculation : 12517.70 milliseconds
Node 8
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3423.30 milliseconds
Calculation : 12522.69 milliseconds
Ctool Version 3.1 -- Copyright (C) 1991 ParaSoft
Node 0
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3295.87 milliseconds
Calculation : 13616.83 milliseconds
Node 1
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3296.38 milliseconds
Calculation : 13608.64 milliseconds
Node 2
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3296.83 milliseconds
Calculation : 13608.45 milliseconds
Node 3
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3297.92 milliseconds
Calculation : 13606.98 milliseconds
Node 4
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3301.63 milliseconds
Calculation : 13604.03 milliseconds
Node 5
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3304.45 milliseconds
Calculation : 13600.38 milliseconds
Node 6
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3297.34 milliseconds
Calculation : 13608.06 milliseconds
Node 7
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3284.35 milliseconds
Calculation : 13620.42 milliseconds
Ctool Version 3.1 -- Copyright (C) 1991 ParaSoft
Node 0
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3188.16 milliseconds
Calculation : 12840.77 milliseconds
Node 1
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3187.97 milliseconds
Calculation : 12834.37 milliseconds
Node 2
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3188.74 milliseconds
Calculation : 12832.83 milliseconds
Node 3
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3188.93 milliseconds
Calculation : 12833.28 milliseconds
Node 4
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3198.59 milliseconds
Calculation : 12823.17 milliseconds
Node 5
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3198.59 milliseconds
Calculation : 12823.87 milliseconds
Node 6
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3182.21 milliseconds
Calculation : 12839.55 milliseconds
Ctool Version 3.1 -- Copyright (C) 1991 ParaSoft
Node 0
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3072.13 milliseconds
Calculation : 14860.03 milliseconds
Node 1
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3069.18 milliseconds
Calculation : 14856.13 milliseconds
Node 2
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3074.75 milliseconds
Calculation : 14849.79 milliseconds
Node 3
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3081.34 milliseconds
Calculation : 14844.16 milliseconds
Node 4
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3082.50 milliseconds
Calculation : 14842.50 milliseconds
Node 5
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 3063.62 milliseconds
Calculation : 14862.21 milliseconds
Ctool Version 3.1 -- Copyright (C) 1991 ParaSoft
Node 0
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2955.78 milliseconds
Calculation : 14083.46 milliseconds
Node 1
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2965.57 milliseconds
Calculation : 14066.30 milliseconds
Node 2
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2962.94 milliseconds
Calculation : 14068.99 milliseconds
Node 3
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2970.24 milliseconds
Calculation : 14061.63 milliseconds
Node 4
===========
Internode Communication *: 0.00 milliseconds
I/O Communication : 2948.48 milliseconds
Calculation : 14083.58 milliseconds
Ctool Version 3.1 -- Copyright (C) 1991 ParaSoft
Node 0
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2829.50 milliseconds
Calculation : 13232.13 milliseconds
Node 1
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2831.23 milliseconds
Calculation : 13222.78 milliseconds
Node 2
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2842.88 milliseconds
Calculation : 13211.01 milliseconds
Node 3
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2818.43 milliseconds
Calculation : 13235.52 milliseconds
Ctool Version 3.1 -- Copyright (C) 1991 ParaSoft
Node 0
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2721.79 milliseconds
Calculation : 12187.90 milliseconds
Node 1
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2733.06 milliseconds
Calculation : 12169.28 milliseconds
Node 2
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2716.74 milliseconds
Calculation : 12185.73 milliseconds
Ctool Version 3.1 -- Copyright (C) 1991 ParaSoft
Node 0
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2561.73 milliseconds
Calculation : 13817.98 milliseconds
Node 1
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2561.47 milliseconds
Calculation : 13811.14 milliseconds
Ctool Version 3.1 -- Copyright (C) 1991 ParaSoft
Node 0
===========
Internode Communication* : 0.00 milliseconds
I/O Communication : 2447.23 milliseconds
Calculation : 11948.22 milliseconds
* Da notare la completa assenza di comunicazioni
tra i nodi.
Le figure che seguono riportano graficamente i risultati del profiling esposti in forma tabellare nelle pagine precedenti. Esse indicano il comportamento della velocita' (fig.5.4), speedup (fig.5.5) ed efficienza (fig.5.6) al crescere del numero di processori.
La fig.5.7 rappresenta invece una estrapolazione dei dati forniti
dalle varie prove effettuate. Facendo la media dei risultati ottenuti
utilizzando differenti funzioni, domini e numero di linee, la
figura indica un comportamento generale a cui "tendono"
gli algoritmi paralleli per il tracciamento di curve di livello.
Il risultato pressoche' ideale ottenuto e' giustificato dal fatto
che non sono necessarie comunicazioni tra i processori. Infatti
dal momento che la funzione dell' algoritmo e' tracciare le curve,
ogni processore puo' spedire i risultati delle proprie elaborazioni
al dispositivo grafico appena disponibili. In altre parole l'
attivita' dei processori e' completamente indipendente. Cio' non
e' sempre vero per gli algoritmi paralleli, in cui, in generale,
i risultati parziali dell' attivita' dei processori devono essere
ricombinati per giungere alla soluzione finale.
Introduzione | Cap.1 | Cap.2 | Cap.3 | Cap.4 | Cap.5 | Appendice | Bibliografia