Appendice A
File “EsempioAssistantV1.ast”:
/************************************************************************ Esempio di applicazione parallela per la validazione del modello ASSISTANT
Versione iniziale dell'applicazione di esempio con implementazioni task parallel (FARM) e data parallel (MAP) dei moduli Elabora e Presenta e realizzazione sequenziale dei moduli Genera.
Tesi di Gabriele Mencagli <[email protected]>
************************************************************************/ //Versione del programma con Switching delle implementazioni parallele //realizzate mediante replicazione dei PARMOD:
//Dimensione dei vettori di input e delle righe della matrice di output //dell'applicazione:
#define N 5000
//Lunghezza degli stream prodotti dai moduli Genera_*: #define STREAMLENGTH 500
//I tempi di attesa successivi sono espressi in microsecondi: //Intervallo tra la generazione di due item di Genera_1: #define WAITGEN1 80000
//Intervallo tra la generazione di due item di Genera_2: #define WAITGEN2 70000
//Intervallo tra la generazione di due item di Genera_3: #define WAITGEN3 60000
//I tempi di attesa successivi sono espressi in secondi: //Tempo di attesa per la funzione F eseguita da Elabora: #define WAITFFUNCTION 5
//Tempo di attesa per il calcolo della matrice eseguito da Presenta: #define WAITMATRIXCOMPUTATION 120
//I tempi di attesa successivi sono espressi in microsecondi:
//Tempo di attesa per il calcolo di una riga della matrice eseguito da //Presenta:
#define WAITROWMATRIXCOMPUTATION 24000 //Define utili:
#define TASK_PARALLEL 0 #define DATA_PARALLEL 1
//Main dell'applicazione di esempio per la validazione di ASSISTANT: generic main() {
stream long[N] input1Elabora; stream long[N] input2Elabora; stream long[N] input1ElaboraFarm; stream long[N] input2ElaboraFarm;
stream long[N] input1ElaboraMap; stream long[N] input2ElaboraMap; stream long[N] outputElaboraFarm; stream long[N] outputElaboraMap; stream long[N] input2Presenta;
stream long[N] outputElaboraPerFarm; stream long[N] input2PresentaFarm; stream long[N] outputElaboraPerMap; stream long[N] input2PresentaMap; stream long[N][N] outputPresentaFarm; stream long[N][N] outputPresentaMap; stream long switchingControl1; stream long switchingControl2; Genera1(output_stream input1Elabora); Genera2(output_stream input2Elabora); Genera3(output_stream input2Presenta); EnvControl1(output_stream switchingControl1); EnvControl2(output_stream switchingControl2);
Switching1(input_stream input1Elabora, input2Elabora, switchingControl1 output_stream input1ElaboraFarm,
input2ElaboraFarm, input1ElaboraMap, input2ElaboraMap); ElaboraFarm(input_stream input1ElaboraFarm, input2ElaboraFarm
output_stream outputElaboraFarm);
ElaboraMap(input_stream input1ElaboraMap, input2ElaboraMap output_stream outputElaboraMap);
Switching2(input_stream outputElaboraFarm, outputElaboraMap, input2Presenta, switchingControl2 output_stream
outputElaboraPerFarm, input2PresentaFarm, outputElaboraPerMap, input2PresentaMap);
PresentaFarm(input_stream outputElaboraPerFarm, input2PresentaFarm output_stream outputPresentaFarm);
PresentaMap(input_stream outputElaboraPerMap, input2PresentaMap output_stream outputPresentaMap);
Stampa(input_stream outputPresentaFarm, outputPresentaMap); }
//Definizione del modulo sequenziale Genera1. Nel documento è indicato //che e' un PARMOD per adesso lo consideriamo un sequenziale:
Genera1(output_stream long input1Elabora[N]) {
generaArray1(output_stream input1Elabora); }
//Definizione del modulo sequenziale Genera2. Nel documento è indicato //che e' un PARMOD per adesso lo consideriamo un sequenziale:
Genera2(output_stream long input2Elabora[N]) {
generaArray2(output_stream input2Elabora); }
//Definizione del modulo sequenziale Genera3. Nel documento è indicato //che e' un PARMOD per adesso lo consideriamo sequenziale:
Genera3(output_stream long input2Presenta[N]) {
generaArray3(output_stream input2Presenta); }
//Proc che genera uno stream di lunghezza STREAMLENGTH di vettori di N //long random:
proc generaArray1(output_stream long v[N]) inc<"stdlib.h", "unistd.h", "time.h">
//Definisco il seed utilizzato per la generazione dei numeri //pseudocasuali dei vettori di input:
time_t tempo;
tempo = time(&tempo); srand(((int) tempo) + 1); long vettore[N];
for(int count = 0; count < STREAMLENGTH; count++){
for(int i = 0; i < N; i++) vettore[i] = 1 + (long) (100.0*rand()/(RAND_MAX + 1.0));
//Attendo per un certo tempo in modo da simulare una //specifico tempo di interpartenza:
usleep(WAITGEN1);
assist_out(v, vettore); }
}c++$
//Proc che genera uno stream di lunghezza STREAMLENGTH di vettori di N //long random:
proc generaArray2(output_stream long v[N]) inc<"stdlib.h", "unistd.h", "time.h"> $c++{
//Definisco il seed utilizzato per la generazione dei numeri //pseudocasuali dei vettori di input:
time_t tempo;
tempo = time(&tempo); srand(((int) tempo) + 2); long vettore[N];
for(int count = 0; count < STREAMLENGTH; count++){
for(int i = 0; i < N; i++) vettore[i] = 1 + (long) (100.0*rand()/(RAND_MAX + 1.0));
//Attendo per un certo tempo in modo da simulare una //specifico tempo di interpartenza:
usleep(WAITGEN2);
assist_out(v, vettore); }
}c++$
//Proc che genera uno stream di lunghezza STREAMLENGTH di vettori di N //long random:
proc generaArray3(output_stream long v[N]) inc<"stdlib.h", "unistd.h", "time.h"> $c++{
//Definisco il seed utilizzato per la generazione dei numeri //pseudocasuali dei vettori di input:
time_t tempo;
tempo = time(&tempo); srand(((int) tempo) + 3); long vettore[N];
for(int count = 0; count < STREAMLENGTH; count++){
for(int i = 0; i < N; i++) vettore[i] = 1 + (long) (100.0*rand()/(RAND_MAX + 1.0));
//Attendo per un certo tempo in modo da simulare una //specifico tempo di interpartenza:
usleep(WAITGEN3);
assist_out(v, vettore); }
}c++$
//Definizione del modulo sequenziale che produce gli eventi esterni per //il primo switching:
EnvControl1(output_stream long switchingControl1){ env_switch(output_stream switchingControl1); }
//Definizione del modulo sequenziale che produce gli eventi esterni per //il secondo switching:
EnvControl2(output_stream long switchingControl2){ env_switch(output_stream switchingControl2); }
//Proc che genera gli eventi esterni: proc env_switch(output_stream long event) inc<"fstream","iostream">
$c++{
int choice;
bool scelta = false; bool finito = false; while(!finito){
while(!scelta){
cout << "Scegli lo switching da eseguire:" << endl; cout << "0 - TASK PARALLEL" << endl;
cout << "1 - DATA PARALLEL" << endl; cout << "2 - ESCI" << endl;
cin >> choice;
if((choice == 0)||(choice == 1)||(choice == 2)) scelta = true;
}
if(choice == 2) finito = true; else assist_out(event, choice); scelta = false;
} }c++$
//PARMOD ONE che stampa le matrici ricevute da Presenta su un file: parmod Stampa(input_stream long outputPresentaFarm[N][N], long outputPresentaMap[N][N]){
topology one pv; do input_section {
guard0: on , , outputPresentaFarm {
distribution outputPresentaFarm broadcast to pv; }
guard1: on , , outputPresentaMap {
distribution outputPresentaMap broadcast to pv; }
} while(true)
virtual_processors { elab0 (in guard0) { VP {
printMatrix(in outputPresentaFarm);
}
}
elab1 (in guard1) { VP { printMatrix(in outputPresentaMap); } } } }
//Modulo sequenziale che effettua la stampa su file delle matrici //calcolate da Presenta:
proc printMatrix(in long outp[N][N]) inc<"fstream","iostream">
$c++{
static int count = 1;
cout << "Il modulo Stampa ha ricevuto la matrice " << count << "/" << STREAMLENGTH << "" << std::endl; ;
std::ofstream f;
f.open ("FileMatrici.txt", fstream::out|fstream::app);
f << "Scrittura della matrice numero " << count << std::endl; for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++) f << outp[i][j] << " "; f << std::endl;
}
f << std::endl;
//Aggiorno l'indice delle matrici ricevute: count++;
//Controllo la fine dello stream: if (count > STREAMLENGTH){
//Fine della stampa su file:
f << "Fine della stampa delle matrici ricevute" << std::endl; }
f.close(); }c++$
//Proc per inizializzare l'attributo sulla modalita' di switching: proc init_attrib (out long a)
$c++{
//Inizialmente si usa un FARM: a = TASK_PARALLEL;
}c++$
//PARMOD ONE che esegue lo switching del modulo Elabora: parmod Switching1(input_stream long input1Elabora[N], long
input2Elabora[N], long switchingControl1 output_stream long input1ElaboraFarm[N], long input2ElaboraFarm[N], long input1ElaboraMap[N], long input2ElaboraMap[N]){ topology one pv;
attribute long behaviour onto pv; init {
//La modalita' di default e' TASK_PARALLEL: VP {
init_attrib (out behaviour); }
}
do input_section {
guard0: on ,, input1Elabora&&input2Elabora { distribution input1Elabora broadcast to pv;
distribution input2Elabora broadcast to pv; }
guard1: on ,, switchingControl1 {
distribution switchingControl1 broadcast to pv; }
} while(true)
virtual_processors {
elab0 (in guard0 out input1ElaboraFarm, input2ElaboraFarm, input1ElaboraMap, input2ElaboraMap) {
VP {
procSwitch(in input1Elabora, input2Elabora, behaviour output_stream input1ElaboraFarm,
input2ElaboraFarm, input1ElaboraMap, input2ElaboraMap);
}
}
elab1 (in guard1) { VP {
update_TaskMode(in switchingControl1 out behaviour);
}
}
output_section {
collects input1ElaboraFarm from ANY pv; collects input2ElaboraFarm from ANY pv; collects input1ElaboraMap from ANY pv; collects input2ElaboraMap from ANY pv; }
}
//Definizione della proc procSwitch eseguita dal parmod di Switching: proc procSwitch(in long A[N], long B[N], long mode output_stream long A1[N], long B1[N], long A2[N], long B2[N])
path<"/home/p4/mencagli/proveAssistant"> $c++{
//Effettuo lo switching in base alla modalita' attuale: if(mode == TASK_PARALLEL){ assist_out(A1, A); assist_out(B1, B); } if(mode == DATA_PARALLEL){ assist_out(A2, A); assist_out(B2, B); } }c++$
//Definizione della proc update_TaskMode eseguita dal parmod di Switching per modificare la modalita' di elaborazione:
proc update_TaskMode(in long mode out long bev) path<"/home/p4/mencagli/proveAssistant">
$c++{
if(mode == TASK_PARALLEL) cout << "ATTENZIONE MODIFICATA LA
MODALITA' DI ELABORAZIONE PASSAGGIO A TASK PARALLEL" << endl; else cout << "ATTENZIONE MODIFICATA LA MODALITA' DI ELABORAZIONE
PASSAGGIO A DATA PARALLEL" << endl;
cout <<"--- ---" << endl;
//Modifico il comportamento attuale: bev = mode;
}c++$
//Definizione del PARMOD Elabora (Versione FARM):
parmod ElaboraFarm(input_stream long input1ElaboraFarm[N], long input2ElaboraFarm[N] output_stream long outputElaboraFarm[N]) {
topology none pv; do input_section {
guard0: on ,, input1ElaboraFarm&&input2ElaboraFarm { distribution input1ElaboraFarm on_demand to pv;
distribution input2ElaboraFarm on_demand to pv; }
} while(true)
virtual_processors {
elab0 (in guard0 out outputElaboraFarm) { VP {
IteraF(in input1ElaboraFarm, input2ElaboraFarm out outputElaboraFarm);
}
} }
output_section {
collects outputElaboraFarm from ANY pv; }
}
proc IteraF(in long A[N], long B[N] out long C[N]) path<"/home/p4/mencagli/proveAssistant">
inc<"iostream","Function.h"> obj<"Function.o">
$c++{
//Attendo per un certo tempo in modo da simulare una specifico //tempo di interpartenza:
sleep(WAITFFUNCTION);
for(long i = 0; i < N; i++) C[i] = FunctionF(A[i], B);
cout << "Un worker di Elabora versione FARM ha prodotto un vettore C" << endl;
}c++$
//Definizione del PARMOD Elabora (Versione MAP):
parmod ElaboraMap(input_stream long input1ElaboraMap[N], long input2ElaboraMap[N] output_stream long outputElaboraMap[N]) { topology array [i:N] pv;
attribute long S1[N] scatter S1[*i0] onto pv[i0]; stream long ris;
do input_section {
guard0: on ,, input1ElaboraMap&&input2ElaboraMap {
distribution input1ElaboraMap[*i1] scatter to S1[i1]; distribution input2ElaboraMap broadcast to pv;
}
} while(true)
virtual_processors {
elab0 (in guard0 out ris) { VP i = 0..N-1 {
EseguiF(in S1[i], input2ElaboraMap out ris);
}
} }
output_section {
collects ris from ALL pv[i]{ long el; long local_result[N]; AST_FOR_EACH(el){ local_result[i] = el; } assist_out(outputElaboraMap, local_result); }<>; } }
//Definizione della proc EseguiF eseguita dai VP di Elabora versione MAP; proc EseguiF(in long a, long b[N] out long c)
path<"/home/p4/mencagli/proveAssistant"> inc<"iostream","Function.h">
obj<"Function.o"> $c++{
//Attendo per un certo tempo in modo da simulare una specifico //tempo di interpartenza:
usleep((WAITFFUNCTION * 1000000) / STREAMLENGTH); c = FunctionF(a, b);
cout << "Un worker di Elabora versione MAP ha prodotto un elemento della matrice C" <<endl;
}c++$
//PARMOD ONE che esegue lo switching del modulo Presenta:
parmod Switching2(input_stream long outputElaboraFarm[N], long
outputElaboraMap[N], long input2Presenta[N], long switchingControl2 output_stream long outputElaboraPerFarm[N], long
input2PresentaMap[N]){ topology one pv;
attribute bool vettorePresente; attribute long behaviour onto pv;
attribute long vettoreGenera[N] onto pv; init {
vettorePresente = false;
//La modalita' di default e' TASK_PARALLEL: VP {
init_attrib (out behaviour); }
}
do input_section {
guard0: on , !vettorePresente, input2Presenta { distribution input2Presenta broadcast to pv; operation {
vettorePresente = true; }<use {vettorePresente}> }
guard1: on ,vettorePresente, outputElaboraFarm { distribution outputElaboraFarm broadcast to pv; operation {
vettorePresente = false; }<use {vettorePresente}> }
guard2: on ,vettorePresente, outputElaboraMap { distribution outputElaboraMap broadcast to pv; operation {
vettorePresente = false; }<use {vettorePresente}> }
guard3: on ,, switchingControl2 {
distribution switchingControl2 broadcast to pv; }
} while(true)
virtual_processors { elab0 (in guard0) { VP {
updateVettore(in input2Presenta out vettoreGenera);
}
}
elab1 (in guard1 out outputElaboraPerFarm, input2PresentaFarm, outputElaboraPerMap, input2PresentaMap) { VP { procSwitch2(in outputElaboraFarm, vettoreGenera, behaviour output_stream outputElaboraPerFarm, input2PresentaFarm, outputElaboraPerMap, input2PresentaMap); } }
elab2 (in guard2) { VP {
procSwitch2(in outputElaboraMap, vettoreGenera, behaviour output_stream
outputElaboraPerFarm, input2PresentaFarm, outputElaboraPerMap, input2PresentaMap);
}
elab3 (in guard3) { VP {
update_TaskMode(in switchingControl2 out behaviour);
}
} }
output_section {
collects outputElaboraPerFarm from ANY pv; collects input2PresentaFarm from ANY pv; collects outputElaboraPerMap from ANY pv; collects input2PresentaMap from ANY pv; }
}
//Definizione della proc per aggiornare il vettore ricevuto da Genera_3: proc updateVettore(in long input2Presenta[N] out long vettoreGenera[N]) path<"/home/p4/mencagli/proveAssistant">
$c++{
for(int i = 0; i < N; i++) vettoreGenera[i] = input2Presenta[i]; }c++$
//Definizione della proc procSwitch eseguita dal PARMOD di Switching 2: proc procSwitch2(in long C[N], long D[N], long mode output_stream long
C1[N], long D1[N], long C2[N], long D2[N]) path<"/home/p4/mencagli/proveAssistant">
$c++{
//Effettuo lo switching in base alla modalita' attuale: if(mode == TASK_PARALLEL){ assist_out(C1, C); assist_out(D1, D); } if(mode == DATA_PARALLEL){ assist_out(C2, C); assist_out(D2, D); } }c++$
//Definizione del PARMOD Presenta (Versione FARM):
parmod PresentaFarm(input_stream long outputElaboraPerFarm[N], long input2PresentaFarm[N] output_stream long outputPresentaFarm[N][N]) {
topology none pv; do input_section {
guard0: on ,, outputElaboraPerFarm&&input2PresentaFarm { distribution outputElaboraPerFarm on_demand to pv;
distribution input2PresentaFarm on_demand to pv; }
} while(true)
virtual_processors {
elab0 (in guard0 out outputPresentaFarm) { VP {
CalcoloMatrice(in outputElaboraPerFarm,
input2PresentaFarm out outputPresentaFarm);
}
} }
output_section {
collects outputPresentaFarm from ANY pv; }
}
//Definizione della proc CalcoloMatrice eseguita dai VP di Presenta //versione FARM;
proc CalcoloMatrice(in long C[N], long D[N] out long E[N][N]) path<"/home/p4/mencagli/proveAssistant">
inc<"iostream","Function.h"> obj<"Function.o">
$c++{
//Attendo per un certo tempo in modo da simulare una specifico //tempo di interpartenza: sleep(WAITMATRIXCOMPUTATION); for(int i = 0; i < N; i++){ for(int j = 0; j < N; j++){ E[i][j] = FunctionG(C[i], D[j]); } }
cout << "Un worker di Presenta versione FARM ha prodotto una matrice E" << endl;
}c++$
//Definizione del PARMOD Presenta (Versione MAP):
parmod PresentaMap(input_stream long outputElaboraPerMap[N], long
input2PresentaMap[N] output_stream long outputPresentaMap[N][N]) { topology array [i:N] pv;
attribute long S2[N] scatter S2[*i0] onto pv[i0]; stream long ris[N];
do input_section {
guard0: on ,, outputElaboraPerMap&&input2PresentaMap { distribution outputElaboraPerMap[*i1] scatter to
S2[i1];
distribution input2PresentaMap broadcast to pv; }
} while(true)
virtual_processors {
elab0 (in guard0 out ris) { VP i = 0..N-1 {
ProdottoRowMatrix(in S2[i], input2PresentaMap out ris);
}
} }
output_section {
collects ris from ALL pv[i] {
static long result[N][N]; const long *el;
AST_FOR_EACH(el) { for(int j = 0;j < N;j++) result[i][j]=el[j]; } assist_out(outputPresentaMap,result); }<>; } }
//Definizione della proc ProdottoRowMatrix eseguita dai VP di Presenta //versione MAP:
proc ProdottoRowMatrix(in long c, long d[N] out long e[N]) path<"/home/p4/mencagli/proveAssistant">
inc<"iostream","Function.h"> obj<"Function.o">
$c++{
for(int i = 0; i < N; i++){ e[i] = FunctionG(c, d[i]); }
//Attendo per un certo tempo in modo da simulare una specifico //tempo di interpartenza:
cout << "Un worker di Presenta versione MAP ha prodotto una riga della matrice E" << endl;
}c++$
File “Function.h”:
/************************************************************************ Esempio di applicazione parallela per la validazione del modello
ASSISTANT
Versione iniziale dell'applicazione di esempio con implementazioni task parallel (FARM) e data parallel (MAP) dei moduli Elabora e Presenta e realizzazione sequenziale dei moduli Genera.
Tesi di Gabriele Mencagli <[email protected]>
************************************************************************/ //Dimensione dei vettori di input e della matrice di output
dell'applicazione: #define N 1000
//Funzione sequenziale F di elaborazione dei dati del modulo Elabora: long FunctionF(long A, long *B);
//Funzione sequenziale G di elaborazione dei dati del modulo Genera: long FunctionG(long C, long D);
File “Function.cpp”:
/************************************************************************ Esempio di applicazione parallela per la validazione del modello
ASSISTANT
Versione iniziale dell'applicazione di esempio con implementazioni task parallel (FARM) e data parallel (MAP) dei moduli Elabora e Presenta e realizzazione sequenziale dei moduli Genera.
Tesi di Gabriele Mencagli <[email protected]>
************************************************************************/ #include <iostream>
#include "Function.h"
//Funzione sequenziale F di elaborazione dei dati del modulo Elabora: long FunctionF(long A, long *B){
//Il calcolo eseguito dalla funzione per adesso e' banale ma si puo' modificare con
//qualcosa di piu' significativo: long count = 0; for(int i = 0; i < N; i++){ count += B[i]; } return A + (count / N); }
//Funzione sequenziale G di elaborazione dei dati del modulo Genera: long FunctionG(long C, long D){
long result;
//Il calcolo eseguito dalla funzione per adesso e' banale ma si puo' modificare con
//qualcosa di piu' significativo: if(C > D) result = C - D;
else result = D - C; return result;