Na programação de software, seria possível ter cargas de CPU e GPU em 100%?


43

Esta é uma pergunta geral sobre um assunto que achei interessante como jogador: gargalos na CPU / GPU e programação. Se não me engano, entendi que tanto a CPU quanto a GPU calculam coisas, mas essa é melhor em alguns cálculos que no outro devido à diferença na arquitetura. Por exemplo, quebrar hashes ou mineração de criptomoedas parece muito mais eficiente em GPUs do que em CPUs.

Então, eu me perguntei: ter uma GPU com carga de 100% enquanto a CPU é de 50% (por exemplo) é inevitável?

Ou, mais precisamente: alguns cálculos que normalmente são feitos pela GPU podem ser feitos pela CPU se o primeiro estiver com 100% de carga, para que ambos atinjam uma carga de 100%?

Eu pesquisei um pouco sobre o assunto, mas voltei de mãos vazias. Penso e espero que isso tenha seu lugar nesta subseção e esteja aberto a qualquer documentação ou palestra que você possa me dar!


53
É trivialmente possível que a CPU e a GPU executem um loop infinito de NO-OPs ao mesmo tempo, o que fará com que ambos tenham uma carga de 100%.
Jörg W Mittag

17
Seguindo o argumento de @ Jörg, a única coisa medida em% de CPU é a fração de tempo que não é gasta aguardando outros processadores. 100% pode ser bom se o programa for eficiente ou ruim se o programa for ineficiente. Na maioria das vezes, as pessoas se concentram no% da CPU como se fosse uma medida de desempenho - não é.
Mike Dunlavey

22
O Crysis original fez isso muito bem.
CubicleSoft

5
@ MikeDunlavey você traz um bom argumento. Nos carros, não medimos seu desempenho pelas RPM, medimos a velocidade.
Capitão Homem

1
@ JörgWMittag: A CPU, talvez. Porém, sistemas operacionais e GPUs interrompem os solucionadores de problemas para lidar com loops infinitos. Ou seja, se um shader não for concluído em um período de tempo razoável, ele morre e a GPU é redefinida.
Nicol Bolas

Respostas:


62

Teoricamente sim, mas na prática raramente vale a pena.

As CPUs e as GPUs estão completas , portanto, qualquer algoritmo que possa ser calculado por um também pode ser calculado pelo outro. A questão é quão rápido e conveniente.

Enquanto a GPU se destaca em fazer os mesmos cálculos simples em muitos pontos de dados de um grande conjunto de dados, a CPU é melhor em algoritmos mais complexos com muitas ramificações. Na maioria dos problemas, a diferença de desempenho entre as implementações de CPU e GPU é enorme. Isso significa que usar um para tirar o trabalho do outro quando está parado não levaria a um aumento notável no desempenho.

No entanto, o preço a pagar é que você precisa programar tudo duas vezes, uma para a CPU e outra para a GPU. Isso é mais do que o dobro de trabalho, porque você também precisará implementar a lógica de comutação e sincronização. Essa lógica é extremamente difícil de testar, porque seu comportamento depende da carga atual. Espere muito obscuro e impossível reproduzir bugs deste golpe.


1
Você mencionou que, na maioria dos problemas, a diferença de desempenho entre as implementações de CPU e GPU é enorme , na verdade, estou bastante interessado em saber até que ponto a diferença de desempenho vai. Você teria algum número ou artigo sobre isso (por exemplo, no exemplo de renderização 3D de textura)? Obrigado pela sua resposta e pelo seu tempo!
24516 MadWard

2
Você pode adicionar que há custos de desempenho para sincronização entre a CPU e a GPU, portanto, geralmente você deseja minimizar o número de transferências entre as duas. Além disso, adicionar ingenuamente ramificações para "não executar nos elementos em que a CPU já trabalhou" não compraria nada, pois os encadeamentos da GPU operam em trava de segurança.
Ethan

3
@gardenhead Nada no universo suporta recursão ilimitada, porque o universo é de tamanho finito e possui densidade de informações finita. A "perfeição de Turing" de um sistema é geralmente uma discussão sobre o que seria possível com essas restrições removidas.
Random832

3
Tenho poucas dúvidas de que uma GPU moderna esteja tecnicamente tão próxima da perfeição de Turing quanto um PC dos anos 80 ... no entanto, se você tentar executar algoritmos gerais em uma GPU, ela geralmente degenerará em um processador seqüencial que também não será necessário. mais rápido que um PC dos anos 80, portanto, a integridade de Turing de uma GPU é, na prática, dificilmente mais útil do que a integridade de Turing de Brainfuck .
leftaroundabout

7
@leftaroundabout GPUs modernas são trivialmente completas como qualquer CPU . A integridade de Turing não tem nada a ver com: 1) desempenho 2) legibilidade da fonte. A CPU dos anos 80 estava tão próxima do TC como todo o resto: ou eram TC ou não (a última opção não faz sentido).
Margaret Bloom

36

Não está relacionado à programação de jogos. Alguns códigos científicos também podem usar a GPU e a CPU.

Com uma programação cuidadosa e dolorosa, por exemplo, usando OpenCL ou CUDA , você pode carregar sua GPU e sua CPU perto de 100%. Muito provavelmente você precisará escrever diferentes partes de código para a GPU (o chamado código "kernel") e para a CPU, e algum código de cola chato (principalmente para enviar à GPU o código do kernel compilado).

No entanto, o código seria complexo e você provavelmente precisará ajustá-lo ao hardware específico em que está executando, principalmente porque a transmissão de dados entre GPU e CPU é cara.

Leia mais sobre computação heterogênea .

Veja também OpenACC , suportado por versões recentes do GCC (por exemplo, GCC 6 em junho de 2016)


1
Você está certo, minhas tags e título foram enganosos, removeram jogos e aumentaram o desempenho / otimização. Eu não quis dizer que era exclusivo dos jogos, mas foi aí que eu notei. Eu pensei que teria que ser muito específico de hardware também. Obrigado pela sua resposta e links!
MadWard 24/06

3
Isso acabaria com dois algoritmos. Eu tentei uma vez: imagem inteira de uma vez para GPU e várias imagens de uma vez para CPU (para abusar de cache grande). É realmente doloroso, especialmente para manter.
PTwr

11

Do ponto de vista da supercomputação, é melhor não pensar na porcentagem de carga da CPU / GPU, mas sim determinar quantas operações o seu problema em questão precisa e depois comparar isso com o desempenho máximo do sistema.

Se você obtiver 100% de utilização da CPU, isso não significa necessariamente que você obtém todo o desempenho do sistema. Muitas vezes, as CPUs podem fazer várias coisas diferentes ao mesmo tempo, digamos uma divisão e uma adição. Se você pode iniciar a divisão mais cedo, ela poderá se sobrepor à adição. A CPU da sua área de trabalho provavelmente possui uma unidade fora de ordem que reordenará as instruções para se beneficiar dessas sobreposições. Ou se você possui o seguinte programa:

if (expr1)
    expr2;
else
    expr3;

Uma CPU reordenada tentará calcular as três expressões ao mesmo tempo e depois descartará o resultado de uma delas. Isso o torna mais rápido no geral. Se você possui algum bloqueador em seu programa e não pode reordenar, está utilizando menos faixas na CPU, mas provavelmente ainda mostrará 100%.

Então você tem recursos SIMD nas CPUs, que são operações vetoriais. É como GPGPU-light no sentido de que você normalmente só tem quatro ou oito operações ao mesmo tempo, as GPUs têm 32 ou 64. Ainda assim, você precisa usá-lo para acionar os FLOPS.

Coisas como compartilhamento falso podem levar a um alto custo de sincronização que geralmente aparece como carga de kernel no Linux. A CPU é completamente usada, mas você não possui muita taxa de transferência útil.

Eu fiz alguma programação em uma máquina IBM Blue Gene / Q. Possui muitos níveis hierárquicos ( esquemático do Blue Gene / L desatualizado ) e, portanto, é difícil de programar com eficiência. Você precisará usar a hierarquia completa até SIMD e SMT (a Intel chama isso de HyperThreading) para obter o desempenho.

E então a rede geralmente limita você. Portanto, é mais rápido no tempo (relógio de parede) computar coisas em várias CPUs ao mesmo tempo, em vez de comunicá-las pela rede. Isso colocará mais carga nas CPUs e tornará o programa mais rápido. Mas a taxa de transferência real do programa não é tão boa quanto parece dos números brutos.

Se você adicionar GPUs à mistura, será ainda mais difícil orquestrar tudo isso para obter desempenho. Essa será uma das coisas que começarei a fazer na minha dissertação de mestrado Lattice QCD em alguns meses.


1

Você pode estar interessado em verificar o mecanismo do navegador Servo que está sendo desenvolvido na Mozilla Research e, mais especificamente, na Web Render (vídeo) .

Embora a mudança dinâmica de uma tarefa da CPU para a GPU possa ser impraticável, como mencionado em outras respostas (principalmente na Philip), pode ser prático estudar antecipadamente a carga da CPU / GPU em cargas de trabalho típicas e alternar algumas tarefas para as geralmente menos carregadas 1.

No caso do Web Render, a novidade é que tradicionalmente os navegadores realizam a maior parte do trabalho de renderização na CPU (ou seja, a CPU é usada para calcular quais objetos exibir, onde cortar, etc ...). A GPU normalmente é melhor nisso ... exceto que nem todos os casos de uso são triviais para implementar (seleção parcial, sombras ... e texto).

Uma versão inicial do Web Render mostrou-se altamente bem-sucedida no aumento de desempenho, mas não tentou resolver o problema da renderização de texto (e tinha algumas outras limitações). A Mozilla Research agora está trabalhando em uma segunda versão que se destina a ter menos limitações e, principalmente, para suportar a renderização de texto.

O objetivo, é claro, é descarregar o máximo possível do processo de renderização para a GPU, deixando a CPU livre para executar Javascript, atualizar o DOM e todas as outras tarefas.

Assim, embora não tão extrema como a sua sugestão, ele não ir para a direção da concepção de uma estratégia de computação com tanto CPU e GPU em mente.


0

Com foco nos jogos (desde que você o mencionou especificamente em sua postagem), existem algumas maneiras de equilibrar a carga. Um exemplo é "skinning", ou seja, animar um modelo. Para cada quadro a ser renderizado, você deve gerar as matrizes de transformação para cada quadro de animação e aplicá-lo aos vértices do modelo para transformá-lo na pose em que precisa estar. Você também precisa interpolar os quadros para obter um movimento suave , a menos que você queira que sua animação pareça com o Quake original (ou seja, irregular).

Nessa situação, você pode fazê-lo na CPU e carregar os resultados na GPU para renderização ou fazer o cálculo e a renderização na GPU. Acredito que hoje em dia isso é feito na GPU (conhecida como "aparência de hardware"): faz sentido, pois você tem cálculos relativamente simples que precisam ser executados milhares de vezes e cada vértice pode ser calculado simultaneamente desde o resultado do vértice A não tem influência no resultado do vértice B.

No entanto, em teoria, você pode alternar dinamicamente entre fazê-lo na CPU ou GPU, dependendo da sobrecarga da GPU e da CPU.

O principal bloqueador para fazer isso em todos os cálculos, porém, é que a CPU e a GPU têm pontos fortes e fracos diferentes. Trabalhos paralelos maciços são mais bem executados na GPU, enquanto tarefas lineares intensivas com ramificação são mais bem executadas na CPU. Apenas alguns trabalhos poderiam ser feitos realisticamente em ambos sem um sério impacto no desempenho.

No geral, o principal problema da programação da GPU (pelo menos no OpenGL e DirectX 11 e abaixo) é que você tem pouco controle sobre como a GPU interpreta seu código de sombreador. Ramificar dentro de um sombreador é arriscado, porque se você criar acidentalmente uma dependência entre os cálculos, a GPU poderá decidir começar a renderizar seus pixels um por um, girando 60fps para 10fps em um instante, apesar dos dados reais serem idênticos.


0

Um exemplo do mundo real é o mecanismo de renderização de código aberto LuxRender , capaz de carregar totalmente uma CPU e GPU ao mesmo tempo. Além disso, ele pode carregar várias GPUs ao mesmo tempo e também pode distribuir entre vários computadores.

O LuxRender usa o OpenCL para facilitar isso, embora também existam compilações sem o OpenCL.

Isso é prático porque os algoritmos que o LuxRender usa são altamente paralelizáveis. O algoritmo mais comum que o LuxRender usa é o rastreamento de caminhos , onde muitos caminhos de luz individuais podem ser calculados independentemente um do outro - uma situação ideal para a computação da GPU e uma que não requer sincronização complexa entre os nós de computação. No entanto, as limitações das GPUs (quantidades menores de memória, falta de suporte para alguns recursos complexos de renderização e falta geral de disponibilidade para alguns artistas) garantem que o suporte à CPU ainda seja essencial.


qual é o sentido de mostrar esta imagem, como é relevante para a pergunta?
mosquito

1
Ehh bem. Eu vou deletá-lo. Eu estava pensando que isso demonstraria facilmente que tipo de software é. Mas talvez seja realmente muito perturbador. (Há muitos tipos diferentes de motores de renderização; este é dirigido a stills fotorrealistas.)
PythonNut

0

Sim, certamente é possível.

Qualquer cálculo que uma CPU possa fazer, uma GPU também poderá fazer e vice-versa.

Mas é incomum porque:

  • Complexidade da engenharia Embora seja possível executar o mesmo código em uma CPU e GPU (por exemplo, CUDA), os processadores possuem diferentes habilidades e características de desempenho. Um é o MIMD; o outro, SIMD. O que é rápido em um é lento no outro (por exemplo, ramificação), então você precisa escrever um código separado para maximizar o desempenho.

  • As GPUs de eficiência de custos são agregadas muito mais poderosas que as CPUs. Toda a idéia das GPUs é usar processadores mais baratos, mais lentos, mas mais numerosos, para realizar cálculos muito mais rápidos do que as CPUs pelo mesmo custo. As GPUs são mais eficientes em termos de custo em uma ou duas ordens de magnitude.

Se o seu algoritmo for executado em GPUs, faz mais sentido otimizar para elas e adicionar quantas você precisar.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.