Há algum benefício em usar a CPU em vez da GPU?

63

Pesquisei processadores e placas gráficas e descobri que as GPUs são muito mais rápidas que as CPUs. Li neste artigo que uma GPU Nvidia de 2 anos superou em 14 vezes o processador Intel Core I7 de 3,2 GHz por 14 vezes em determinadas circunstâncias. Se as GPUs são tão rápidas, por que os desenvolvedores não as usam para todas as funções de um jogo? É possível que as GPUs façam outra coisa que não gráficos?

Daniel Pendergast
fonte
17
Se você estiver em um jogo em que está transferindo tudo para a GPU e sua CPU quase não estiver fazendo nada, poderá obter um aumento de desempenho colocando parte da carga de volta na CPU.
Tetrad
3
sua GPU sua talvez melhor do que o seu CPU, mas eu não acho que sua placa de vídeo é melhor do que sua placa-mãe (e não vou comparar o sistema operacional para o motorista lol)
e-MEE
27
GPU is faster than a CPUé um falso mito no qual muitas pessoas são levadas a acreditar depois de ver benchmarks baseados em problemas especificamente voltados para a GPU (essa classe de problemas é chamada de "problemas paralelos embaraçosamente paralelos"), veja minha resposta nesta pergunta do superusuário: Por que ainda estamos usando CPUs em vez de GPUs?
Lie Ryan
5
Uma vantagem é que cada computador tem um CPU :)
Tim Holt

Respostas:

50

"Eu li que os carros de F1 são mais rápidos do que aqueles que dirigimos nas ruas ... por que as pessoas não usam carros de F1 então?" Bem ... A resposta a esta pergunta é simples: os carros de F1 não podem quebrar ou girar tão rápido quanto a maioria dos carros (o carro mais lento poderia vencer um F1 nesse caso). O caso das GPUs é muito semelhante, elas são boas em seguir uma linha reta de processamento, mas não são tão boas quando se trata de escolher diferentes caminhos de processamento.

Um programa executado na GPU faz sentido quando deve ser executado várias vezes em paralelo, por exemplo, quando você precisa misturar todos os pixels da Textura A com pixels da Textura B e colocá-los todos na Textura C. Essa tarefa, quando executada em uma CPU, seria processado da seguinte forma:

for( int i =0; i< nPixelCount; i++ )
     TexC[i] = TexA[i] + TexB[i];

Mas isso é lento quando você precisa processar muitos pixels; portanto, a GPU, em vez de usar o código acima, apenas usa o próximo:

     TexC[i] = TexA[i] + TexB[i];

e preenche todos os núcleos com este programa (essencialmente copiando o programa para o núcleo), atribuindo um valor ipara cada um. Então é aí que vem a mágica da GPU e faz com que todos os núcleos executem o programa ao mesmo tempo , realizando muitas operações muito mais rapidamente do que o programa de CPU linear poderia fazer.

Essa maneira de trabalhar é boa quando você precisa processar da mesma maneira muitas entradas pequenas, mas é muito ruim quando você precisa criar um programa que possa ter ramificações condicionais. Então agora vamos ver o que a CPU faz quando se trata de alguma verificação de condição:

  • 1: Execute o programa até a primeira operação lógica
  • 2: Avaliar
  • 3: Continue executando a partir do resultado do endereço de memória da comparação (como em uma instrução JNZ asm)

Isso é muito rápido para a CPU definir um índice, mas para a GPU fazer o mesmo, é muito mais complicado. Como o poder da GPU vem da execução da mesma instrução ao mesmo tempo (eles são núcleos SIMD), eles devem ser sincronizados para poder tirar proveito da arquitetura do chip. Ter que preparar a GPU para lidar com filiais implica mais ou menos:

  • 1: Crie uma versão do programa que segue apenas a ramificação A, preencha esse código em todos os núcleos.
  • 2: Execute o programa até a primeira operação lógica
  • 3: Avalie todos os elementos
  • 4: Continue processando todos os elementos que seguem a ramificação A, enfileire todos os processos que escolheram o caminho B (para o qual não há programa no núcleo!). Agora, todos os núcleos que escolheram o caminho B estarão inativos !! - o pior caso é um único núcleo em execução e todos os outros núcleos apenas esperando.
  • 5: Quando o processamento for concluído, ative a versão da ramificação B do programa (copiando-a dos buffers de memória para uma pequena memória principal).
  • 6: Executar ramificação B.
  • 7: Se necessário, misture / mescle os dois resultados.

Esse método pode variar com base em muitas coisas (ou seja, algumas muito pequenasas filiais podem ser executadas sem a necessidade dessa distinção), mas agora você já pode ver por que a ramificação seria um problema. Os caches da GPU são muito pequenos, você não pode simplesmente executar um programa a partir da VRAM de maneira linear, ele precisa copiar pequenos blocos de instruções para os núcleos a serem executados e se você tiver ramificações suficientes, sua GPU ficará mais parada do que executando. qualquer código, que não faz sentido quando se executa um programa que segue apenas uma ramificação, como a maioria dos programas, mesmo que seja executado em vários threads. Em comparação com o exemplo da F1, seria como abrir para-quedas de freio em cada esquina e sair do carro para guardá-los de volta no carro até a próxima esquina em que você deseja virar novamente ou encontrar um semáforo vermelho (a próxima esquina provavelmente).

É claro que há o problema de outras arquiteturas serem tão boas na tarefa de operações lógicas, muito mais baratas e mais confiáveis, padronizadas, mais conhecidas, com baixo consumo de energia, etc. As placas de vídeo mais recentes dificilmente são compatíveis com as mais antigas sem emulação de software. use instruções asm diferentes entre eles, mesmo sendo do mesmo fabricante, e que, por enquanto, a maioria dos aplicativos de computador não exige esse tipo de arquitetura paralela e, mesmo que precisem, eles podem usar através de APIs padrão, como OpenCL como mencionados pelo eBusiness, ou através das APIs gráficas. Provavelmente em algumas décadas teremos GPUs que podem substituir CPUs, mas não acho que isso aconteça tão cedo.

Eu recomendo a documentação do AMD APP, que explica muito sobre a arquitetura da GPU, e também vi sobre a NVIDIA nos manuais da CUDA, o que me ajudou muito a entender isso. Ainda não entendo algumas coisas e posso estar enganado, provavelmente alguém que sabe mais pode confirmar ou negar minhas declarações, o que seria ótimo para todos nós.

Pablo Ariel
fonte
6
analogia estranha, mas é um bom argumento the fastest isn't always the fastest.
Lie Ryan
11
Obrigado! Eu acho que é um tópico interessante, porque vincula muitos conceitos de programação de jogos à maneira como o hardware funciona, o que é um pouco esquecido na terra das linguagens de alto nível atuais. Gostaria de acrescentar outras coisas, mas escrever a resposta já levou algum tempo, então tentarei atualizá-la mais tarde, como os recursos de "modo protegido" das CPUs, a velocidade do barramento de memória, etc., mas espero que isso esclareça algumas desvantagens técnicas de executar tudo no gpu.
Pablo Ariel
6
A analogia seria muito melhor se fosse precisa. Os carros de F1 têm tremendas habilidades de frenagem, o que lhes permite manter a alta velocidade em uma curva em vez de começar a frear com bastante antecedência. Encurralar em alta velocidade também é melhor graças às altas forças descendentes, embora o raio de virada provavelmente não seja ótimo para estacionamentos. Melhores razões podem incluir a falta de espaço de armazenamento, o espelho retrovisor, o ar-condicionado, o controle de cruzeiro, a proteção contra os elementos, os assentos dos passageiros, a suspensão e a distância ao solo para lidar com estradas precárias ou várias outras coisas comuns em veículos de passageiros.
amigos estão
5
@ Pablo Ariel Estou respondendo à declaração: "Os carros de F1 não podem quebrar ou girar tão rápido quanto a maioria dos carros". Você sugere que os carros de F1 só podem acelerar em linha reta e não são muito bons em curvas ou durante a desaceleração. Mas os carros de F1 podem realmente travar muito mais rapidamente do que "a maioria dos carros" e são excelentes nas curvas em alta velocidade.
GargantuChet
4
A analogia é mais preciso se você pensa em Dragsters em vez de carros de F1
Agustin Meriles
32

GPUs são muito boas tarefas paralelas. O que é ótimo ... se você estiver executando tarefas paralelas.

Os jogos são sobre o tipo de aplicativo menos paralelizável. Pense no loop principal do jogo. A IA (vamos supor que o jogador seja tratado como um caso especial da AI) precisa responder a colisões detectadas pela física. Portanto, ele deve ser executado posteriormente. Ou, no mínimo, a física precisa chamar rotinas de IA dentro dos limites do sistema de física (o que geralmente não é uma boa ideia por muitas razões). Os gráficos não podem ser executados até que a física seja executada, porque é a física que atualiza a posição dos objetos. Obviamente, a IA também precisa ser executada antes da renderização, pois pode gerar novos objetos. Os sons precisam ser executados após a IA e os controles do jogador

Em geral, os jogos podem se alinhar de muito poucas maneiras. Os gráficos podem ser desmembrados em um thread; o loop do jogo pode empurrar um monte de dados no segmento de gráficos e dizer: renderize this. Ele pode fazer alguma interpolação básica, para que o loop principal do jogo não precise estar sincronizado com os gráficos. O som é outro segmento; o loop do jogo diz "play this" e é reproduzido.

Depois disso, tudo começa a ficar dolorido. Se você tiver algoritmos de processamento complexos (como os de RTS), poderá encadear esses. Pode levar alguns quadros para que os algoritmos sejam concluídos, mas eles serão simultâneos pelo menos. Além disso, é bem difícil.

Então, você está analisando quatro tópicos: jogo, gráficos, som e possivelmente processamento de AI a longo prazo. Isso não é muito. E isso não é suficiente para GPUs, que podem ter literalmente centenas de threads em execução ao mesmo tempo. É isso que dá às GPUs seu desempenho: poder utilizar todos esses threads de uma vez. E os jogos simplesmente não podem fazer isso.

Agora, talvez você possa ir "longe" em algumas operações. As IAs, por exemplo, geralmente são independentes uma da outra. Assim, você pode processar várias dezenas de IAs ao mesmo tempo. Até que você realmente precise torná-los dependentes um do outro. Então você está com problemas. Objetos de física são igualmente independentes ... a menos que haja uma restrição entre eles e / ou colidem com alguma coisa. Então eles se tornam muito dependentes.

Além disso, há o fato de que a GPU simplesmente não tem acesso à entrada do usuário, o que, pelo que entendi, é meio importante para os jogos. Então isso teria que ser fornecido. Também não possui acesso direto a arquivos ou qualquer método real de comunicação com o sistema operacional; então, novamente, teria que haver algum tipo de maneira de fornecer isso. Ah, e todo esse processamento de som? GPUs não emitem sons. Então eles precisam voltar para a CPU e depois para o chip de som.

Ah, e a codificação para GPUs é terrível. É difícil acertar, e o que é "certo" para uma arquitetura de GPU pode estar muito, muito errado para outra. E isso não é apenas mudar da AMD para a NVIDIA; isso pode estar mudando de uma GeForce 250 para uma GeForce 450. Essa é uma mudança na arquitetura básica. E poderia facilmente fazer com que seu código não funcionasse bem. C ++ e até C não são permitidos; o melhor que você obtém é o OpenCL, que é parecido com o C, mas sem alguns detalhes. Como recursão . É isso mesmo: sem recursão nas GPUs.

Depurando? Ah, espero que você não goste dos recursos de depuração do IDE, porque esses certamente não estarão disponíveis. Mesmo se você estiver usando GDB, dê um beijo de despedida. Você terá que recorrer à printfdepuração ... espere, não há printfGPUs. Portanto, você terá que gravar nos locais da memória e fazer com que seu programa de stub da CPU os leia novamente.

É isso mesmo: depuração manual . Boa sorte com isso.

Além disso, essas bibliotecas úteis que você usa em C / C ++? Ou talvez você seja mais do tipo .NET, usando XNA e assim por diante. Como queiras. Não importa, já que você não pode usar nenhum deles na GPU. Você deve codificar tudo do zero. E se você já possui uma base de código, é difícil: é hora de reescrever todo esse código.

Então sim. É horrível fazer qualquer tipo de jogo complexo. E nem funcionaria, porque os jogos simplesmente não são paralelos o suficiente para ajudar.

Nicol Bolas
fonte
21

Por que não é tão fácil de responder - é importante observar que as GPUs são processadores especializados que não são realmente destinados ao uso generalizado como uma CPU comum. Devido a essa especialização, não é de surpreender que uma GPU possa superar uma CPU pelas coisas para as quais foi especificamente projetada (e otimizada), mas isso não significa necessariamente que possa substituir a funcionalidade e o desempenho completos de uma CPU generalizada.

Suspeito que os desenvolvedores não façam isso por vários motivos, incluindo:

  • Eles querem que os gráficos sejam da qualidade mais rápida e mais alta possível, e o uso de recursos valiosos da GPU pode interferir nisso.

  • O código específico da GPU pode ter que ser escrito, e isso provavelmente introduzirá complexidade adicional na programação geral do jogo (ou aplicativo) em questão.

  • Uma GPU normalmente não tem acesso a recursos como placas de rede, teclados, mouses e joysticks; portanto, não é possível lidar com todos os aspectos do jogo.

Em resposta à segunda parte da sua pergunta: Sim, existem outros usos. Por exemplo, projetos como o SETI @ Home (e provavelmente outros projetos BOINC) estão usando GPUs (como os da nVidia) para cálculos complexos de alta velocidade:

  Execute o SETI @ home em sua GPU NVIDIA
  http://setiathome.berkeley.edu/cuda.php

( Gostei da sua pergunta porque ela apresenta uma ideia interessante. )

Randolf Richardson
fonte
18

As CPUs são mais flexíveis, geralmente é mais fácil programá-las, elas podem executar threads únicos muito mais rapidamente.

Embora as GPUs modernas possam ser programadas para resolver praticamente qualquer tarefa, elas apenas obtêm uma vantagem de velocidade quando podem utilizar sua arquitetura paralela. Geralmente é o caso de tarefas "simples" altamente repetitivas. Muito do código que escrevemos é ramificado de maneira imprevisível para executar com eficiência em uma GPU.

Além disso, você pode gastar muito tempo otimizando o código para diferentes chips gráficos. Embora o OpenCL esteja disponível para executar o mesmo código em vários chips gráficos diferentes, você trocará algumas das vantagens de velocidade por esse luxo.

Do ponto de vista do programador de jogos, geralmente também queremos que o jogo seja executado em computadores com placas gráficas menores. Alguns dos chips integrados não têm a capacidade de programação necessária, mas, se o fizerem, são tão lentos que não vencerão o processador por uma margem muito grande, mesmo para o tipo de trabalho em que devem ser bons. E, é claro, se você utilizasse uma GPU de gama baixa para um jogo, obteria o poder de processamento necessário da renderização gráfica.

De fato, as perspectivas são ótimas, mas quando você está criando um jogo, em vez de decifrar senhas, os problemas práticos na maioria dos casos superam os benefícios.

aaaaaaaaaaaa
fonte
6

GPU são muito difíceis de programar. Você deve pesquisar como classificar uma lista em uma GPU . Muitas teses têm pesquisa para fazê-lo.

Usar uma CPU com um thread é fácil, usar multi-threads é mais difícil, usar muitos computadores com biblioteca paralela, pois o PVM ou o MPI é difícil e o uso de uma GPU é o mais difícil.

Ellis
fonte
4

Além do que Randolf Richardson respondeu existem algumas funcionalidades que os processadores GPU não conseguem lidar sozinhos. Por exemplo, alguns dos comandos de gerenciamento de memória gráfica são processados ​​pela CPU, pois a GPU não pode lidar com eles.

E há outro grande motivo: a GPU foi projetada para cálculos multithread. Isso significa que os fabricantes de GPU podem facilmente adicionar núcleos sempre que quiserem aumentar o poder computacional. Mas há muitas tarefas que não podem ser divididas em problemas menores, como calcular o número n- ésimo da série Fibonacci . Nessas situações, a CPU é muito mais rápida, pois é mais otimizada para tarefas de thread único.

Ali1S232
fonte
4

Há muitas respostas sugerindo que as GPUs são mais rápidas porque lidam com tarefas em paralelo. Isso está exagerando um pouco a questão. As GPUs podem ser mais eficientes por outros motivos, como poder ter acesso mais restritivo à memória, não ter que suportar tantos tipos de dados, ter um conjunto de instruções mais eficiente etc. As primeiras GPUs ainda podiam desenhar apenas 1 pixel a uma vez, mas era o fato de que eles podiam fazer 1 a cada ciclo que era importante.

A diferença real é que são dois tipos diferentes de máquinas que são personalizadas para executar bem em diferentes categorias de tarefas que parecem semelhantes, mas na verdade são bem diferentes. É como comparar um avião a um carro. O avião tem uma velocidade máxima muito mais alta, mas tem mais restrições sobre como pode ser usado. Nas ocasiões em que você pode fazer a mesma jornada com qualquer um dos tipos, o avião parece superior.

Kylotan
fonte
A analogia sobre o avião é muito boa (+1), mas no que diz respeito às CPUs que suportam tipos de dados diferentes, esse é realmente um conceito de linguagem de nível superior, já que as CPUs (pelo menos no espaço Intel) tendem a lidar apenas com dados em formas muito básicas (por exemplo, bits, bytes, palavras, dwords, etc.). Existem algumas instruções de loop restrito para varrer ou copiar dados que são finalizados com um byte zero, mas os dados nessas instâncias não são realmente reconhecidos pela CPU como sendo de um tipo específico (exceto por ser um bloco de dados com terminação zero) no contexto desses loops).
Randolf Richardson 10/09
@Randolf: As CPUs possuem instruções e registros diferentes que lidam com diferentes tipos de dados de baixo nível (por exemplo, assinado vs. não assinado, integral vs. ponto flutuante). É o caso do 8086 e das arquiteturas mais modernas, e não é totalmente gratuito.
Kylotan
Tenho certeza de que eles ainda fazem muito processamento linear na arquitetura subjacente. Do lado da programação, são necessárias apenas uma instrução para a GPU, mas os núcleos não são executados exatamente em paralelo devido à dependência de outro hardware que não é paralelo, como a leitura da memória, provavelmente a GPU pode fornecer dados para um único núcleo em um tempo.
Pablo Ariel
3

Os desenvolvedores fazem usam GPUs para todas as funções que são bons. Eles usam CPUs para todas as funções em que são bons. O que faz você pensar que não?

As GPUs são boas em tarefas que podem ser maciçamente paralelizadas e requerem grandes quantidades de computação, com baixos requisitos de memória ou alta correlação temporal, com apenas pequenas quantidades de tomada de decisão. Isso inclui renderizar imagens, simulações de física (partículas, colisão, tecido, água, reflexão) e assim por diante. Portanto, é exatamente para isso que os jogos modernos usam a GPU.

As CPUs são boas em tarefas que não se adaptam bem e exigem grandes quantidades de tomada de decisão. Eles podem tolerar altos requisitos de memória, mesmo com apenas correlação temporal moderada. Isso inclui inteligência artificial, interface do usuário, E / S de disco e rede e assim por diante. Portanto, é exatamente para isso que os jogos modernos usam a CPU.

David Schwartz
fonte
1

O readback é outro motivo pelo qual penso ocasionalmente preferindo a CPU. Não em termos de largura de banda (como GPU-> largura de banda da CPU não é tanto um problema no hardware moderno), mas em termos de paralisar o pipeline. Se você precisar recuperar os resultados de uma computação e fazer algo interessante ou útil com eles, o uso da GPU não é uma escolha sábia (no caso geral - haverá casos especiais em que pode permanecer apropriado), pois a leitura sempre exigirá a GPU pare o que estiver fazendo, limpe todos os comandos pendentes e aguarde a conclusão da readback. Isso pode prejudicar o desempenho na medida em que não apenas elimina os benefícios do uso da GPU, mas pode ser consideravelmente mais lento.

Maximus Minimus
fonte
0

Este é um tópico antigo, mas este artigo publicado recentemente pode responder a essa pergunta. Este artigo, publicado no ACM Computing Surveys 2015, mostra que cada uma das CPUs e GPUs tem suas vantagens exclusivas e, portanto, este documento justifica a mudança do paradigma "CPU vs GPU" para o paradigma "computação colaborativa CPU-GPU".

Uma pesquisa sobre técnicas de computação heterogênea CPU-GPU

user984260
fonte