2011-09-22 3 views
6

Mi chiedevo se esistesse un modo più efficiente di scrivere a = a + b + c?STL spingere trasformatore vettoriale multiplo?

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>()); 

Questo funziona ma esiste un modo per ottenere lo stesso effetto utilizzando solo una riga di codice? Ho visto l'implementazione saxpy negli esempi, tuttavia questo utilizza 2 vettori e un valore costante;


È più efficiente?

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

Questo mi sembra abbastanza buono. –

risposta

7

a = a + b + c ha bassa intensità aritmetica (solo due operazioni aritmetiche per ogni 4 operazioni di memoria), quindi il calcolo sarà banda di memoria vincolata. Per confrontare l'efficienza delle soluzioni proposte, dobbiamo misurare le loro richieste di larghezza di banda.

Ogni chiamata a transform nella prima soluzione richiede due carichi e un negozio per ogni chiamata a plus. Quindi possiamo modellare il costo di ogni chiamata transform come 3N, dove N è la dimensione dei vettori a, b e c. Poiché ci sono due invocazioni di transform, il costo di questa soluzione è 6N.

Possiamo modellare il costo della seconda soluzione allo stesso modo. Ogni chiamata di arbitrary_functor richiede tre carichi e un negozio. Quindi, un modello di costo per questa soluzione sarebbe 4N, il che implica che la soluzione for_each dovrebbe essere più efficiente della chiamata transform due volte. Quando N è grande, la seconda soluzione dovrebbe eseguire 6N/4N = 1.5x più veloce della prima.

Ovviamente, è possibile combinare sempre zip_iterator con transform in modo simile per evitare due chiamate separate a transform.

+0

Questa è un'analisi molto elegante, ma non posso fare a meno di chiedermi quanto sia costoso l'iteratore di zip (lo uso molto, ma non ho idea di come funziona o delle sue prestazioni). Ha qualche impatto qui? – talonmies

+0

zip_iterator può effettivamente aumentare l'ingombro del kernel, poiché ogni iteratore zippato richiede risorse di registro. In questo esempio, A è incluso nella zip in modo ridondante, una volta come sorgente e una volta come destinazione. Una soluzione un po 'più snella potrebbe solo inviarlo nella zip una volta, ma è improbabile che faccia la differenza dato che arbitary_functor è così semplice. –