Смекни!
smekni.com

Паралельні обчислення з використанням MPI (стр. 4 из 5)

MPI_Bcast(&acc_name, acc_name_len, MPI_CHAR, 0, MPI_COMM_WORLD); MPI_Barrier(MPI_COMM_WORLD);

MPI_Bcast(&acc_pass, acc_pass_len, MPI_CHAR, 0, MPI_COMM_WORLD); MPI_Barrier(MPI_COMM_WORLD);

printf("Proc %d: recv %s:: %s\n",myrank,acc_name,acc_pass);fflush(stdout);

char[256] ret_pass;

int result = do_decrypt_pass(&acc_pass, &ret_pass, myrank);

MPI_Ssend(&result, 1, MPI_INT, 0, TAG_RESULT, MPI_COMM_WORLD);

}

MPI_Finalize();

return 0;

}

===== Example4.cpp =====

У цьому прикладі головний процес (ранг 0) чекає підключення всіх підлеглих процесів (посилки ними повідомлення з тегом TAG_READY), розсилає рядок in_line усім підлеглим процесам, що намагаються підібрати пароль довжини myrank (тобто власний номер процесу). Власне зломом займається функція int do_decrypt_pass(char* incoming_pass_str, char * result_pass_str, int length)

Процеси повертають результат підбора c повідомленням TAG_RESULT. MPI_Barrier використовується для синхронізації. Висновок приклада:


Example4 output (np = 5)

Initializing

Feeding

Proc 1: recv apc:: 1234

Proc 2: recv apc:: 1234

Proc 3: recv apc:: 1234

Proc 1 returned 0

Proc 4: recv apc:: 1234

Proc 3 returned 0

Proc 2 returned 1

Proc 4 returned 1

У цьому прикладі всі процеси ламають той самий пароль, і новий цикл (не реалізований у прикладі) не почнеться, поки не завершать роботу всі процеси. Отже, час одного циклу визначається часом роботи процесу з максимальним рангом (тобто виконуючого підбор найбільшої довжини => перебір найбільшого числа комбінацій).

Приклад 5 показує більш зроблену систему, що читає з необхідну інформацію з файлу, і роздає кожному процесу по паролі. Процеси працюють в асинхронному режимі, зв'язуючи з головним процесом, що відіграє роль «роздавального-прийомного центра», організовуючи систему дуже схожу на «клієнта-сервер».

Завдання 2: Після вивчення коду поясніть, чому це не є системою клієнт-сервер.

===== Example5.cpp =====

#include <mpi.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

//типи повідомлень

#define TAG_MSG 98 // службове повідомлення – зміст перемінної – код (див. нижче)

#define TAG_SEND_NAMELEN 97 // пересилається довжина рядка імені

#define TAG_SEND_PASSLEN 96 // пересилається довжина рядка пароля

#define TAG_SEND_NAME 95 // пересилається рядок імені

#define TAG_SEND_PASS 94 // пересилається рядок імені

#define MSG_FAILURE 0 // невдача при розшифровці

#define MSG_SUCCESS 1 // успіх при розшифровці

#define MSG_READY 2 // клієнт готовий до прийому наступного пароля

#define MSG_GO_ON 3 // сигнал клієнту продовжувати роботу

#define MSG_BREAK 5 // сигнал клієнту завершити роботу

int do_decrypt_pass(int param);

int main(int argc, char* argv[])

{

int x,result;

char in_line[256],acc_name[256],acc_pass[256],racc_name[256],racc_pass[256];

int myrank, size;

MPI_Status status;

MPI_Init(&argc,&argv);

MPI_Comm_size(MPI_COMM_WORLD,&size);

MPI_Comm_rank(MPI_COMM_WORLD,&myrank);

if (myrank == 0) // kind'a Master Process

{

puts("Initializing"); fflush(stdout);

FILE* in_file = fopen("pass.txt","r");

char* p;

int allok=1,numclients=size-1;

int acc_name_len,acc_pass_len,racc_name_len,racc_pass_len;

while (allok || numclients)

{

MPI_Probe(MPI_ANY_SOURCE, TAG_MSG, MPI_COMM_WORLD, &status); // модель подій!

int src = status.MPI_SOURCE;

MPI_Recv(&result, 1, MPI_INT, src, TAG_MSG, MPI_COMM_WORLD, &status); // Чекаємо повідомлень від клієнтів

printf("<<< Proc %d returned %d&bsol;n",src,result);fflush(stdout);

switch(result)

{

case MSG_SUCCESS:

MPI_Recv(&racc_name_len, 1, MPI_INT, src,TAG_SEND_NAMELEN, MPI_COMM_WORLD, &status);

MPI_Recv(&racc_pass_len, 1, MPI_INT, src,TAG_SEND_PASSLEN, MPI_COMM_WORLD, &status);

MPI_Recv(&racc_name, racc_name_len, MPI_CHAR, src, TAG_SEND_NAME, MPI_COMM_WORLD, &status);

MPI_Recv(&racc_pass, racc_pass_len, MPI_CHAR, src, TAG_SEND_PASS, MPI_COMM_WORLD, &status);

printf ("[+] Proc %d got: %s:: %s&bsol;n",src,racc_name,racc_pass);fflush(stdout);

break;

case MSG_FAILURE:

MPI_Recv(&racc_name_len, 1, MPI_INT, src, TAG_SEND_NAMELEN, MPI_COMM_WORLD, &status);

MPI_Recv(&racc_name, racc_name_len, MPI_CHAR, src, TAG_SEND_NAME, MPI_COMM_WORLD, &status);

printf ("[-] Proc %d couldn't break: %s in set limits&bsol;n",src,racc_name);fflush(stdout);

break;

case MSG_READY: // є вільний робітник

if (!fgets(in_line,256,in_file)) allok =0; // готуємо account info

if (p = strtok(in_line,"::")) sprintf(acc_name,"%s",p); else allok= 0; //

if (p = strtok(NULL,"::")) sprintf(acc_pass,"%s",p); else allok= 0; //

if (allok) x = MSG_GO_ON; else { x = MSG_BREAK; numclients--;}// якщо є рядок – «згодовуємо»

MPI_Ssend(&x, 1, MPI_INT, src, TAG_MSG, MPI_COMM_WORLD);// її клієнту. Інакше (файл

// закінчився) – гасимо клієнта.

if (allok)

{

acc_name_len = strlen(acc_name)+1, acc_pass_len = strlen(acc_pass)+1;

printf (">>> Feeding %s:: %s to proc %d&bsol;n",acc_name,acc_pass, src);fflush(stdout);

MPI_Ssend(&acc_name_len, 1, MPI_INT, src,TAG_SEND_NAMELEN, MPI_COMM_WORLD);

MPI_Ssend(&acc_pass_len, 1, MPI_INT, src,TAG_SEND_PASSLEN, MPI_COMM_WORLD);

MPI_Ssend(&acc_name, acc_name_len, MPI_CHAR, src, TAG_SEND_NAME, MPI_COMM_WORLD);

MPI_Ssend(&acc_pass, acc_pass_len, MPI_CHAR, src, TAG_SEND_PASS, MPI_COMM_WORLD);

}

break;

}

}

printf ("[%d] Process exits&bsol;n",myrank);fflush(stdout);

}

else

{

int acc_name_len, acc_pass_len;

while (1)

{

x = MSG_READY;

MPI_Ssend(&x, 1, MPI_INT, 0, TAG_MSG, MPI_COMM_WORLD);// Посилаємо сигнал готовності

printf("[%d] Waiting&bsol;n",myrank);fflush(stdout);

MPI_Recv(&x, 1, MPI_INT, 0, TAG_MSG, MPI_COMM_WORLD, &status);

if (x == MSG_BREAK) // Вирішуємо, що робити далі

{

printf("[%d] BREAK received &bsol;n",myrank);fflush(stdout);

break;

}

MPI_Recv(&acc_name_len, 1, MPI_INT, 0,TAG_SEND_NAMELEN, MPI_COMM_WORLD, &status);

MPI_Recv(&acc_pass_len, 1, MPI_INT, 0,TAG_SEND_PASSLEN, MPI_COMM_WORLD, &status);

MPI_Recv(&acc_name, acc_name_len, MPI_CHAR, 0, TAG_SEND_NAME, MPI_COMM_WORLD, &status);

MPI_Recv(&acc_pass, acc_pass_len, MPI_CHAR, 0, TAG_SEND_PASS, MPI_COMM_WORLD, &status);

printf("[%d] Proc recv %s:: %s&bsol;n",myrank,acc_name,acc_pass);fflush(stdout);

int result = do_decrypt_pass(myrank);// Розшифровуємо пароль

switch (result) // Відсилаємо результат

{

case MSG_SUCCESS:

MPI_Ssend(&result, 1, MPI_INT, 0, TAG_MSG, MPI_COMM_WORLD);

MPI_Ssend(&acc_name_len, 1, MPI_INT, 0,TAG_SEND_NAMELEN, MPI_COMM_WORLD);

MPI_Ssend(&acc_pass_len, 1, MPI_INT, 0,TAG_SEND_PASSLEN, MPI_COMM_WORLD);

MPI_Ssend(&acc_name, acc_name_len, MPI_CHAR, 0, TAG_SEND_NAME, MPI_COMM_WORLD);

MPI_Ssend(&acc_pass, acc_pass_len, MPI_CHAR, 0, TAG_SEND_PASS, MPI_COMM_WORLD);

break;

case MSG_FAILURE:

MPI_Ssend(&result, 1, MPI_INT, 0, TAG_MSG, MPI_COMM_WORLD);

MPI_Ssend(&acc_name_len, 1, MPI_INT, 0,TAG_SEND_NAMELEN, MPI_COMM_WORLD);

MPI_Ssend(&acc_name, acc_name_len, MPI_CHAR, 0, TAG_SEND_NAME, MPI_COMM_WORLD);

break;

}

}

printf ("[%d] Process exits&bsol;n",myrank);fflush(stdout);

}

MPI_Finalize();

return 0;

}

int do_decrypt_pass(int param)

{

if (param % 2 == 0) return 1;

else return 0;

}

===== Example5.cpp =====

У цьому прикладі головний процес (master) займається керуванням іншими «робітниками» процесами (slave), а також відає постачанням і збором інформації. Підпрограма

MPI_Probe (int source, int tag, MPI_Comm comm, MPI_Status *status)

перевіряє наявність повідомлень, готових до прийому. Її варіант, неблокуючий - MPI_Iprobe(int source, int tag, MPI_Comm comm, int *flag, MPI_Status *status) - якщо повідомлення вже надійшло і може бути прийнято, повертається значення прапора «істина». Інакше (повідомлення надійшло нецілком) – «неправду». Виклик процедури, що блокуючий, MPI_Probe з параметрами MPI_ANY_SOURCE і MPI_ANY_TAG зупиняє виконання майстра-процесу до надходження якого-небудь повідомлення, реалізуючи в рамках процесу модель подій. Далі в залежності від повідомлення, що надійшло, майстер-процес або приймає результати (успіх/невдача) з висновком відповідного повідомлення, або видає робочому процесу черговий набір інформації інформації (логін-пароль). Якщо всі паролі вже роздані – робочому процесу посилається сигнал BREAK. Висновок приклада 5: Example5 output (np = 5)


Initializing

[2] Waiting

<<< Proc 2 returned 2

>>> Feeding apc:: 12345 to proc 2

[3] Waiting

<<< Proc 3 returned 2

>>> Feeding admin:: aa5632 to proc 3

[2] Proc recv apc:: 12345

[1] Waiting

<<< Proc 1 returned 2

>>> Feeding bionicman:: 3995d to proc 1

[3] Proc recv admin:: aa5632

[4] Waiting

<<< Proc 4 returned 2

>>> Feeding root:: *** to proc 4

[1] Proc recv bionicman:: 3995d

<<< Proc 2 returned 1

[4] Proc recv root:: ***

[+] Proc 2 got: apc:: 12345

<<< Proc 3 returned 0

[-] Proc 3 couldn't break: admin in set limits

<<< Proc 1 returned 0

[-] Proc 1 couldn't break: bionicman in set limits

<<< Proc 4 returned 1

[+] Proc 4 got: root:: ***

[2] Waiting

<<< Proc 2 returned 2

>>> Feeding vasya:: 1234nasja to proc 2

[3] Waiting

<<< Proc 3 returned 2

>>> Feeding jmanderley:: 1a2_+3 to proc 3

[2] Proc recv vasya:: 1234nasja

[1] Waiting

<<< Proc 1 returned 2

>>> Feeding man:: aa6321 to proc 1

[3] Proc recv jmanderley:: 1a2_+3

[4] Waiting

<<< Proc 4 returned 2

>>> Feeding demeter:: 3ss9951 to proc 4

[1] Proc recv man:: aa6321

<<< Proc 2 returned 1

[4] Proc recv demeter:: 3ss9951

[+] Proc 2 got: vasya:: 1234nasja

<<< Proc 3 returned 0

[-] Proc 3 couldn't break: jmanderley in set limits

<<< Proc 1 returned 0

[-] Proc 1 couldn't break: man in set limits

<<< Proc 4 returned 1

[+] Proc 4 got: demeter:: 3ss9951

[2] Waiting

<<< Proc 2 returned 2

>>> Feeding wheeljack:: *3472364%s to proc 2

[3] Waiting

<<< Proc 3 returned 2

[2] Proc recv wheeljack:: *3472364%s

>>> Feeding dalain:: 4nas5t to proc 3

[1] Waiting

<<< Proc 1 returned 2

[3] Proc recv dalain:: 4nas5t

>>> Feeding nobode:: * to proc 1

[4] Waiting

<<< Proc 4 returned 2

[1] Proc recv nobode:: *

>>> Feeding lamer:: password to proc 4

<<< Proc 2 returned 1

[4] Proc recv lamer:: password

[+] Proc 2 got: wheeljack:: *3472364%s

<<< Proc 3 returned 0

[-] Proc 3 couldn't break: dalain in set limits

<<< Proc 1 returned 0

[-] Proc 1 couldn't break: nobode in set limits

<<< Proc 4 returned 1

[+] Proc 4 got: lamer:: password

[2] Waiting

<<< Proc 2 returned 2

>>> Feeding cewl:: asfuh$Kjsfhdf&34kd to proc 2

[3] Waiting

<<< Proc 3 returned 2

>>> Feeding hacker:: to proc 3

[2] Proc recv cewl:: asfuh$Kjsfhdf&34kd

[1] Waiting

<<< Proc 1 returned 2

>>> Feeding LASTONE:: LASTPASS to proc 1

[3] Proc recv hacker::

[4] Waiting

<<< Proc 4 returned 2

<<< Proc 2 returned 1

[1] Proc recv LASTONE:: LASTPASS

[4] BREAK received

[4] Process exits

[+] Proc 2 got: cewl:: asfuh$Kjsfhdf&34kd

<<< Proc 3 returned 0

[-] Proc 3 couldn't break: hacker in set limits

<<< Proc 1 returned 0

[-] Proc 1 couldn't break: LASTONE in set limits

[2] Waiting

<<< Proc 2 returned 2

[3] Waiting

[2] BREAK received

[2] Process exits

<<< Proc 3 returned 2

[1] Waiting

[3] BREAK received

[3] Process exits

<<< Proc 1 returned 2

[0] Process exits

[1] BREAK received

[1] Process exits

3.4 Паралельне введення-виведення.

Останній приклад 6 показує, можна було вирішити ту ж задачу простіше:

===== Example6.cpp =====

#include <mpi.h>

#include <stdio.h>

#include <string.h>

int do_decrypt_pass(int param)

{

if (param % 2 == 0) return 1;

else return 0;

}

int main(int argc, char* argv[])

{

char in_line[256],acc_name[256],acc_pass[256];

FILE * file_in;

int myrank, size;

MPI_Init(&argc,&argv);

MPI_Comm_size(MPI_COMM_WORLD,&size);

MPI_Comm_rank(MPI_COMM_WORLD,&myrank);

file_in = fopen("pass.txt","r");

printf("[%d]: file open&bsol;n",myrank); fflush(stdout);

char* p;

for (int i=0; i<= myrank;i++) fgets(in_line,256,file_in);

while (!feof(file_in))

{

if (p = strtok(in_line,"::")) sprintf(acc_name,"%s",p);

if (p = strtok(NULL,"::")) sprintf(acc_pass,"%s",p);

printf("[%d] Read: %s:: %s&bsol;n",myrank,acc_name,acc_pass); fflush(stdout);

int result = do_decrypt_pass(myrank);

if (result ==1) {printf ("[+] Proc %d got: %s:: %s&bsol;n",myrank,acc_name,acc_pass);fflush(stdout);}

else {printf ("[-] Proc %d couldn't break: %s in set limits&bsol;n",myrank,acc_name);fflush(stdout);}

for (int i=0; i< size;i++) fgets(in_line,256,file_in);

}

printf ("[%d]: Process exits&bsol;n",myrank);fflush(stdout);

MPI_Finalize();

return 0;

}

===== Example6.cpp =====

У коді немає нічого нового, тому розбір його залишаємо на самостійне проробку.

Example6 output (np =)

[0]: file open

[0] Read: apc:: 12345

[1]: file open

[1] Read: admin:: aa5632

[-] Proc 1 couldn't break: admin in set limits

[1] Read: vasya:: 1234nasja

[+] Proc 0 got: apc:: 12345

[0] Read: root:: ***

[+] Proc 0 got: root:: ***

[0] Read: man:: aa6321

[-] Proc 1 couldn't break: vasya in set limits