我想知道为什么我的前几千个结果是正确的,然后我在 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 个线程。您必须启动足够多的线程来覆盖图像中的所有像素。我们可以通过增加块数来解决这个问题。
您使用的复印尺寸不正确。您的 image1
和 image2
数组都指定为 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
(正如我上面所展示的那样)。
#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 个线程。您必须启动足够多的线程来覆盖图像中的所有像素。我们可以通过增加块数来解决这个问题。
您使用的复印尺寸不正确。您的
image1
和image2
数组都指定为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
(正如我上面所展示的那样)。