intro++ a Thrust

Anuncio
Librería Thrust
Clase 5
¿ Que es Thrust ?
http://thrust.github.io/
excelente documentación, muchos ejemplos
Ejemplo hecho en clase
#include<thrust/host_vector.h>
#include<thrust/device_vector.h>
#include<thrust/functional.h>
#include<thrust/transform_reduce.h>
#include<cstdlib>
#include<iostream>
#include<cstdio>
using namespace thrust::placeholders;
int main(int arch, char **argv)
{
srand(13);
int N=10000000;
thrust::host_vector<float> hvec(N);
thrust::generate(hvec.begin(),hvec.end(),rand);
thrust::device_vector<float> dvec(N);
thrust::copy(hvec.begin(),hvec.end(),dvec.begin());
//thrust::transform(dvec.begin(),dvec.end(),dvec.begin(),_1/RAND_MAX);
//float mayor = thrust::reduce(dvec.begin(),dvec.end(),-1.f,thrust::maximum<float>());
float mayor =
transform_reduce(dvec.begin(),dvec.end(),_1/RAND_MAX,-1.f,thrust::maximum<float>());
//std::cout << mayor << std::endl;
printf("%.10f\n",mayor);
}
Device backends
#include<thrust/host_vector.h>
#include<thrust/device_vector.h>
#include<thrust/functional.h>
#include<thrust/transform_reduce.h>
#include<cstdlib>
#include<iostream>
#include<cstdio>
using namespace thrust::placeholders;
Mismo codigo, diferente compilacion
Corre serial en CPU (C/C++)
Corre en paralelo en CPU (openmp,tbb)
Corre en la GPU (cuda)
int main(int arch, char **argv)
Ver
{
srand(13);
int N=10000000;
thrust::host_vector<float> hvec(N);
thrust::generate(hvec.begin(),hvec.end(),rand);
ejemplo device_backends.cu
thrust::device_vector<float> dvec(N);
thrust::copy(hvec.begin(),hvec.end(),dvec.begin());
//thrust::transform(dvec.begin(),dvec.end(),dvec.begin(),_1/RAND_MAX);
//float mayor = thrust::reduce(dvec.begin(),dvec.end(),-1.f,thrust::maximum<float>());
float mayor =
transform_reduce(dvec.begin(),dvec.end(),_1/RAND_MAX,-1.f,thrust::maximum<float>());
//std::cout << mayor << std::endl;
printf("%.10f\n",mayor);
}
https://github.com/thrust/thrust/tree/master/examples
Componentes de Thrust
Containers:
●
●
●
Para manejar el contenido en memoria del host y del device.
Simplifican las copias D → H, H → D.
Mucho mas que un array, son colecciones genéricas de objetos.
Iteradores:
●
●
Actuan como punteros...
Pero mantienen info del espacio de memoria.
Algoritmos:
●
●
Se aplican a rangos de containers, delimitados por iteradores.
Son genericos, flexibles, y portables.
Operadores predefinidos
Operadores propios
Comparadores propios
Ejemplo:
struct Persona{
...datos de una persona;
};
…..
Persona p;
p.inicializacion();
device_vector<p> Gente(40000000);
sort(Gente.begin(),Gente.end(),
comparador_de_edad);
Gente[0] → datos de
la persona mas joven;
Gente[40000000-1] → datos del
Mas viejo;
Predicados propios
Ejemplo:
struct Persona{
...datos de una persona;
};
…..
Persona p;
p.inicializacion();
device_vector<p> Gente(40000000);
Int M =
count_if(Gente.begin(),Gente.end(),
vive_en_bariloche);
M ==
numero de personas que viven en Bche
Thrust Best Practices
Thrust by Example, GTC, Julien Demouth, Nvidia
Thrust Best Practices
Thrust by Example, GTC, Julien Demouth, Nvidia
Thrust Best Practices
Thrust by Example, GTC, Julien Demouth, Nvidia
Thrust Best Practices
Thrust by Example, GTC, Julien Demouth, Nvidia
Thrust Best Practices
Thrust by Example, GTC, Julien Demouth, Nvidia
Fancy Iterators
Fancy Iterators
– constant_iterator
– counting_iterator
– transform_iterator
– permutation_iterator
– zip_iterator
Quick-Start-Guide THRUST
Fancy Iterators
constant_iterator
Representa un puntero a un rando de valores constantes.
Util para crear una secuencia constante sin usar memoria.
Si uso economiza memoria y ancho de banda.
include <thrust/iterator/constant_iterator.h>
...
// create iterators
thrust::constant_iterator<int> first(10);
thrust::constant_iterator<int> last = first + 3;
first[0]
// returns 10
first[1]
// returns 10
first[100] // returns 10
// sum of [first, last)
thrust::reduce(first, last);
// returns 30 (i.e. 3 * 10)
Quick-Start-Guide THRUST
Fancy Iterators
constant_iterator
Representa un puntero a un rando de valores constantes.
Util para crear una secuencia constante sin usar memoria.
Si uso economiza memoria y ancho de banda.
#include
#include
#include
#include
#include
#include
#include
<thrust/iterator/constant_iterator.h>
<thrust/transform.h>
<thrust/functional.h>
<thrust/device_vector.h>
<thrust/copy.h>
<iterator>
<iostream>
int main(void)
{
thrust::device_vector<int> data(4);
data[0] = 3; data[1] = 7;
data[2] = 2; data[3] = 5;
// add 10 to all values in data
thrust::transform(data.begin(), data.end(),
thrust::constant_iterator<int>(10),
data.begin(),
thrust::plus<int>());
// data is now [13, 17, 12, 15]
// print result
thrust::copy(data.begin(), data.end(),
std::ostream_iterator<int>(std::cout, "\n"));
return 0;
}
Quick-Start-Guide THRUST
x={0,1,2,...} → f(x)={f(0),f(1),...}
#include<thrust/device_vector.h>
#include<thrust/transform.h>
#include<thrust/sequence.h>
#include<iostream>
struct mifuncion
{
float a;
mifuncion(float _a):a(_a){};
__device__ __host__
float operator()(float x)
{
return sinf(a*x);
}
};
int main(int arch, char **argv)
{
srand(13);
int N=10000000;
thrust::device_vector<float> x(N); // abscisa
thrust::device_vector<float> y(N); // coordenada
thrust::sequence(x.begin(),x.end()); // x={0,1,2,3,...N-1}
float a=1.0; mifuncion op(a);
thrust::transform(x.begin(),x.end(), y.begin(),op); // x={sin(a*0),sin(a*1),..., sin(a*(N-1))}
// check
std::cout << y[2] << " vs " << sin(a*2.0) << std::endl;
}
Fancy Iterators
counting_iterator
Representa un puntero a un rando de valores constantes.
Util para crear una secuencia constante sin usar memoria.
Si uso economiza memoria y ancho de banda.
#include<thrust/device_vector.h>
#include<thrust/transform.h>
#include <thrust/iterator/counting_iterator.h>
#include<iostream>
struct mifuncion
{
float a;
mifuncion(float _a):a(_a){};
X={0,1,2,...} → f(x)={f(0),f(1),...}
__device__ __host__
float operator()(float x){
return sinf(a*x);
}
};
int main(int arch, char **argv)
{
int N=10000000;
thrust::device_vector<float> y(N); // coordenada
float a=1.0; mifuncion op(a);
thrust::transform(
thrust::make_counting_iterator(0),thrust::make_counting_iterator(N),
y.begin(),op
);
// y={sin(a*0),sin(a*1),..., sin(a*(N-1))}
std::cout << y[2] << " vs " << sin(a*2.0) << std::endl;
}
nvcc tabulate_with_counting_iterator.cu
Fancy Iterators
counting_iterator
Representa un puntero a un rando de valores constantes.
Util para crear una secuencia constante sin usar memoria.
Si uso economiza memoria y ancho de banda.
#include<thrust/device_vector.h>
#include<thrust/transform.h>
#include <thrust/iterator/counting_iterator.h>
#include<iostream>
struct mifuncion
{
float a;
mifuncion(float _a):a(_a){};
X={0,1,2,...} → f(x)={f(0),f(1),...}
__device__ __host__
float operator()(float x){
return sinf(a*x);
}
};
int main(int arch, char **argv)
{
int N=10000000;
thrust::device_vector<float> y(N); // coordenada
float a=1.0; mifuncion op(a);
thrust::counting_iterator<int> first(0);
thrust::counting_iterator<int> last(N);
thrust::transform(
first,last,
y.begin(),op
);
// y={sin(a*0),sin(a*1),..., sin(a*(N-1))}
std::cout << y[2] << " vs " << sin(a*2.0) << std::endl;
}
nvcc tabulate_with_counting_iterator2.cu
Thrust Best Practices
Thrust by Example, GTC, Julien Demouth, Nvidia
Fancy Iterators
transform_iterator
Representa un puntero a un rango de valores despues de una transformacion por una funcion.
Util para crear un rango lleno con el resultado de aplicar una operacion sobre otro rango sin guardarlo
explicitamente en memoria ni ejecutando la transformacion...
Facilita la “fusion de kernels”, pateando la ejecucion de la transformacion hasta que el valor
transformado es necesitado, minimizando asi memoria y ancho de banda.
#include <thrust/iterator/transform_iterator.h>
#include <thrust/device_vector.h>
// note: functor inherits from unary_function
struct square_root : public thrust::unary_function<float,float>
{
__host__ __device__
float operator()(float x) const
{
return sqrtf(x);
}
};
int main(void)
{
thrust::device_vector<float> v(4);
v[0] = 1.0f; v[1] = 4.0f; v[2] = 9.0f; v[3] = 16.0f;
typedef thrust::device_vector<float>::iterator FloatIterator;
thrust::transform_iterator<square_root, FloatIterator> iter(v.begin(), square_root());
*iter;
iter[0];
iter[1];
iter[2];
iter[3];
//
//
//
//
//
returns
returns
returns
returns
returns
1.0f
1.0f;
2.0f;
3.0f;
4.0f;
// iter[4] is an out-of-bounds error
}
ejemplos THRUST
Fancy Iterators
transform_iterator
Representa un puntero a un rango de valores despues de una transformacion por una funcion.
Util para crear un rango lleno con el resultado de aplicar una operacion sobre otro rango sin guardarlo
explicitamente en memoria ni ejecutando la transformacion...
Facilita la “fusion de kernels”, pateando la ejecucion de la transformacion hasta que el valor
transformado es necesitado, minimizando asi memoria y ancho de banda.
#include <thrust/iterator/transform_iterator.h>
#include <thrust/device_vector.h>
#include <thrust/sort.h>
// note: functor inherits from unary_function
struct seno: public thrust::unary_function<float,float>
{
__host__ __device__
float operator()(float x) const
{
return sinf(x);
}
};
int main(void)
{
thrust::device_vector<float> v(4);
v[0] = 1.0f; v[1] = 4.0f; v[2] = 9.0f; v[3] = 16.0f;
float result = thrust::reduce(
thrust::make_transform_iterator(v.begin(), seno()),
thrust::make_transform_iterator(v.end(), seno())
);
float sum=0.0; for(int i=0;i<4;i++) sum+=sin(v[i]);
std::cout << result << " " << sum << std::endl;
}
nvcc reduce_with_transform_iterator.cu
Fancy Iterators
transform_iterator
Representa un puntero a un rango de valores despues de una transformacion por una funcion.
Util para crear un rango lleno con el resultado de aplicar una operacion sobre otro rango sin guardarlo
explicitamente en memoria ni ejecutando la transformacion...
Facilita la “fusion de kernels”, pateando la ejecucion de la transformacion hasta que el valor
transformado es necesitado, minimizando asi memoria y ancho de banda.
#include <thrust/iterator/transform_iterator.h>
#include <thrust/device_vector.h>
#include <thrust/sort.h>
// note: functor inherits from unary_function
struct seno: public thrust::unary_function<float,float>
{
__host__ __device__
float operator()(float x) const
{
return sinf(x);
}
};
int main(void)
{
thrust::device_vector<float> v(4);
v[0] = 1.0f; v[1] = 4.0f; v[2] = 9.0f; v[3] = 16.0f;
auto first= thrust::make_transform_iterator(v.begin(), seno());
auto end= first+4;
float result = thrust::reduce(first,end);
float sum=0.0; for(int i=0;i<4;i++) sum+=sin(v[i]);
std::cout << result << " vs " << sum << std::endl;
}
nvcc --std=c++11 reduce_with_transform_iterator2.cu
Fancy Iterators
permutation_iterator
Representa un puntero a una vision reordenada de un rango.
Util para fusionar las operaciones de “scatter” y “gather” con otros algoritmos.
#include <thrust/iterator/permutation_iterator.h>
#include <thrust/reduce.h>
#include <thrust/device_vector.h>
#include <iostream>
// this example fuses a gather operation with a reduction for
// greater efficiency than separate gather() and reduce() calls
int main(void)
{
// gather locations
thrust::device_vector<int> map(4);
map[0] = 3;
map[1] = 1;
map[2] = 0;
map[3] = 5;
pregunta de clase!
// array to gather from
thrust::device_vector<int> source(6);
source[0] = 10;
source[1] = 20;
source[2] = 30;
source[3] = 40;
source[4] = 50;
source[5] = 60;
// fuse gather with reduction:
//
sum = source[map[0]] + source[map[1]] + ...
int sum = thrust::reduce(thrust::make_permutation_iterator(source.begin(), map.begin()),
thrust::make_permutation_iterator(source.begin(), map.end()));
// print sum
std::cout << "sum is " << sum << std::endl;
return 0;
}
Aplicación del permutation iterator
Imagen “encriptada”
Imagen “desencriptada”
Los pixels estan mezclados usando un mapeo dado...
[FINAL ICNPG2014]
Fancy Iterators
zip_iterator
Representa un puntero a un rango de tuplas, cada una de las cuales compacta
iteradores de varios inputs.
Util para crear una array de estructuras virtual, pero manteniendo la performance
de una estructura de arrays.
Facilita kernel fusio, al proveer una forma de amortizar la ejecucion de la misma
operacion sobre muchos rangos a la vez.
https://github.com/thrust/thrust/blob/master/examples/arbitrary_transformation.cu
// output[i] = F(first[i], second[i], third[i], ... ).
Quick-Start-Guide THRUST
Thrust Best Practices
Thrust by Example, GTC, Julien Demouth, Nvidia
Thrust Best Practices
Thrust by Example, GTC, Julien Demouth, Nvidia
Thrust Best Practices
Thrust by Example, GTC, Julien Demouth, Nvidia
Programación híbrida
Usar un “system-specific vector”
Execution policies
Ejemplo de execution policies
/share/apps/codigos/alumnos_icnpg2016/clase_05/omp_vs_cuda/ompvsgpu_same_host.cu
●
nvcc -Xcompiler -fopenmp ompvsgpu_same_host.cu
●
qsub submit.sh
●
Ver output...
Un solo Programa
Paralelizacion para GPU
Paralelizacion para CPU multicore
Using a system-specific vector
Paralelismo de datos y de tareas
CPU ociosa...
Paralelismo de datos y de tareas
farber1-11_sync.cu
clase_05/hibrid_programming/
Paralelismo de datos y de tareas
farber1-11_sync.cu
farber1-11_async.cu
PROBAR!
clase_05/hibrid_programming/
Thrust 1.8 (el ultimo)
Thrust v1.8.0 release
We are pleased to announce the release of Thrust v1.8, an open-source C++
library for developing high-performance parallel applications. Modeled after the
C++ Standard Template Library, Thrust brings a familiar abstraction layer to the
realm of parallel computing.
Thrust 1.8.0 (viene incluido con CUDA 7):
support for algorithm invocation from CUDA __device__ code
support for CUDA streams
Algorithm performance improvements
thrust::complex template provides complex number support .
Volveremos con Thrust después de unas clases...
Descargar