1 / 39

Eloiza Helena Sonoda

OOPS Object-Oriented Parallel System Um framework de classes para programação científica paralela. Eloiza Helena Sonoda. Orientador: Prof. Dr. Gonzalo Travieso. Apoio financeiro. Introdução.

ardice
Download Presentation

Eloiza Helena Sonoda

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. OOPSObject-Oriented Parallel SystemUm framework de classes para programação científica paralela. Eloiza Helena Sonoda Orientador: Prof. Dr. Gonzalo Travieso Apoio financeiro

  2. Introdução • O desenvolvimento da tecnologia dos microprocessadores tem resultado em grande desempenho dos computadores. • O processamento paralelo tem se mostrado bastante apropriado para satisfazer a demanda crescente de desempenho computacional. • Aumento na disponibilidade de sistemas paralelos.

  3. Introdução • Aplicações com alta demanda de poder computacional tendem a ser desenvolvidas usando programação concorrente para execução paralela. • A programação concorrente é bastante complexa e a responsabilidade de desenvolver aplicações paralelas eficientes acaba sendo do programador da aplicação. • Tornam-se necessárias ferramentas apropriadas para auxiliar no desenvolvimento de aplicações paralelas.

  4. Abordagens para o desenvolvimento de ferramentas • Compiladores paralelizantes. • Diretivas de paralelização. • Linguagens. • Bibliotecas.

  5. Motivação do trabalho Argumentamos que uma abordagem promissora é baseada em ferramentas convencionais de programação seqüencial acrescida de uma biblioteca de classes que forneça abstrações adequadas de concorrência.

  6. OOPS Object-Oriented Parallel System • Proposta. • Conceitos básicos. • Apresentação de classes e exemplos. Programa Usuário Framework OOPS Biblioteca MPI

  7. Proposta • Projeto e implementação do framework de classes OOPS para apoiar a programação científica paralela. • Características: • Voltado a aplicações científicas com necessidade de alto desempenho. • Técnicas de orientação a objetos para organizar o desenvolvimento do programa e encapsular detalhes de paralelismo.

  8. Proposta • Memória distribuída e passagem de mensagens. • Utiliza somente ferramentas convencionais de programação acrescida de uma biblioteca de classes. • Envolvimento do programador com aspectos paralelos de projeto. • Fornecimento de abstrações próximas aos modelos matemáticos.

  9. Proposta • Processadores virtuais. • Grupos de processadores virtuais. • Topologias. • Contêineres distribuídos. • Componentes paralelos. • Composições dos componentes paralelos: • Seqüencial. • Concorrente.

  10. Classes básicas • OOPS::Main • Componente paralelo principal, realiza inicialização e finalização da máquina virtual paralela. • OOPS::Group • Grupo de processadores virtuais. • OOPS::Sendable • Classe básica para objetos que serão comunicados.

  11. Classes básicas • OOPS::Partner • Parceiro em uma comunicação. • OOPS::Workgroup • Grupo de trabalho para comunicações. • OOPS::Topology • Estrutura de comunicação entre os processadores de um grupo. • OOPS::Distribution • Modos de distribuição de contêineres.

  12. Topologias • Derivadas de OOPS::Topology. • Fornece comunicação ponto a ponto entre os processadores de um grupo em um arranjo e comunicação coletiva em subgrupos. • OOPS::TopologyPlain • OOPS::TopologyPipe • OOPS::TopologyPipeRing • OOPS::TopologyLinear • OOPS::TopologyRing • OOPS::TopologyGrid • OOPS::TopologyTorus

  13. #include <iostream> #include <mpi++.h> int main(int argc, char **argv) { MPI::Init(argc, argv); int size, myID; size = MPI::COMM_WORLD.Get_size(); myID = MPI::COMM_WORLD.Get_rank(); int x = 0, tag = 99; if (!myID) { std::cout << "I have x = " << x << std::endl; x++; MPI::COMM_WORLD.Send(&x, 1, MPI::INT, 1, tag); } else { MPI::COMM_WORLD.Recv(&x, 1, MPI::INT, myID - 1, tag); std::cout << "I have x = " << x << std::endl; x++; if (myID != (size - 1)) MPI::COMM_WORLD.Send(&x, 1, MPI::INT, myID + 1, tag); } MPI::Finalize(); return 0; }

  14. #include <iostream> #include <mpi++.h> int main(int argc, char **argv) { MPI::Init(argc, argv); int size, myID; size = MPI::COMM_WORLD.Get_size(); myID = MPI::COMM_WORLD.Get_rank(); int next = myID + 1; int previous = myID - 1; if (!myID) previous = MPI::PROC_NULL; if (myID == size - 1) next = MPI::PROC_NULL; int x = 0, tag = 99; MPI::COMM_WORLD.Recv(&x, 1, MPI::INT, previous, tag); std::cout << "I have x = " << x << std::endl; x++; MPI::COMM_WORLD.Send(&x, 1, MPI::INT, next, tag); MPI::Finalize(); return 0; }

  15. #include <iostream>#include <oops> void OOPS::Main::executeOn(const OOPS::Group *allProcs) { OOPS::TopologyPipe topo(allProcs); int x = 0; topo.fromPrevious(x); std::cout << "I have x = " << x << std::endl; x++; topo.toNext(x);}

  16. Modos de distribuição dos contêineres • Derivadas de OOPS::Distribution. • Tamanhos locais. • Conversões entre índices locais e globais. • OOPS::DistributionBlocked • OOPS::DistributionCyclic • OOPS::DistributionNone

  17. Contêineres Distribuídos • Coleções de dados parametrizados no tipo do elemento armazenado. • Particionamento de dados determinado pela topologia e modo de distribuição. • OOPS::Vector<T> • OOPS::VectorRepl<T> • OOPS::Matrix<T>

  18. const int dim = 10000; void OOPS::Main::executeOn(const OOPS::Group *allProcs) { try { OOPS::TopologyLinear topo(allProcs); OOPS::DistributionBlocked block;OOPS::Vector<double> v1(dim, block, topo), v2(dim, block, topo), v(dim, block, topo); std::ifstream a1("vector1.dat"), a2("vector2.dat"); a1 >> v1; a2 >> v2;v = v1 * v2; std::ofstream saida("result.dat"); saida << v;double s = v.sum(); if (topo.group()->myID() == 0) std::cout << "Produto escalar = " << s << std::endl;} catch(Error_NotPositive e) { ...código... } catch(...) { std::cout << "\nOOPS!!\n " << std::endl; } }

  19. const int N = 1000; void OOPS::Main::executeOn(const OOPS::Group *allProcs) { try { OOPS::TopologyLinear topo_linear(allProcs); OOPS::TopologyGrid topo_grid(allProcs, allProcs->size()); OOPS::DistributionBlocked block; OOPS::DistributionNone none; OOPS::VectorRepl<double> a(N, topo_linear);OOPS::Vector<double> b(N, block, topo_linear); std::ifstream file_vec("vector.dat");file_vec >> a; OOPS::Matrix<double> m(N, N, block, none, topo_grid); std::ifstream file_mat(“matrix.dat");file_mat >> m; b = m * a; std::ofstream saida("result.dat"); saida << b; }}

  20. Estêncil

  21. Atualização de bordas fantasmas

  22. void OOPS::Main::executeOn(const OOPS::Group *allProcs) { try { OOPS::TopologyGridgrid(allProcs); OOPS::DistributionBlocked block; int M, N; double Ts, Ti, diff_limit; readArgs(M, N, Ts, Ti, diff_limit); int ghost = 1; OOPS::Matrix<double> a(M, N, block, block, grid, ghost), b(M, N, block, block, grid, ghost); ... inicialização das matrizes a e b ... double max_diff; do { b.syncGhostsCart(); for (int i = 0; i < b.localRowSize(); i++) for (int j = 0; j < b.localColSize(); j++) a.local(i,j) = (b.local(i,j-1) + b.local(i,j+1) + b.local(i-1,j) + b.local(i+1,j)) / 4.0; a.syncGhostsCart(); max_diff = 0;

  23. for (int i = 0; i < b.localRowSize(); i++) for (int j = 0; j < b.localColSize(); j++) { b.local(i,j) = (a.local(i,j-1) + a.local(i,j+1) + a.local(i-1,j) + a.local(i+1,j)) / 4.0; double diff = fabs(b.local(i,j) - a.local(i,j)); if (diff > max_diff) max_diff = diff; } grid.max(max_diff); } while (max_diff > diff_limit); std::ofstream result("result.dat");result << b; }}

  24. Intertopologias • Derivadas de OOPS::InterTopology. • Função parametrizada no tipo de componente OOPS::Execute<T>(), com T apresentando um método estático T::executeOn().

  25. Composição seqüencial void OOPS::Main::executeOn(const OOPS::Group *allProcs) { try{ OOPS::TopologyGrid topo_grid(allProcs); OOPS::DistributionBlocked block; int N; OOPS::Matrix<double> m(N, N, block, block, topo_grid); foo(m); bar(m); std::ofstream result("result.dat");result << m; }}

  26. Composição concorrente class InterTopologyPipe : public OOPS::InterTopology { OOPS::Partner *next, *prev;public: InterTopologyPipe(const OOPS::Group *g) : OOPS::InterTopology(g) { int n = g->myID() + 1; int p = g->myID() - 1; if (g->isFirst()) p = OOPS::PARTNER_NULL; if (g->isLast()) n = OOPS::PARTNER_NULL; next = new OOPS::Partner(g, n); prev = new OOPS::Partner(g, p); } void toNext(int &x) const { next->send(x); } void fromPrevious(int &x) const { prev->recv(x); }};

  27. class foo {public:static void executeOn(const OOPS::Group *g, const InterTopologyPipe *it);};class bar {public:static void executeOn(const OOPS::Group *g, const InterTopologyPipe *it);};void foo::executeOn(const OOPS::Group *g, const InterTopologyPipe *it) {int x; ... continuação do código ...it->toNext(x);}void bar::executeOn(const OOPS::Group *g, const InterTopologyPipe *it) { int x; it->fromPrevious(x); ... continuação do código ...}

  28. void OOPS::Main::executeOn(const OOPS::Group *allProcs) { try{ int n = 2; int *IDs; IDs = new int[n]; IDs[0] = 0; IDs[1] = 2; OOPS::Group *sub1 = allProcs->subGroup(n, IDs); IDs[0] = 1; IDs[1] = 3; OOPS::Group *sub2 = allProcs->subGroup(n, IDs); delete IDs; InterTopologyPipe *it = new InterTopologyPipe(allProcs); OOPS::Execute<foo>(sub1, it); OOPS::Execute<bar>(sub2, it);}}

  29. Desempenho • Programa para o cálculo do fractal de Mandelbrot. • Cluster Beowulf com 8 nós de processamento. • Testes realizados com matrizes 5000x5000.

  30. int compute_mandel(const double x, const double y) {// retorna o valor de mandelbrot para o complexo (x + iy)}void OOPS::Main::executeOn(const OOPS::Group *allProcs) { try{ OOPS::TopologyGrid grid(allProcs); OOPS::DistributionCyclic cyclic; int n_real, n_imag; double br, ur, bi, ui;readArgs(br, ur, bi, ui, n_real, n_imag); double rdelta = (ur - br) / n_real;double idelta = (ui - bi) / n_imag; OOPS::Matrix<int> mandel(n_imag, n_real, cyclic, cyclic, grid); for (int i = 0; i < mandel.localRowSize(); i++) for (int j = 0; j < mandel.localColSize(); j++) { OOPS::Matrix<int>::Index gi = mandel.localToGlobal(i,j); mandel.local(i,j) = compute_mandel(br+(gi.col()*rdelta)+rdelta/2, ui-(gi.row()*idelta)-idelta/2); } std::ofstream outFile("result.dat");outFile << mandel; }}

  31. int compute_mandel(const double x, const double y) {/* retorna o valor de mandelbrot para o complexo (x + iy)*/}int main(int argc, char *argv[]) { double lr, ur, li, ui, dx, dy;int rr, ir; FILE *arq;int **result; int i, j; double x, y; int ix, iy;int NP, p, NPr, NPi, pr, pi, lrr, lir; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &NP); MPI_Comm_rank(MPI_COMM_WORLD, &p);dx = (ur - lr) / rr; dy = (ui - li) / ir;/* Compute process grid dimensions */ NPr = (int)sqrt(NP); while (NP % NPr != 0) NPr--; NPi = NP/NPr; /* Compute position of the process on the grid */pi = p / NPr; pr = p % NPr;

  32. /* Compute local sizes */ lir = ir/NPi + (pi < (ir % NPi)); lrr = rr/NPr + (pr < (rr % NPr)); /* Allocate local pixels */ result = (int**)malloc(lir * sizeof(int*)); for (i = 0; i < lir; i++) result[i] = (int*)malloc(lrr*sizeof(int)); /* Compute distributed mandelbrot (cyclic distribution) */ for (iy = 0; iy < lir; iy++) { y = ui - (iy*NPi+pi) * dy; for (ix = 0; ix < lrr; ix++) {x = lr + (ix*NPr+pr) * dx;result[iy][ix] = compute_mandel(x + dx/2, y - dy/2); } } if (p > 0) { MPI_Request rq[lir]; MPI_Status st; /* Send result to process 0 */ for (iy = 0; iy < lir; iy++) MPI_Isend(result[iy], lrr, MPI_INT, 0, 0, MPI_COMM_WORLD, &rq[iy]); for (iy = 0; iy < lir; iy++) MPI_Wait(&rq[iy], &st); }

  33. else { /* Process 0: collect and write results */ int **finalresult; int partner; MPI_Status st; finalresult = (int**)malloc(ir * sizeof(int*)); for (i = 0; i < ir; i++) finalresult[i] = (int*)malloc(rr*sizeof(int)); for (iy = 0; iy < lir; iy++) for (ix = 0; ix < lrr; ix++) finalresult[iy*NPi][ix*NPr] = result[iy][ix]; for (partner = 1; partner < NP; partner++) { int ppi = partner / NPr; int ppr = partner % NPr;int plir = ir/NPi + (ppi < (ir % NPi));int plrr = rr/NPr + (ppr < (rr % NPr)); for (iy = 0; iy < plir; iy++)MPI_Recv(result[iy], plrr, MPI_INT, partner, 0, MPI_COMM_WORLD, &st); for (iy = 0; iy < plir; iy++) for (ix = 0; ix < plrr; ix++) finalresult[iy*NPi+ppi][ix*NPr+ppr] = result[iy][ix]; } /* Create output file */ } MPI_Finalize(); return 0;}

  34. Sobrecarga adicionada pelo OOPS

  35. Sugestões de trabalhos futuros • Extensão das classes desenvolvidas. • Entrada e saída paralela. • Balanceamento de cargas e criação dinâmica de tarefas. • Estruturas de dados irregulares.

More Related