20 julho, 2013 0 Comentários AUTOR: elemarjr CATEGORIAS: Sem categoria Tags:,

Fundamentos de C++ AMP - Parte 4 - index e extent

Tempo de leitura: 1 minuto

Olá. Tudo certo?

Esse é o quarto post da série onde apresento os fundamentos de C++ AMP – a extensão da linguagem C++ e biblioteca, da Microsoft, para desenvolvimento de programas com paralelização massiva, usando a GPU.

Os posts anteriores foram:

  1. O que é? Para que serve? Hello World!
  2. accelerator e accelerator_view
  3. array e array_view

Nesse post falo sobre outras duas classes fundamentais: index e extent

Entendendo o conceito

Cada elemento em um array ou array_view é "indexado" por um objeto da classe index. Ele é criado através de um template definido no namespace concurrent que é completado com um número. Esse número indica o número de dimensões representado pelo índice.

A "extensão" de um array ou array_view é determinada por um objeto extent. Esse objeto, por sua vez, também é completado por um número que determina o número de dimensões que a dimensão terá.

Para tornar o exemplo mais compreensível, veja o fragmento que segue:

#include <amp.h>
#include <vector>
#include <assert.h>

using namespace concurrency;

int main() {

	std::vector<float> v(16);
	int seed = 0;
	std::generate(v.begin(), v.end(), [&seed](){ return ++seed; });

	extent<2> e(4, 4);
	array_view<float, 2> av(e, v);

	index<2> idx(2, 3);

	assert (av[idx] == v[2 * 4 + 3]);
}

Perceba:

  • Criamos um vetor de 16 posições para representar uma matriz e alimentamos esse vetor,
  • Criamos um objeto extent com duas dimensões, 4x4;
  • Criamos um índice de duas dimensões para indexar esse mesmo vetor;
  • Comparamos o valor do array_view e do vetor (na mesma posição).

Tudo funcionou bem.

Relação com o for_each_parallel

for_each_parallel é uma função central para C++ AMP. Discutiremos essa função com mais detalhes em um post futuro. Por hora, é importante apenas que saibamos que essa função é responsável por percorrer um array (ou array_view) e disparar threads independentes de execução.

Considere agora o seguinte exemplo:

#include <amp.h>
#include <vector>
#include <assert.h>

using namespace concurrency;

int main() {

	std::vector<float> vA(16);
	std::vector<float> vB(16);
	std::vector<float> vC(16);

	int seed = 0;
	std::generate(vA.begin(), vA.end(), [&](){ return ++seed; });
	std::generate(vB.begin(), vB.end(), [&](){ return seed--; });

	extent<2> e(4, 4);
	array_view<const float, 2> a(e, vA);
	array_view<const float, 2> b(e, vB);
	array_view<float, 2> c(e, vC);
	c.discard_data();

	parallel_for_each(a.extent, [=](index<2> idx) restrict (amp) {
		c[idx] += a[idx] + b[idx];
	});
	c.synchronize();

	index<2> idx(0,0);
	assert(c[idx] == 17);
}

Trata-se de um exemplo recorrente em C++ AMP, bem parecido com aquele que apresentei no primeiro post e que também é utilizado pela Microsoft.

O importante, aqui, é perceber que a função parallel_for_each passa um objeto index em cada iteração que determina como o array ou array_view será acessado.

Por enquanto, era isso.

Concluindo

array e array_view tem extensão determinada por um objeto do tipo extent. Os valores armazenados são recuperados a partir de um índice do tipo index.

Era isso.