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...