我想知道为什么我的前几千个结果是正确的,然后我在 cuda 编程中得到了旧值?

I am wondering why my first few thousand results are coming correct and then i am getting old values in cuda programming?

#include "opencv2\opencv.hpp"
#include <stdint.h>
#include <stdio.h>
#include <cuda.h>

using namespace cv;
using namespace std;
#define count 200000 


__global__
void SubArrays(int * a, int * b, int size)
{
    int id = blockIdx.x * blockDim.x + threadIdx.x;

    if (id < size)
    {
        a[id] -= b[id];
    }

}


int image1[count];
int image2[count];

int main(int argv, char** argc)
{

    Mat im1 = imread("1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    Mat im2 = imread("2.jpg", CV_LOAD_IMAGE_GRAYSCALE);
    int size = (im1.rows*im1.cols);

    printf("size: %d \n\n\n\n", size);

    int i = 0;

    for (int r = 0; r < im1.rows; r++)
    {
        for (int c =0; c< im1.cols; c++,i++)
        {
            image1[i] = im1.at<uint8_t>(r, c);
            image2[i] = im2.at<uint8_t>(r, c);
        }
    }


    printf("This is first image array's first 5 elements\n\n");
    for (int b = 0; b < 5; b++)
    {
        printf("%d\n",image1[b]);
    }

    printf("This is second image array's first 5 elements\n\n");
    for (int b = 0; b < 5; b++)
    {
        printf("%d\n", image2[b]);
    }

    int * h_a = image1;
    int * h_b = image2;

    int * d_a;
    int * d_b;

    cudaMalloc(&d_a, sizeof(char)*size);
    cudaMalloc(&d_b, sizeof(char)*size);

    cudaMemcpy(d_a, h_a, sizeof(char)*size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_b, h_b, sizeof(char)*size, cudaMemcpyHostToDevice);

    SubArrays << <1, 1024 >> >(d_a, d_b, size);

    cudaMemcpy(h_a, d_a, sizeof(char)*size, cudaMemcpyDeviceToHost);
    printf("calculating result\n\n");

    for (int check = 0; check < size ; check++)
    {
        printf("%d \n", h_a[check]);
    }

    cudaFree(d_a);
    cudaFree(d_b);

    return 0;
}

当我的内核运行时,它给出了前几个值,即差异正确,然后它开始显示旧值?我究竟做错了什么 ?我是菜鸟,尽管我认为这些是我选择错误的块和线程的数量。 我的 gpu CC 是 3.2

您的代码中至少有 2 个错误。

  1. 如前所述,您的内核假定每个像素有 1 个线程。您必须启动足够多的线程来覆盖图像中的所有像素。我们可以通过增加块数来解决这个问题。

  2. 您使用的复印尺寸不正确。您的 image1image2 数组都指定为 int 数组,并且您的内核相应地接受 int * 参数。您已经(显然)加载了 unsigned char 图像,但在加载该图像的过程中,您已将每个像素从 8 位数量转换为 32 位数量:

    int size = (im1.rows*im1.cols);
    
    printf("size: %d \n\n\n\n", size);
    
    int i = 0;
    
    for (int r = 0; r < im1.rows; r++)
    {
        for (int c =0; c< im1.cols; c++,i++)
        {
            image1[i] = im1.at<uint8_t>(r, c);  // this converts 8bit to 32bit
    

    在上面的代码中,您的 size 变量被正确计算,但它现在指的是 32 位 (int) 数量的大小,而不是 8 位 (uint8_t) 数量。因此,当您在主机和设备之间进行复制操作时:

    cudaMemcpy(d_a, h_a, sizeof(char)*size, cudaMemcpyHostToDevice);
                         ^^^^^^^^^^^
    

    sizeof(char) 的使用不正确。您现在正在处理 int 个数量,您应该在任何地方都使用 sizeof(int)

以下工作示例修复了这些问题,并且似乎可以正常工作,删除了 openCV 依赖项:

$ cat t1222.cu
#include <stdint.h>
#include <stdio.h>

using namespace std;
#define count 200000


__global__
void SubArrays(int * a, int * b, int size)
{
    int id = blockIdx.x * blockDim.x + threadIdx.x;

    if (id < size)
    {
        a[id] -= b[id];
    }

}


int image1[count];
int image2[count];

int main(int argv, char** argc)
{

    int i = 0;
    for (i = 0; i < count; i++)
        {
            image1[i] = 3;
            image2[i] = 1;
        }

    int size = count;
    printf("This is first image array's first 5 elements\n\n");
    for (int b = 0; b < 5; b++)
    {
        printf("%d\n",image1[b]);
    }

    printf("This is second image array's first 5 elements\n\n");
    for (int b = 0; b < 5; b++)
    {
        printf("%d\n", image2[b]);
    }

    int * h_a = image1;
    int * h_b = image2;

    int * d_a;
    int * d_b;

    cudaMalloc(&d_a, sizeof(int)*size);
    cudaMalloc(&d_b, sizeof(int)*size);

    cudaMemcpy(d_a, h_a, sizeof(int)*size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_b, h_b, sizeof(int)*size, cudaMemcpyHostToDevice);

    SubArrays << <(count + 1023)/1024, 1024 >> >(d_a, d_b, size);

    cudaMemcpy(h_a, d_a, sizeof(int)*size, cudaMemcpyDeviceToHost);
    printf("calculating result\n\n");

    for (int check = 0; check < size ; check++)
    {
        if (h_a[check] != 2){printf("mismatch at %d, was: %d  should be 2\n", check, h_a[check]); return -1;}
    }
    printf("Success!\n");
    cudaFree(d_a);
    cudaFree(d_b);

    return 0;
}
$ nvcc -o t1222 t1222.cu
$ cuda-memcheck ./t1222
========= CUDA-MEMCHECK
This is first image array's first 5 elements

3
3
3
3
3
This is second image array's first 5 elements

1
1
1
1
1
calculating result

Success!
========= ERROR SUMMARY: 0 errors
$

我总是建议您在使用 CUDA 代码时遇到问题时使用 proper cuda error checking(尽管我没有在此处添加它),并且 运行 您的代码使用 cuda-memcheck(正如我上面所展示的那样)。