Elemar DEV

Tecnologia e desenvolvimento

Fundamentos de C++ AMP – Parte 1 – O que é? Para que serve? Hello World

Olá. Tudo certo?

Depois de um tempo com pouca atividade, resolvi resgatar posts mais técnicos aqui para o blog. Com base nisso, resolvi iniciar uma nova série falando sobre uma tecnologia que me fascina um bocado: C++ AMP

O que é C++ AMP?

De forma simplificada, podemos dizer que C++ AMP é a combinação de uma extensão para a linguagem C++ e de uma pequena biblioteca, criada pela Microsoft, que facilita o desenvolvimento de aplicações que tirem proveito da capacidade de execução paralela das GPUs (processadores disponíveis em placas gráficas).

Para que serve C++ AMP?

Comecemos com a explicação disponível no site do MSDN:

C++ AMP (C++ Accelerated Massive Parallelism) accelerates the execution of your C++ code by taking advantage of the data-parallel hardware that’s commonly present as a graphics processing unit (GPU) on a discrete graphics card. The C++ AMP programming model includes support for multidimensional arrays, indexing, memory transfer, and tiling. It also includes a mathematical function library. You can use C++ AMP language extensions to control how data is moved from the CPU to the GPU and back.

Ou seja, C++ AMP faz “a ponte” entre o código que a CPU executa, bem como seus dados, e o código em execução na GPU com seus dados.

C++ AMP é suportado por ferramentas que conhecemos

C++ AMP é amplamente suportada pelo Visual Studio. Além disso, programas escritos utilizando essa tecnologia são plenamente compatíveis com máquinas usando Windows.

Para utilizar C++ AMP não é necessário aprender uma nova ferramenta, ou uma nova linguagem.

C++ AMP facilita compatibilidade

Uma vez que o código tenha compilado, o mesmo executável será capaz de executar em uma ampla diversidade de máquinas desde que estas tenham suporte para DirectX 11. Não há restrição para uma determinada marca de placa de vídeo.

A distribuição consiste em copiar o executável com algumas DLLs.

Programas escritos com C++ AMP também é compatível com o conceito de computação em nuvem.

Hello C++ AMP World

Stop to talk, show me the code!

Para explicar os fundamentos de C++ AMP, ouso começar com uma variação de um exemplo recorrente para a tecnologia.

Comecemos com uma versão que não utiliza C++ AMP:

#include <iostream>

int main()
{
	using namespace std;

	int a_data[] = {1, 2, 3, 4, 5};
	int b_data[] = {6, 7, 8, 9,10};
	int sum_data[5];

	for (int i = 0; i < 5; i++)
		sum_data[i] = a_data[i] + b_data[i];

	for (int i = 0; i < 5; i++)
		cout << sum_data[i] << "... ";
	
	return 0;
}

... agora, vejamos uma que  utiliza:

#include <amp.h>
#include <iostream>

int main()
{
	using namespace std;
	using namespace concurrency;

	int a_data[] = {1, 2, 3, 4, 5};
	int b_data[] = {6, 7, 8, 9,10};
	int sum_data[5];

	array_view<const int, 1> a(5, a_data);
	array_view<const int, 1> b(5, b_data);
	array_view<int, 1> sum(5, sum_data);
	sum.discard_data();

	parallel_for_each(sum.extent, [=] (index<1> i) restrict(amp) {
		sum[i] = a[i] + b[i];
	});

	for (int i = 0; i < 5; i++)
		cout << sum[i] << "... ";
	
	return 0;
}

O programa em sí não apresenta nada de interessante. Basicamente, somamos elementos de dois vetores colocando os resultados em um terceiro. Entretanto, a forma como isso é feito varia um bocado. O primeiro programa utiliza apenas os recursos da CPU. Enquanto isso, o segundo, utiliza a GPU para completar o trabalho.

Importante destacar que esse programa é uma variação do exemplo no site do MSDN. Há uma boa explanação sobre cada elemento por lá - recomendo muito a leitura.

Aqui, gostaria de relacionar apenas alguns aspectos chave. Vejamos:

  • C++ AMP cria um "visão" em torno dos dados que serão utilizados pela placa gráfica. Na prática, em tempo de execução, haverá um transporte de dados da memória convencional para a memória da placa de vídeo onde o processamento ocorrerá. No final, os dados da placa de vídeo são retornados para a memória convencional;
  • A função discard_data orienta o run-time de que os valores de uma determinada fonte não são entradas relevantes para o processamento e, por isso, não precisam ser copiados;
  • O modificador const int serve para indicar que os dados representados serão utilizados apenas como "entrada" e que não há necessidade de retornar dados da memória da placa de vídeo quando o processamento for encerrado;
  • A função parallel_for_each é parte da biblioteca do C++ AMP. Ela "operacionaliza" o transporte dos dados e a execução do programa na placa de vídeo;
  • O modificador restricted(amp) indica para o compilador que o código do bloco que segue deverá ser compatível com execução na GPU;
  • Em tempo de execução, o código "marcado" com restricted(amp) é convertido para algo que pode ser executado na GPU (se isso for possível).

O que aprendemos?

Para concluir, um pequeno review:

  • C++ AMP é uma tecnologia poderosa que permite que escrevamos aplicações que tirem proveito da capacidade de execução paralela das GPUs utilizando C++.
  • A curva de aprendizado para C++ AMP é pequena. Afinal, há apenas uma pequena biblioteca e poucas extensões a linguagem C++ que já conhecemos.
  • Código escrito com C++ AMP é potencialmente mais compatível do que aqueles escritos em tecnologias com propósito similar.

Próximos passos

Antes de avançar para o próximo post, recomendo a leitura desses artigos.

Era isso.

16 comentários em “Fundamentos de C++ AMP – Parte 1 – O que é? Para que serve? Hello World

  1. Alexandre Chohfi
    04/07/2013

    Muito interessante Elemar, nunca tinha ouvido falar na AMP, apenas na PPL, que uso sempre que posso. Criei um Renderer3D via software para aprender C++ e usei a PPL para paralelizar o line scan de cada triangulo. Não usarei a AMP neste proj porque perde todo o sentido de fazer tudo via software, mas percebi que o parallel_for_each é na mesma sintaxe da PPL. É o mesmo parallel_for_each?

    • elemarjr
      04/07/2013

      Não, man. Aliás, é importante entender a distinção entre PPL e AMP.

      PPL serve para “paralelizar” a execução em diversas threads, na CPU. AMP serve para “paralelizar” a execução em diversas threads na GPU. Código AMP roda muito mais rápido e, importante para o seu caso, consome muito menos energia do que o código PPL. Entretanto, PPL suporta qualquer operação, AMP tem um domínio mais restrito.

      BTW, parabéns pelo prêmio MVP recente.

      • Alexandre Chohfi
        04/07/2013

        Vlw :D
        Mas voltando, a minha dúvida era se o parallel_for_each, em termos de código era o mesmo, não em termos de execução, pois esta no mesmo namespace e tem a mesma sintaxe, usando iterator. A execução dele eu entendi que ocorre na GPU e por isso o domínio mais restrito, ele compila o bloco de código restricted(amp){} especificamente para rodar na GPU. Entendi a funcionalidade do AMP, e achei fantástica!

      • Alexandre Chohfi
        04/07/2013

        Se não for a mesma implementação, não vejo como usar PPL e AMP no mesmo código, pois eles adicionam headers diferentes.

        • elemarjr
          04/07/2013

          Assinatura não é a mesma. Apenas parece. O primeiro argumento é um “extent”

          • Alexandre Chohfi
            04/07/2013

            Hummmm, agora que eu vi… #Cego

            • elemarjr
              04/07/2013

              Mas, falando sério, Chohfi. Em celulares, pode fazer uma grande diferença de consumo de energia.

              • Alexandre Chohfi
                04/07/2013

                Elemar, por acaso isso é algo que eu estava conversando em um evento que tive com um pessoal da Intel, semana passada.
                Porque não paralelizamos sempre que podemos, se melhora a performance e é bom para todo mundo? IMO: Porque raramente fazemos algo que realmente vai ser significativo fazer o paralelismo. O paralelismo é, normalmente, visto como melhoria. Se não vemos o problema, não resolvemos ele. E ai, o que você acha Elemar?

    • elemarjr
      20/07/2013

      Não entendi o “fazer tudo via software”!

      • alexandrechohfi
        20/07/2013

        Estou realizando todas as operações que a GPU faz, na CPU. Não utilizo a GPU para praticamente nada, eu programei, em C++, um raster, um vertex shader, um pixel shader, etc, com todos os passos que normalmente a GPU tem que lidar. Mas eu uso só a CPU. Segui um tutorial feito em C#/JavaScript/TypeScript. Se quiser dar uma olhada: http://blogs.msdn.com/b/davrous/archive/2013/06/13/tutorial-series-learning-how-to-write-a-3d-soft-engine-from-scratch-in-c-typescript-or-javascript.aspx

        • elemarjr
          20/07/2013

          Muito bacana. Entendo que seja um projeto para aprendizado, não para produção.

          De qualquer forma, C++ AMP trata de GPGPU, ou seja, de processamento genérico, que é massivamente paralelizável, sendo executado na GPU. Seria curioso ver a GPU fazendo o trabalho de GPU… você estaria “reconstruindo” uma parte do DirectX.

          Compartilha aí o teu trabalho. Se der, claro.

  2. elemarjr
    05/07/2013

    Respondendo ao Alexandre aqui, em uma thread nova. :)

    Programas paralelizados são difíceis de manter e depurar. Além disso, como destacou, nem todo problema é fácil de paralelizar.

  3. Pingback: Fundamentos de C++ AMP – Parte 2 – accelerator e accelerator_view | Elemar DEV

  4. Pingback: Fundamentos de C++ AMP – Parte 3 – array e array_view | Elemar DEV

  5. Pingback: Fundamentos de C++ AMP – Parte 4 – index e extent | Elemar DEV

  6. Pingback: Fundamentos de C++ AMP – parte 5 (final) – restrict(amp) e parallel_for_each | Elemar DEV

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

Informação

Publicado às 01/07/2013 por em Post e marcado , .

Estatísticas

  • 625,784 hits
%d blogueiros gostam disto: