É bastante claro em uma pesquisa do top500 que a indústria está tendendo a um aumento exponencial nos núcleos de processamento . Os maiores supercomputadores usam MPI para comunicação entre nós, embora não pareça haver uma tendência clara para o paralelismo entre nós, com a abordagem mais simples (mas não necessariamente a mais eficiente) para mapear um único processo MPI para cada núcleo, automático paralelização do compilador, OpenMP, pthreads, CUDA, Cilk e OpenCL.
Sou parte de um grupo de cientistas que mantêm e desenvolvem um código com potencial para ser usado em alguns dos maiores supercomputadores do mundo. Assumindo um tempo finito para o desenvolvedor, como me preparo para o futuro para que eu possa tirar proveito do desempenho da máquina mais poderosa do mundo? Que suposições devo fazer sobre a arquitetura de interconexão de processos? Que paradigmas sofrerão quando entrarmos na era dos muitos partidos? Os idiomas do espaço de endereçamento global particionado estarão disponíveis "em produção" em máquinas de escala reduzida?
fonte
Respostas:
Perspectiva histórica
É realmente impossível dizer como serão os novos paradigmas no futuro, por exemplo, uma boa perspectiva histórica que sugiro ler Rise and Fall of HPF, de Ken Kennedy . Kennedy dá conta de dois padrões emergentes, MPI versus um compilador inteligente, e detalha como o MPI teve a quantidade certa de adotantes iniciais e flexibilidade para dominar. O HPF finalmente resolveu seus problemas, mas já era tarde demais.
De várias maneiras, vários paradigmas, como PGAS e OpenMP, seguem a mesma tendência do HPF. Os códigos anteriores não eram flexíveis o suficiente para usar bem e deixaram muito desempenho em cima da mesa. Mas a promessa de não ter que escrever todos os pontos do algoritmo paralelo é um objetivo atraente. Portanto, a busca de novos modelos está sempre sendo buscada.
Tendências claras em hardware
Agora, o sucesso da MPI tem sido frequentemente citado por estar intimamente ligado à forma como modela o hardware em que é executado. Aproximadamente cada nó tem um número pequeno de processos e a transmissão das mensagens para ponto a ponto local ou através de operações coletivas coordenadas é facilmente realizada no espaço em cluster. Por causa disso, não confio em ninguém que dê um paradigma que não segue de perto as novas tendências de hardware. Na verdade, fiquei convencido dessa opinião pelo trabalho de Vivak Sarakar .
De acordo com isso, aqui estão três tendências que estão claramente avançando em novas arquiteturas. E deixe-me ser claro, agora existem doze arquiteturas diferentes sendo comercializadas no HPC. Isso ocorre há menos de 5 anos, apresentando apenas o x86, portanto, nos próximos dias haverá muitas oportunidades para o uso de hardware de maneiras diferentes e interessantes
Modelos Atuais
O modelo atual é na verdade 3 níveis de profundidade. Embora existam muitos códigos usando bem dois desses níveis, poucos surgiram usando os três. Acredito que, para chegar à exascala, é preciso investir na determinação de se o código pode ser executado nos três níveis. Este é provavelmente o caminho mais seguro para interagir bem com as tendências atuais.
Deixe-me iterar nos modelos e como eles precisarão mudar com base nas novas visualizações de hardware previstas.
Distribuído
Os players no nível distribuído se enquadram amplamente nas línguas MPI e PGAS. O MPI é um vencedor claro no momento, mas idiomas do PGAS, como UPC e Chapel, estão avançando no espaço. Uma boa indicação é o HPC Benchmark Challenge. Os idiomas do PGAS estão dando implementações muito elegantes dos benchmarks.
O ponto mais interessante aqui é que, embora atualmente este modelo funcione apenas no nível do nó, ele será um modelo importante dentro de um nó para arquiteturas de mosaico. Uma indicação é o chip Intel SCC, que agia fundamentalmente como um sistema distribuído. A equipe do SCC criou sua própria implementação MPI e muitas equipes tiveram êxito em portar bibliotecas da comunidade para essa arquitetura.
Mas, para ser sincero, o PGAS realmente tem uma boa história para entrar nesse espaço. Deseja realmente programar o internode MPI e depois fazer o mesmo truque intranode? Um grande problema com essas arquiteturas lado a lado é que elas terão velocidades de clock diferentes nos chips e grandes diferenças na largura de banda da memória, de modo que os códigos de desempenho devem levar isso em consideração.
Memória compartilhada no nó
Aqui vemos o MPI frequentemente sendo "bom o suficiente", mas PThreads (e bibliotecas derivadas de PThreads como Intel Parallel Building Blocks) e OpenMP ainda são usados com frequência. A visão comum é que haverá um momento em que haverá threads de memória compartilhada suficientes que o modelo de soquete da MPI quebrará para o RPC ou você precisará de um processo de menor peso executando no núcleo. Já é possível ver as indicações de sistemas IBM Bluegene com problemas com o MPI de memória compartilhada.
Como comenta Matt, o maior aumento de desempenho para códigos intensivos em computação é a vetorização do código serial. Enquanto muitas pessoas assumem que isso é verdade em aceleradores, também é crítico para máquinas no nó também. Acredito que Westmere tenha uma FPU de 4 largos, portanto, só é possível obter um quarto dos flops sem vetorização.
Embora eu não veja o OpenMP atual entrando bem nesse espaço, há um lugar para chips de baixa potência ou de ladrilhos usarem mais fios leves. O OpenMP tem dificuldade em descrever como o fluxo de dados funciona e, à medida que mais threads são usados, apenas vejo essa tendência se tornar mais exagerada; basta ver exemplos do que é preciso fazer para obter uma pré-busca adequada com o OpenMP.
Tanto o OpenMP quanto o PThreads em um nível suficiente do curso podem tirar proveito da vetorização necessária para obter uma boa porcentagem de pico, mas isso exige a quebra de seus algoritmos de uma maneira que a vetorização seja natural.
Coprocessador
Finalmente, o surgimento do coprocessador (GPU, MIC, acclerators Cell) ocorreu. Está ficando claro que nenhum caminho para a exascale será completo sem eles. No SC11, todos os participantes do prêmio Bell os usavam com muita eficiência para chegar aos petaflops baixos. Enquanto CUDA e OpenCL dominaram o mercado atual, tenho esperanças de que os compiladores OpenACC e PGAS entrem no espaço.
Agora, para chegar à exascala, uma proposta é acoplar os chips de baixa potência a muitos co-processadores. Isso eliminará muito bem a camada intermediária da pilha atual e usará códigos que gerenciam problemas de decisão no chip principal e embaralham o trabalho para os co-processadores. Isso significa que, para que o código funcione com bastante eficiência, uma pessoa deve repensar os algoritmos em termos de kernels (ou codelets), ou seja, fragmentos paralelos no nível da instrução sem ramificação. Até onde eu sei, uma solução para essa evolução é bastante aberta.
Como isso afeta o desenvolvedor do aplicativo
Agora, para chegar à sua pergunta. Se você deseja se proteger das complexidades que se aproximam das máquinas de escala exascória, faça algumas coisas:
Se você quer se apresentar hoje, o MPI + CUDA / OpenCL é bom o suficiente, mas o UPC está chegando lá, portanto, não é uma má idéia levar alguns dias e aprendê-lo. O OpenMP inicia, mas gera problemas quando o código precisa ser refatorado. PThreads requer reescrever completamente seu código para seu estilo. O que torna o MPI + CUDA / OpenCL o melhor modelo atual.
O que não é discutido aqui
Embora toda essa conversa sobre exascale seja agradável, algo que não é realmente discutido aqui é obter dados dentro e fora das máquinas. Embora tenha havido muitos avanços nos sistemas de memória, não os vemos no cluster de mercadorias (muito caro demais). Agora que a computação intensiva de dados está se tornando um grande foco de todas as conferências de supercomputação, é provável que haja um movimento maior no espaço de alta largura de banda da memória.
Isso leva a outra tendência que pode acontecer (se as agências de financiamento certas se envolverem). As máquinas se tornarão cada vez mais especializadas para o tipo de computação necessário. Já vemos máquinas "com muitos dados" sendo financiadas pela NSF, mas essas máquinas estão em uma trilha diferente da do Exascale Grand Challenge de 2019.
Isso se tornou mais do que o esperado, solicite referências onde você precisar deles nos comentários
fonte
Vamos começar discutindo uma estratégia para código intranodo (computação que não toca na interconexão), pois acho que o MPI é uma boa opção para código internode. Eu acho que não faz sentido falar em nós com menos de 100 núcleos, pelo menos uma GPU ou MIC atual.
É fato que os pthreads por si só não conseguem o máximo desempenho em qualquer chip moderno, porque você deve tirar proveito da unidade vetorial (verdadeira desde o primeiro Cray). Na Intel e AMD, você pode usar intrínsecos, mas estes não são portáteis e, na minha opinião, são desajeitados. CUDA e OpenCL têm vetorização incorporada na biblioteca e facilitam a obtenção do desempenho máximo. Todo o novo hardware de que tenho conhecimento tem esse requisito de vetor, portanto, qualquer solução deve levar isso em consideração. Para mim, CUDA / OpenCL é o caminho atual.
Em seguida, todas essas máquinas serão NUMA, o que é mais difícil de programar, mas acho que a estratégia do kernel funciona. Você divide trabalho e dados em pequenas unidades. Eles provavelmente serão agendados automaticamente, como acontece atualmente no CUDA e no OpenCL, mas você pode especificar dependências. Para problemas que se encaixam no paradigma de streaming, esse chunking também pode ser feito automaticamente. A Intel TBB faz isso, mas eu prefiro a abordagem de biblioteca de nível superior exemplificada por Thrust e Cusp , que pode atingir CUDA ou (em breve) TBB.
fonte
Vou tentar uma resposta mais curta do que alguns dos meus estimados colegas neste tópico ;-)
Minha mensagem para todos os meus alunos é sempre que o tempo do desenvolvedor é mais valioso que o tempo da CPU. Isso significa que se você tiver tempo para converter 100% do código com 80% de eficiência para rodar em grandes máquinas - usando uma abordagem de alto nível -, estará melhor do que quando usar um baixo nível que consome tempo abordagem que oferece 100% de eficiência em 20% do seu código. Como conseqüência, sou um grande fã de bibliotecas de alto nível. Os meus favoritos nesta área são os blocos de construção de encadeamento (TBB), pois permitem analisar algoritmos nos loops mais externos e em um nível alto. Ele também pode fazer todas as coisas que você pode querer fazer com pthreads, sem a grosseria de ter que lidar com funções do sistema operacional, etc. - então não OpenMP,
Não posso falar com autoridade sobre OpenCL, CUDA etc.
fonte
As respostas postadas anteriormente são excelentes, mas se concentraram principalmente na arquitetura dos nós, o que eu acho que reflete o fato de que o MPI geralmente é considerado suficiente como os modelos de programação entre nós na maioria dos casos e que é o paralelismo entre os modos em que lutamos.
Aqui estão minhas tentativas de responder a duas perguntas que ainda não foram respondidas ou respondidas de maneira relativamente limitada:
Que suposições devo fazer sobre a arquitetura de interconexão de processos?
Vou considerar três propriedades das redes:
A latência é inversamente proporcional à frequência. Sabemos que a escala de frequência estagnou. Portanto, pode-se concluir que é improvável que a latência diminua significativamente no futuro. A latência de envio-recv do MPI no Blue Gene / Q é de cerca de 2 nós, o que corresponde a 3200 ciclos. Mais da metade dessa latência é de software, mas boa parte dela é exigida pelo padrão MPI; um ajuste extenso pode reduzir a latência para perto de 1 nós, principalmente se for possível afirmar que os curingas MPI não serão usados.
De qualquer forma, a latência do hardware para injeção de pacotes nos sistemas Blue Gene e Cray é de cerca de 1 nós. De qualquer forma, aumentar a simultaneidade no nível do nó dificulta manter esse número tão baixo, mas estou otimista de que os projetistas de hardware encontrarão maneiras de manter a latência abaixo de 5 nós no futuro próximo.
A largura de banda da rede é trivialmente aumentada aumentando o número de links de rede. Isso é apenas parte da história, no entanto. Um coloca 1000 links de saída em um nó e não pode usá-los se o (s) processador (es) não puderem conduzir a rede com largura de banda total. Por exemplo, alguns supercomputadores afundam no barramento (por exemplo, HyperTransport) e não na rede, em termos de largura de banda de injeção.
Não há limites fundamentais para a largura de banda da rede, apenas os práticos. A largura de banda custa dinheiro e energia. Os projetistas de sistemas terão que levar em consideração as compensações entre a largura de banda da rede e outras partes da máquina ao desenvolver sistemas futuros. Muitos códigos não são limitados à largura de banda da rede; portanto, parece improvável que veremos máquinas com muito mais largura de banda por conexão no futuro. No entanto, a largura de banda por nó deve aumentar proporcionalmente à energia de computação, para que haja várias conexões por nó para aumentar a escala.
A terceira propriedade das redes que geralmente é negligenciada nos modelos formais é quantas mensagens podem ser enviadas uma única vez. Ter uma rede com 1 ns de latência e / ou 1 TB / s de largura de banda que só pode enviar 1 mensagem por vez seria totalmente inútil para a maioria dos usos. É importante poder enviar muitas mensagens de vários threads ao mesmo tempo e para a rede não entrar em colapso devido à contenção. Agora, os sistemas Cray e Blue Gene alcançam mais de 1 MMPS (milhão de mensagens por segundo). Não me lembro dos números exatos, mas ambos são capazes de atingir uma fração significativa do pico da largura de banda com pequenas mensagens. Uma rede ideal pode atingir a largura de banda máxima com qualquer mensagem de tamanho, mas na prática isso é impossível devido ao cabeçalho do pacote e às despesas gerais relacionadas à contabilidade. Contudo,
Esta é uma resposta incompleta e imperfeita. Outros são convidados a tentar melhorá-lo ou sugerir coisas que devo melhorar.
Os idiomas do espaço de endereçamento global particionado estarão disponíveis "em produção" em máquinas de escala reduzida?
Os sistemas Cray XE, XK e XC possuem um compilador UPC e CAF com qualidade de produção. Os sistemas Blue Gene podem ser entregues com XLUPC e XLCAF, mas ninguém pede isso para que não seja entregue. O PERCS possui compiladores XLUPC e XLCAF de nível de produção, mas não possui instalações em larga escala acessíveis à comunidade científica.
Os coarrays fazem parte do Fortran 2008, embora as implementações no Intel e no GNU Fortran ainda não sejam de alta qualidade. A implementação da Intel tem a reputação de funcionar, mas também é bastante lenta (há um artigo no PGAS12 sobre isso).
Quanto ao modelo de programação PGAS (como os modelos de programação - não as linguagens de programação - são o assunto da pergunta original), a biblioteca Global Arrays é uma aproximação razoável à qualidade da produção em muitos casos. Como tempo de execução, não é tão robusto quanto o MPI, mas o MPI é bastante exclusivo em termos de qualidade das implementações. A implementação do ARMCI-MPI do ARMCI torna o Global Arrays muito mais estável, embora mais lento em alguns casos.
É relativamente fácil implementar construções no estilo PGAS de uma maneira de qualidade de produção usando o MPI-3 RMA. Se alguém postar uma nova pergunta sobre isso, ficarei feliz em responder.
fonte
Quantidades realmente massivas de núcleos também abrem uma perspectiva trivial, mas surpreendentemente útil - apenas para usá-lo para executar muitas iterações de toda a simulação.
Hoje em dia, parte significativa da pesquisa computacional se resume a varrer algum espaço de parâmetro, rastrear um grande conjunto de condições iniciais ou calcular uma distribuição de algum resultado de maneira reamostragem; todas essas tarefas são embaraçosamente paralelas, portanto à prova de Amdahl.
fonte
Suspeito que mesmo as respostas mais bem pensadas para essa pergunta sejam obsoletas em cinco a dez anos. Dada a incerteza dos futuros paradigmas de programação, pode não valer a pena gastar muito tempo pré-otimizando sua base de código.
fonte
Eu estava prestes a postar esta resposta a esta pergunta , mas foi fechada como uma duplicata desta, então aqui vai:
Isso pode parecer um pouco salomônico, mas, na minha experiência, o futuro pertence ao híbrido abordagens nas quais vários nós com vários núcleos de memória compartilhada executando kernels com vários threads são conectados por meio de um paradigma de memória distribuída, como o MPI.
Existem, no entanto, alguns problemas e eles não envolvem o hardware. Primeiro de tudo, a maioria dos programadores paralelos investem pesadamente em códigos do tipo MPI e relutam em ser os primeiros a reimplementar partes, ou toda a sua base de códigos, usando um novo paradigma. A falta de pessoas que usam abordagens de memória compartilhada leva a um progresso mais lento nos algoritmos dessa área, o que faz com que qualquer investimento pareça ainda mais inútil.
Um segundo problema é que todo mundo associa o paralelismo de memória compartilhada ao OpenMP . Embora o OpenMP seja uma maneira rápida e fácil de resolver problemas pequenos e simples em um pequeno número de processadores, é um modelo de programação absolutamente terrível para o paralelismo real da memória compartilhada. Embora todos nós, em algum momento ou outro, aprendamos vários paradigmas simples e eficientes de programação paralela, por exemplo, pools de threads ou agendadores , eles não são fáceis de implementar usando o OpenMP e, francamente, esse não é o tipo de paralelismo que O OpenMP estimula os programadores a usar.
Em resumo, a barreira para passar de uma memória puramente distribuída para um paradigma de memória puramente / parcialmente compartilhada é bastante alta. Se você deseja usar os threads de maneira eficiente, precisa esquecer o OpenMP e gerenciar os threads e a concorrência (olá pthreads , adeus Fortran).
Mas por que mudar para uma abordagem híbrida? Bem, embora o MPI seja escalado para milhares de núcleos, o modelo subjacente é um dos padrões de sincronicidade e comunicação estática em etapas de bloqueio. Isso é bom para alguns problemas, por exemplo, simulações de bilhões de partículas, mas não é ideal para problemas mais difíceis ou de granulação mais fina. Os paradigmas de memória compartilhada facilitam muito o balanceamento de carga dinâmico e / ou a comunicação assíncrona, mas isso envolve um grande esforço de programação.
fonte