2013-08-08 3 views
4

У меня есть следующий (компилируемый и исполняемый) код с использованием CUDA Thrust для выполнения сокращений float2 массивов. Он работает правильноCUDA Уменьшение тяги с помощью массивов double2

using namespace std; 

// includes, system 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <math.h> 
#include <conio.h> 

#include <typeinfo> 
#include <iostream> 

// includes CUDA 
#include <cuda.h> 
#include <cuda_runtime.h> 

// includes Thrust 
#include <thrust/host_vector.h> 
#include <thrust/device_vector.h> 
#include <thrust/reduce.h> 

// float2 + struct 
struct add_float2 { 
    __device__ float2 operator()(const float2& a, const float2& b) const { 
     float2 r; 
     r.x = a.x + b.x; 
     r.y = a.y + b.y; 
     return r; 
    } 
}; 

// double2 + struct 
struct add_double2 { 
    __device__ double2 operator()(const double2& a, const double2& b) const { 
     double2 r; 
     r.x = a.x + b.x; 
     r.y = a.y + b.y; 
     return r; 
    } 
}; 

void main(int argc, char** argv) 
{ 
    int N = 20; 

    // --- Host 
    float2* ha; ha = (float2*) malloc(N*sizeof(float2)); 
    for (unsigned i=0; i<N; ++i) { 
     ha[i].x = 1; 
     ha[i].y = 2; 
    } 

    // --- Device 
    float2* da; cudaMalloc((void**)&da,N*sizeof(float2)); 
    cudaMemcpy(da,ha,N*sizeof(float2),cudaMemcpyHostToDevice); 

    thrust::device_ptr<float2> dev_ptr_1(da); 
    thrust::device_ptr<float2> dev_ptr_2(da+N); 

    float2 init; init.x = init.y = 0.0f; 

    float2 sum = thrust::reduce(dev_ptr_1,dev_ptr_2,init,add_float2()); 

    cout << " Real part = " << sum.x << "; Imaginary part = " << sum.y << endl; 

    getch(); 

} 

Однако, когда я изменяю float2 к double2 в программе main, а именно

void main(int argc, char** argv) 
{ 
    int N = 20; 

    // --- Host 
    double2* ha; ha = (double2*) malloc(N*sizeof(double2)); 
    for (unsigned i=0; i<N; ++i) { 
     ha[i].x = 1; 
     ha[i].y = 2; 
    } 

    // --- Device 
    double2* da; cudaMalloc((void**)&da,N*sizeof(double2)); 
    cudaMemcpy(da,ha,N*sizeof(double2),cudaMemcpyHostToDevice); 

    thrust::device_ptr<double2> dev_ptr_1(da); 
    thrust::device_ptr<double2> dev_ptr_2(da+N); 

    double2 init; init.x = init.y = 0.0; 

    double2 sum = thrust::reduce(dev_ptr_1,dev_ptr_2,init,add_double2()); 

    cout << " Real part = " << sum.x << "; Imaginary part = " << sum.y << endl; 

    getch(); 

} 

я получаю exception на reduce линии. Как я могу использовать сокращение CUDA Thrust с помощью массивов double2? Я делаю что-то неправильно? Заранее спасибо.

рабочего раствор следующего ответа TALONMIES»

с использованием патезраса;

// includes, system 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <math.h> 
#include <conio.h> 

#include <typeinfo> 
#include <iostream> 

// includes CUDA 
#include <cuda.h> 
#include <cuda_runtime.h> 

// includes Thrust 
#include <thrust/host_vector.h> 
#include <thrust/device_vector.h> 
#include <thrust/reduce.h> 

struct my_double2 { 
    double x, y; 
}; 

// double2 + struct 
struct add_my_double2 { 
    __device__ my_double2 operator()(const my_double2& a, const my_double2& b) const { 
     my_double2 r; 
     r.x = a.x + b.x; 
     r.y = a.y + b.y; 
     return r; 
    } 
}; 

void main(int argc, char** argv) 
{ 
    int N = 20; 

    // --- Host 
    my_double2* ha; ha = (my_double2*) malloc(N*sizeof(my_double2)); 
    for (unsigned i=0; i<N; ++i) { 
     ha[i].x = 1; 
     ha[i].y = 2; 
    } 

    // --- Device 
    my_double2* da; cudaMalloc((void**)&da,N*sizeof(my_double2)); 
    cudaMemcpy(da,ha,N*sizeof(my_double2),cudaMemcpyHostToDevice); 

    thrust::device_ptr<my_double2> dev_ptr_1(da); 
    thrust::device_ptr<my_double2> dev_ptr_2(da+N); 

    my_double2 init; init.x = init.y = 0.0; 

    cout << "here3\n"; 
    my_double2 sum = thrust::reduce(dev_ptr_1,dev_ptr_2,init,add_my_double2()); 

    cout << " Real part = " << sum.x << "; Imaginary part = " << sum.y << endl; 

    getch(); 

} 

ответ

4

Это известная несовместимость с MSVC и nvcc. См. Например, here. Решение состоит в том, чтобы определить вашу собственную версию double2 и использовать ее вместо этого.

Для справки я могу скомпилировать и запустить ваш код правильно на 64-битной коробке Linux с CUDA 5.5.

+0

Большое спасибо за ваш ответ. В чем причина такой несовместимости? Включает ли он также последние версии MSVC? На цитируемой веб-странице предлагается определить настраиваемую версию 'double2' как' struct'. Как насчет производительности? В прошлом я немного поиграл с собственной версией 'double2' в виде пары« двойных »чисел, но я понял, что решение с классом-оболочкой, использующим' double2', вместо пары 'double', было Быстрее. – JackOLantern

+1

Я не знаком с компиляторами и библиотеками Microsoft, поэтому я не могу сказать вам больше, чем то, что я предложил в ответ. Что касается 'double2' по сравнению с struct - я так понимаю, вы не знаете, что' double2' * является * простой структурой (смотрите в 'vector_types.h'). Должно быть (и по моему опыту нет) какая-либо разница в испускаемом коде или производительности при использовании типа вектора CUDA и использования вашей собственной функционально эквивалентной структуры. – talonmies

+0

Спасибо, я принял ваш ответ. Да, я знаю, что 'double2' является' struct', но перед определением есть специальные ключевые слова: '__device_builtin__ __builtin_align __ (16)'. До тех пор, как я знаю, они должны допускать совместный доступ к памяти. Это обеспечит некоторые улучшения по сравнению с настраиваемым определением, не использующим выравнивание? – JackOLantern

 Смежные вопросы

  • Нет связанных вопросов^_^