2011-09-22 17 views
6

Me preguntaba si había una manera más eficiente de escribir a = a + b + c?STL thrust multiple vector transform?

thrust::transform(b.begin(), b.end(), c.begin(), b.begin(), thrust::plus<int>()); 
thrust::transform(a.begin(), a.end(), b.begin(), a.begin(), thrust::plus<int>()); 

Esto funciona, pero ¿hay alguna forma de obtener el mismo efecto con solo una línea de código? Miré la implementación de saxpy en los ejemplos, sin embargo, esto usa 2 vectores y un valor constante;


¿Es esto más eficiente?

struct arbitrary_functor 
{ 
    template <typename Tuple> 
    __host__ __device__ 
    void operator()(Tuple t) 
    { 
     // D[i] = A[i] + B[i] + C[i]; 
     thrust::get<3>(t) = thrust::get<0>(t) + thrust::get<1>(t) + thrust::get<2>(t); 
    } 
}; 


int main(){ 

    // allocate storage 
    thrust::host_vector<int> A; 
    thrust::host_vector<int> B; 
    thrust::host_vector<int> C; 

    // initialize input vectors 
    A.push_back(10); 
    B.push_back(10); 
    C.push_back(10); 

    // apply the transformation 
    thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(A.begin(), B.begin(), C.begin(), A.begin())), 
        thrust::make_zip_iterator(thrust::make_tuple(A.end(), B.end(), C.end(), A.end())), 
        arbitrary_functor()); 

    // print the output 
     std::cout << A[0] << std::endl; 

    return 0; 
} 
+0

Esto se ve bastante bien para mí. –

Respuesta

7

a = a + b + c tiene baja intensidad aritmética (sólo dos operaciones aritméticas para cada 4 operaciones de memoria), por lo que el cálculo va a ser el ancho de banda de memoria obligado. Para comparar la eficiencia de sus soluciones propuestas, debemos medir sus demandas de ancho de banda.

Cada llamada a transform en la primera solución requiere dos cargas y una tienda para cada llamada a plus. Entonces podemos modelar el costo de cada llamada transform como 3N, donde N es del tamaño de los vectores a, b y c. Dado que hay dos invocaciones de transform, el costo de esta solución es 6N.

Podemos modelar el costo de la segunda solución de la misma manera. Cada invocación de arbitrary_functor requiere tres cargas y una tienda. Entonces, un modelo de costo para esta solución sería 4N, lo que implica que la solución for_each debería ser más eficiente que llamar al transform dos veces. Cuando N es grande, la segunda solución debe realizar 6N/4N = 1.5x más rápido que la primera.

Por supuesto, siempre puede combinar zip_iterator con transform de manera similar para evitar dos llamadas separadas a transform.

+0

Es un análisis muy elegante, pero no puedo evitar preguntarme qué tan caro es el iterador zip (lo uso mucho, pero no tengo ni idea de cómo funciona ni cómo funciona). ¿Eso tiene algún impacto aquí? – talonmies

+0

zip_iterator de hecho puede aumentar la huella del kernel, ya que cada iterador comprimido requiere recursos de registro. En este ejemplo, A está incluido en el archivo zip de forma redundante, una vez como fuente y una como destino. Una solución un poco más delgada solo podría enviarla en el zip una vez, pero es poco probable que haga una diferencia dado que arbitary_functor es tan simple. –

Cuestiones relacionadas