Professional Documents
Culture Documents
Wojciech Gałuszewski
(nr indeksu: 179956)
Cel projektu
Celem projektu jest wykorzystanie maszyn wielordzeniowych i wieloprocesorowych
oraz sieci maszyn, a także pewnych koprocesorów (np. na bazie kart graficznych) do
rozwiązywania złożonych zadań obliczeniowych.
Dzięki równoległemu, czyli jednoczesnemu, wykonywaniu obliczeń przez wiele
jednostek, można uzyskać znaczne przyśpieszenie w stosunku do obliczeń wykonywanych na
maszynie sekwencyjnej.
Implementacja
Podczas implementacji MPI głównym problemem z jakim trzeba się zmierzyć jest brak
współdzielonej pamięci. W moim przypadku aby „ciepło rozchodziło się” musi następować
ścisła komunikacja między poszczególnymi procesami. Dla ułatwienia postanowiłem dzielić
wierszami zadania dla poszczególnych procesów.
Kod przedstawiający podział zadań, wraz z inicjalizacją MPI przedstawia poniższy listing:
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &p);
MPI_Comm_rank(MPI_COMM_WORLD, &id);
Y_segment_min = (Y / p) * id;
Y_segment_max = (Y / p) + Y_segment_min;
if (id == 0)
{
Y_segment_min++; // Zakładam, że brzegi są zimne
printf("\nIlosc procesow: %i:\n", p);
}
printf("Robotnik: %i Przydzielony zakres OD %i DO %i \n", id, Y_segment_min,
Y_segment_max);
Aby poprawić czytelność programu algorytm zamiany tablic, dla czasów t, t+1
umieściłem w funkcji update().
Kod komunikacji między procesami przedstawia listing:
if (id == 0)
{
update(T1, T2, X, Y_segment_min, Y_segment_max + 1);
MPI_Send(&T2[(Y_segment_max - 1)*X], X, MPI_FLOAT, id + 1, 0, MPI_COMM_WORLD);
MPI_Recv(&T2[(Y_segment_max)*X], X, MPI_FLOAT, id + 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
if (id == (p - 1))
{
update(T1, T2, X, Y_segment_min, Y_segment_max);
MPI_Recv(&T2[(Y_segment_min - 1)*X], X, MPI_FLOAT, id - 1, 0, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
MPI_Send(&T2[(Y_segment_min)*X], X, MPI_FLOAT, id - 1, 0, MPI_COMM_WORLD);
50
MPI
Klaster 3x 2CPU
40
(OpenMP + MPI)
30
20
10
0
1 3 5 7 9 11
Ilość procesów
Działanie programu w różnych wariantach dla bardzo dużych ilości iteracji (1000000) oraz małej tablicy (100x100)
void update(float * T1, float * T2, int X, int Yp, int Yk)
{
for (int j = Yp; j < Yk - 1; j++)
{
for (int i = 1; i < X - 1; i++)
{
float T_SR = T1[i + X * j]; //Element srodkowy
float T_L = T1[(i + 1) + X * j]; //Element Lewy
float T_P = T1[(i - 1) + X * j]; //Element Prawy
float T_G = T1[i + X * (j + 1)]; //Element Gorny
float T_D = T1[i + X * (j - 1)]; //Element Dolny
T2[i + X * j] = 0.125*(4 * T_SR + T_L + T_P + T_G + T_D);
}
}
}
int main()
{
//********* WARTOSCI PODSTAWOWE *********
int X = 100; // Wielkosc tablicy elementow skonczonych X-Y
int Y = X; //Zakładam, ze tablica będzie kwadratowa
int ITER = 1000000; //Ilosc iteracji
//Zerowanie tablicy T1
for (int i = 0; i < X; i++) {
for (int j = 0; j < Y; j++) {
int index = i + j * X;
T1[index] = 0.0;
T2[index] = 0.0;
}
}
//Na potrzeby projektu zakladam, ze cieplo bedzie transferowane z jednego boku, a brzegi będą zimne
for (int j = 0; j < Y; j++) {
int index = j * X;
T1[index] = 99.0; //Ustawiam temperature na 99
T2[index] = 99.0; //Ustawiam temperature na 99
}
int id;
int p;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &p);
MPI_Comm_rank(MPI_COMM_WORLD, &id);
Y_segment_min = (Y / p) * id;
Y_segment_max = (Y / p) + Y_segment_min;
if (id == 0)
{
Y_segment_min++;
printf("\nIlosc procesow: %i:\n", p);
}
while (iter < ITER) //Glowna petla wykonujaca zadana ilosc przebiegow
{
if (p == 1)
{
update(T1, T2, X, Y_segment_min, Y_segment_max);
update(T2, T1, X, Y_segment_min, Y_segment_max);
}
if (p >= 2)
{
if (id == 0)
{
update(T1, T2, X, Y_segment_min, Y_segment_max + 1);
MPI_Send(&T2[(Y_segment_max - 1)*X], X, MPI_FLOAT, id + 1, 0, MPI_COMM_WORLD);
MPI_Recv(&T2[(Y_segment_max)*X], X, MPI_FLOAT, id + 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
if (id == (p-1))
{
update(T1, T2, X, Y_segment_min, Y_segment_max);
MPI_Recv(&T2[(Y_segment_min - 1)*X], X, MPI_FLOAT, id - 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
MPI_Send(&T2[(Y_segment_min)*X], X, MPI_FLOAT, id - 1, 0, MPI_COMM_WORLD);
if ((id == 0)&&(p>1))
for (int i = 1; i < p; i++)
{
MPI_Recv(&T1[(Y_segment_max*i)*X], Y_segment_max*X, MPI_FLOAT, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
}
MPI_Finalize();
if (id == 0)
{
startclock = (double)clock() - startclock; //Obliczenie czasu trwania programu
//Pokazanie wynikow na ekranie, wyświetlane jest tylko 20x20 komorek (ograniczonych do typu int)
for (int j = 0; j < 20; j++) //Zmiana tylko wnętrza tablicy "Zimne brzegi"
{
for (int i = 0; i < 20; i++)
{
int index = i * (X / 20) + j * (X*(X / 20));
if ((int)T1[index] < 10) printf(" ");
printf(" %i", (int)T1[index]);
}
printf("\n");
}
free(T1);
free(T2);
return 0;
}