2015-08-24 2 views
0

У меня есть простая программа с 3 массивами, которые подсчитывают, сколько третьего массива 0, а первое и второе имеют одинаковые значения. когда он является истинным приращением другого индекса массива. Проблем:CUDA Array установлен в 0 после вызова ядра

  1. Если ядро ​​имеет только первую if() then функции массив А является либо 0

  2. Если вставить if() then else функции значения массива A устанавливается в 0 после индекса = 2 и не считать состояние, когда А, в, с = 0

это код

#include <stdio.h> 
#include <cuda.h> 
#include <cuda_runtime.h> 
#include <stdlib.h> 
#include <cuda_runtime_api.h> 

// Kernel that executes on the CUDA device 
__global__ void square_array(float *a, float *b, float *c, float *res) 
{ 
    int idx = blockIdx.x * blockDim.x + threadIdx.x; 
    if (a[idx]=b[idx] && c[idx]==0) { 
     res[0]++; 
    } 
    else if (a[idx]=b[idx] && c[idx]==1){ 
     res[1]++; 
    } 

} 

// main routine that executes on the host 
int main(void) 
{ 
    float *a_h, *a_d; // Pointer to host & device arrays 
    float *b_h, *b_d; // Pointer to host & device arrays 
    float *c_h, *c_d; // Pointer to host & device arrays 
    float *res_h, *res_d; // Pointer to host & device arrays 

    const int N = 10; // Number of elements in arrays 
    size_t size = N * sizeof(float); 
    //size_t size_s = 4 * sizeof(float); 
    a_h = (float *)malloc(size);  // Allocate array on host 
    cudaMalloc((void **) &a_d, size); // Allocate array on device 
    b_h = (float *)malloc(size);  // Allocate array on host 
    cudaMalloc((void **) &b_d, size); // Allocate array on device 
    c_h = (float *)malloc(size);  // Allocate array on host 
    cudaMalloc((void **) &c_d, size); // Allocate array on device 
    res_h = (float *)malloc(size);  // Allocate array on host 
    cudaMalloc((void **) &res_d, size); // Allocate array on device 

    // Initialize host array and copy it to CUDA device 
    // for (int i=0; i<N; i++) a_h[i] = (float)i; 
    for (int i=0; i<N; i++) a_h[i] = (float)i; 
    for (int i=0; i<N; i++) b_h[i] = (float)i; 
    for (int i=0; i<N; i++) c_h[i] = (float)i; 
    for (int i=0; i<4; i++) res_h[i] = 0; 


    cudaMemcpy(a_d, a_h, size, cudaMemcpyHostToDevice); 
    cudaMemcpy(b_d, b_h, size, cudaMemcpyHostToDevice); 
    cudaMemcpy(c_d, c_h, size, cudaMemcpyHostToDevice); 
    cudaMemcpy(res_d, res_h, size, cudaMemcpyHostToDevice); 
    // Do calculation on device: 
    int block_size = 8; 
    int n_blocks = N/block_size + (N%block_size == 0 ? 0:1); 
    square_array <<< n_blocks, block_size >>> (a_d, b_d, c_d, res_d); 
    // Retrieve result from device and store it in host array 
    cudaMemcpy(a_h, a_d, sizeof(float)*N, cudaMemcpyDeviceToHost); 
    cudaMemcpy(b_h, b_d, sizeof(float)*N, cudaMemcpyDeviceToHost); 
    cudaMemcpy(c_h, c_d, sizeof(float)*N, cudaMemcpyDeviceToHost); 
    cudaMemcpy(res_h, res_d, sizeof(float)*N, cudaMemcpyDeviceToHost); 

    // Print results 
    for (int i=0; i<N; i++){ 
     printf("%f A \n", a_h[i]); 
    } 
    for (int i=0; i<N; i++){ 
      printf("%f B \n", b_h[i]); 
     } 
    for (int i=0; i<N; i++){ 
      printf("%f C \n", c_h[i]); 
     } 
    for (int i=0; i<4; i++){ 
     printf("%f res \n", res_h[i]); 
    } 

    // Cleanup 
    free(a_h); cudaFree(a_d); 
    free(b_h); cudaFree(b_d); 
    free(c_h); cudaFree(c_d); 
    free(res_h); cudaFree(res_d); 
} 
+1

С первого взгляда, кажется, что вы пишете 'Рез [0]' и 'Рез [1]' с ** ** всех потоков. Окончательные значения в этом массиве будут довольно произвольными. * Если * я понял вас правильно, вы могли бы использовать какое-то сокращение здесь, но реализовать это на GPU далеко не тривиально. – Marco13

ответ

1

Помимо = в if (a[idx]=b[idx] && c[idx]==0) {, которые должны быть ==, как вы уже нашли (и то же самое для следующего if заявление) , есть по крайней мере две другие проблемы в коде:

  1. Вы не убедитесь, что индекс нить не выходит за границы массивов. Так как вы используете 2 блока из 8 потоков, у вас есть 16 потоков, обращающихся к 10 элементам массивов. Чтобы избежать этой проблемы, вам необходимо передать N как параметр для вашего ядра и добавить if (idx < N).

  2. Вы аккумулируете в res параллельно без какой-либо защиты, что приводит к разным условиям гонки. Это очень типичная проблема с гистограммой, которая объясняется в литературе (в Интернете, книгах, примерах CUDA ...). Быстрое решение для вас (хотя, вероятно, и не самое эффективное) - использовать атомные операции, такие как atomicAdd. В вашем случае линия res[0]++; станет atomicAdd(&res[0], 1);, и res[1]++; станет (как вы уже догадались) atomicAdd(&res[1], 1);. Поддержка этого для float подразумевает, что вы скомпилируете свой код при использовании возможности вычисления не менее 2.0.

НТН

+0

Thak you so much, он работает –

0

К сожалению, я решена problem.It была ошибка введя контроль = и не верно ==

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